# Using 1Password and direnv to store developer secrets

https://blog.cynexia.com/using-1password-and-direnv-to-store-developer-secrets

Author: [Rob Aleck](https://blog.cynexia.com/pages/about) · https://github.com/mnbf9rca · https://www.linkedin.com/in/robertaleck/ · https://family-foqos.app/

Published: 2026-04-06
Updated: 2026-10-01
Categories: How-to


This is more notes to myself so i don't forget. Goals:

- no secrets stored on the filesystem (so they can't be [sucked up by credential-harvesting malware](<https://docs.litellm.ai/blog/security-update-march-2026>))
- individual vault per project
- secrets automatically injected to envvars so that apps can follow [12-Factor App methodology](<https://12factor.net/>)
- deployed secrets use platform native secret manager (e.g. [Cloudflare secrets manager](<https://developers.cloudflare.com/workers/configuration/secrets/>), [Azure keyvault](<https://azure.microsoft.com/en-us/products/key-vault/>), [AWS SSM Parameter Store](<https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html>) etc.)
- separation of this vault from my main password vault in BitWarden. My whole world exists in Bitwarden - i dont want to inadvertently expose it. And as Bitwarden has a pretty awful CLI experience, it doesnt work for me.
- Safe to commit secret file to source control
- Safe to commit my `.env` files to source control because they no longer contain secrets

Benefits of 1Password:

- tightly integrated CLI tool and desktop app, with MacOS biometric auth integration
- Industry standard toolset, well regarded security position
- relatively cheap - roughly $50 per year

## Initial set up

### 1. Install `1Password`, `1password-cli`, `direnv`.

1Password must be the direct download or Homebrew cask version, not the Mac App Store version as App Store enforces sandboxing.

```
brew install --cask 1password 1password-cli
brew install direnv
```

### 2. Configure 1Password desktop app

- Settings > Developer > Turn on "Show 1Password Developer experience"
- Settings > Developer > Turn on "Integrate with 1Password CLI"
- Settings > Security > Turn on "Unlock with Touch ID"

### 3. Configure shell

Add to `~/.zshrc`. This causes `direnv` to evaluate a `.env.tpl` file each time you navigate in to a folder, and clear when you navigate out of a folder.

```
eval "$(direnv hook zsh)"
```

Open a new terminal shell (or type it in the existing one).

## Adding secrets to a project

### 1. Add the secret to 1Password

### Create a new vault in 1Password

Vaults are the security separation between projects. There is [no hard limit](<https://www.reddit.com/r/1Password/comments/rmj9ct/comment/hpmn7s9/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button>) to the number of vaults you can add.

### Create a new item per environment

I create a new "password" type per environment. You can then add config as additional "password" types, with the name of the envvar, for example:

![Screenshot of a 1Password "New Item" dialog creating a login entry titled "dev". Fields shown: username (empty), password (empty), a custom field labeled "secret_name" with a masked value, notes (empty), and options to add a website, location, or tags. The item is owned by user "Rob" in a vault called "project". A blue Save button is in the bottom-right corner.](https://blog.cynexia.com/attachments/using-1password-and-direnv-to-store-developer-secrets/Screenshot-2026-04-06-at-20.21.20.png)

### 2. Create `.env.tpl` in the project folder

This file is safe to commit - it contains no secrets, only references to secrets - example:

```
export MY_SECRET="op://project/dev/secret_name"
```

### 3. Create `.envrc` in project folder

Also safe to commit. This is what `direnv` runs on entry. Typically:

```
eval "$(op inject -i .env.tpl)"
```

One thing to note: if the desktop app is locked and the biometric prompt/login is declined (or times out), the env vars get set to empty strings, not the `op://` references.

### 4. Allow `direnv`

A security measure...

```
direnv allow
```

### 5. Test

Exit the directory and go back in.

```
❯ cd .. && cd -
~/Downloads/myfolder
direnv: loading ~/Downloads/myfolder/.envrc
direnv: export +MY_SECRET
```

You should see a prompt from 1Password to grant access to the vault. This happens the first time after vault timeout/lock.

![1Password authorization prompt requesting CLI access for iTerm2. The dialog shows the iTerm2 terminal icon connected via a green checkmark to the 1Password icon, with the text "Allow iTerm2 to get CLI access". The account "rob" is listed below with an expandable disclosure arrow. Cancel and blue Authorize buttons at the bottom.](https://blog.cynexia.com/attachments/using-1password-and-direnv-to-store-developer-secrets/image.png)

## Use with VSCode

Install the official [`mkhl.direnv`](<https://marketplace.visualstudio.com/items?itemName=mkhl.direnv>) extension ([source](<https://github.com/direnv/direnv-vscode>)). This will read `.envrc` natively whenever a folder is opened. There's a `direnv: Reload` command (`Cmd+Shift+P`).

## Updating or adding new secrets

If new, add the `op://` reference to `.env.tpl`. Update the secret in 1Password, run `direnv reload` in the folder.

## Deploying and using secrets in other places

Platform-native secret stores inject env vars. App code unchanged.

- CI - either:
    - Deploy secrets as Github Actions secrets, then mapped to envvars in the workflow
    - or use the 1Password [Github Action](<https://github.com/1Password/load-secrets-action>) with a [Service Account](<https://developer.1password.com/docs/service-accounts/>) to pull directly from the vault
- Cloudflare: `wrangler secret put SECRET_NAME` → \`env.SECRET_NAME\`
- Azure: Key Vault + managed identity → App Settings with `@Microsoft.KeyVault(SecretUri=…)`
- AWS: SSM Parameter Store (Standard, free) → env vars in Lambda/ECS task definitions
- Local containers: `op run --env-file=.env.tpl -- docker compose up`

