@adddog/1password-env
v0.0.2
Published
Single source of truth for secrets via 1Password. Replaces committed `.env` files, scattered GitHub secrets, and manual secret management.
Readme
@adddog/1password-env
Single source of truth for secrets via 1Password. Replaces committed .env files, scattered GitHub secrets, and manual secret management.
Install
pnpm add @adddog/1password-envHow it works
secrets.ts (config) --> 1Password vault --> .env file / CI env vars
^ ^ ^
defineSecrets() op-env init op-env hydrate
1password/load-secrets-action (CI)- Define secrets in a
secrets.tsconfig - Init scaffolds the 1Password vault and items (
op-env init) - Hydrate resolves secrets and writes
.envfiles (op-env hydrate) - CI uses
1password/load-secrets-actionto inject secrets at runtime
Config
Add an "op-env" key to your package.json — no extra config files needed:
// package.json
{
"op-env": {
"vault": "my-project",
"environments": {
"remote": {
"item": "remote",
"fields": [
"COOKIE_SECRET",
"PASETO_SECRET_KEY",
{ "env": "DB_PASS", "field": "database-password" }
],
"outputFile": ".config/.env.dev.remote",
"literals": {
"CORS_ORIGINS": "https://example.com"
}
}
}
},
"scripts": {
"hydrate": "op-env hydrate",
"hydrate:init": "op-env init --from-env .config/.env.dev.remote"
}
}outputFile paths are relative to the package.json directory.
Alternatively, use a standalone secrets.ts file with --config:
import { defineSecrets } from "@adddog/1password-env"
export default defineSecrets({
vault: "my-project",
environments: { /* ... */ },
})CLI
op-env init — scaffold vault and items
Reads config and creates the 1Password vault + items via the op CLI. Requires the 1Password desktop app integration (not service account).
# Auto-discovers config from package.json "op-env" key
op-env init
# Seed values from an existing .env file
op-env init --from-env .config/.env.dev.remote
# Preview without making changes
op-env init --dry-run
# Or with pnpm scripts:
pnpm hydrate:initIdempotent — skips vaults and items that already exist.
op-env hydrate — write .env files
Resolves secrets from 1Password and writes the output file. Requires OP_SERVICE_ACCOUNT_TOKEN.
# Hydrate all environments (reads package.json)
op-env hydrate
# Hydrate a specific environment
op-env hydrate -e remote
# Or with pnpm scripts:
pnpm hydrateop-env resolve — print secrets to stdout
op-env resolve -e remote
# COOKIE_SECRET=abc123...
# PASETO_SECRET_KEY=k4.local...All commands auto-discover config from the nearest package.json with an "op-env" key. Pass --config <path> to use a standalone config file instead.
Programmatic API
import { defineSecrets, resolveSecrets, hydrateEnv, initFromConfig } from "@adddog/1password-env"
// Resolve to a map
const secrets = await resolveSecrets(config, "remote")
// Write .env file, returns output path
const path = await hydrateEnv(config, "remote", "/path/to/base")
// Scaffold vault + items (uses op CLI)
const result = await initFromConfig(config, { fromEnv: ".env.dev.remote" })Setup (one-time)
1. Define config
Add "op-env" to your project's package.json.
2. Scaffold 1Password
# With existing .env file (seeds values):
op-env init --from-env .config/.env.dev.remote
# Without (creates placeholders):
op-env init3. Create service account (manual — 1P web UI)
- Go to https://my.1password.com/developer-tools/directory
- Create a service account
- Grant it access to your vault(s)
- Copy the token
4. Configure token
# Local dev
echo 'export OP_SERVICE_ACCOUNT_TOKEN="ops_..."' >> ~/.zshrc
# GitHub Actions
gh secret set OP_SERVICE_ACCOUNT_TOKEN5. Hydrate
op-env hydrate -c .config/secrets.ts6. CI (GitHub Actions)
For CI, use the official 1Password action instead of this package:
- uses: 1password/load-secrets-action@v2
with:
export-env: true
env:
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
MY_SECRET: op://vault/item/fieldAdding & updating secrets
Add a new secret
Add the field to your config (
package.jsonorsecrets.ts):"fields": [ "EXISTING_SECRET", "NEW_API_KEY" // <-- add here ]Create the field in 1Password via the
opCLI:# Add a field to an existing item op item edit "remote" --vault "my-project" "NEW_API_KEY=sk-live-abc123" # Or create via the 1Password desktop/web appRe-hydrate to pull the new value into your
.env:op-env hydrate
Update an existing secret
No config change needed — just update the value in 1Password:
op item edit "remote" --vault "my-project" "COOKIE_SECRET=new-value-here"Then re-hydrate:
op-env hydrateAdd a new environment
Add the environment to your config:
"environments": { "remote": { /* ... */ }, "staging": { "item": "staging", "fields": ["DB_URL", "API_KEY"], "outputFile": ".config/.env.staging" } }Scaffold the new vault item:
op-env initSet values in 1Password (via
opCLI or the app), then hydrate:op-env hydrate -e staging
Summary
| Task | Config change? | 1Password change? | Command |
|------|:-:|:-:|---------|
| Add secret | Yes — add to fields | Yes — op item edit | op-env hydrate |
| Update secret value | No | Yes — op item edit | op-env hydrate |
| Add environment | Yes — add to environments | Yes — op-env init | op-env hydrate |
| Add literal (non-secret) | Yes — add to literals | No | op-env hydrate |
Claude Code Plugin
claude plugin marketplace add samelie/1password-env
claude plugin install 1password-envAdds the /op-env-setup skill for interactive 1Password secret management setup.
Output formats
dotenv (default):
COOKIE_SECRET=abc123
CORS_ORIGINS=https://example.comshell:
#!/bin/bash
export COOKIE_SECRET="abc123"
export CORS_ORIGINS="https://example.com"