Hello.

til

Your .env file is a secret at rest: mount it from 1Password instead

2026-11-06

TL;DR A plaintext .env is a secret at rest: anything that can see the project folder can read it, and one stray git add commits it. A 1Password Environment can mount the same file as a named pipe, so nothing sits on disk. It is at-rest hygiene, not a sandbox, and the pipe has two traps.

Your .env is a credential that lives next to your code, in plaintext. 1Password's own announcement puts it the same way: secrets are stored in plaintext on disk, and it is easy to forget the .gitignore entry and expose credentials in a commit.

Why a file is the problem

A file is readable by anything that runs as you and can reach the directory: build tools, editor plugins, AI agents, sync clients. It also gets copied wherever the project goes: backups, snapshots, a zipped folder, a forgotten clone.

The fix is to not have the file. For a mounted Environment, the contents are never stored on disk; they are passed to the reader on demand through a UNIX named pipe.

What it looks like

1Password Developer page with two cards: SSH Agent, status Running, and Environments, with a View Environments button.
The Developer page in the 1Password desktop app. Environments sits next to the SSH agent.
A 1Password Environment with 8 secrets shown as masked values, connected to a local .env file at an anonymized path, status Enabled.
One Environment, eight secrets, masked by default, connected to a local .env file. Project name and path are anonymized.

Set it up

You need the 1Password desktop app, the Environments policy on for your account, and Mac or Linux (local .env files are not supported elsewhere).

Step 1 of 3

Create the Environment

In the app open Developer > View Environments, create an Environment and use Import .env file. Doing this in the UI means no script or agent has to read the values.

What you get, and what you do not

You get: no plaintext values on disk, nothing for Git to track ("it won't be tracked by Git", per the announcement), no copy for a backup of the project folder to pick up (my inference from the above), and a file that locks again when 1Password locks.

You do not get isolation. The docs are explicit: once the file is unlocked, every process can read it until you lock 1Password or disable the mount, and no distinction is made between processes. A process running as you can still read the secrets while the app is unlocked. Other documented limits: Mac and Linux only, and mounts aren't designed for concurrent access.

The pipe gotchas

The mount is a named pipe, not a regular file. A scratch FIFO shows what that does to a wrapper script (this is a plain mkfifo, not the 1Password mount):

A named pipe is not a regular file
$ mkfifo a.fifo && (while true; do echo FOO=bar > a.fifo; done) &
$ ls -l a.fifo | cut -c1
p
$ [ -f a.fifo ]; echo f=$?
f=1
$ [ -e a.fifo ]; echo e=$?
e=0
$ args=""; [ -f a.fifo ] && args="--env-file a.fifo"; echo "before: args=[$args]"
before: args=[]
$ args=""; [ -e a.fifo ] && args="--env-file a.fifo"; echo "after: args=[$args]"
after: args=[--env-file a.fifo]

So test with -e, not -f, or the --env-file flag is skipped without an error.

Second, keep the mount out of directories you bind-mount into a Linux container. With the mount at <project>/.dev.vars, my astro build in a container hung until my 300 s timeout. Why is an inference: the writer is the host app. A plain FIFO in a bind-mounted directory behaved similarly: cat inside the container got no data and was only stopped by timeout. Mounting outside the project and passing it from the host with container run --env-file ~/.config/<project>/env delivered the variables in my test, but I have not rerun the full build with that setup.

A .env on disk is a secret at rest; a mounted Environment is not, as long as the mount is a pipe outside your bind mounts.