Skip to main content

Getting Started

Install (clone and build)​

There is no published package yet. Build from source:

git clone https://github.com/catesworks/env-sync.git
cd env-sync
pnpm install && pnpm build

This builds the TypeScript CLI. The executable is apps/cli/bin/env-sync.js. To call it as env-sync from anywhere, put a symlink or alias on your PATH:

alias env-sync="node $PWD/apps/cli/bin/env-sync.js"

To build the Go binary instead (Go toolchain required):

cd go && go build -o env-sync ./cmd/env-sync

Prerequisites​

env-sync reads from 1Password and writes through each platform's own API or CLI. You only need the tools and credentials for the platforms that your manifest uses.

Needed forWhat
Every command1Password access. The TypeScript CLI uses the op CLI, with a signed-in desktop session or OP_SERVICE_ACCOUNT_TOKEN. The Go CLI uses the 1Password SDK and requires OP_SERVICE_ACCOUNT_TOKEN.
ssm targetsThe aws CLI, with credentials for the expected account and region. Override them with ENV_SYNC_AWS_ACCOUNT_ID / ENV_SYNC_AWS_REGION.
github-actions targetsThe gh CLI, authenticated. (The Go CLI talks to the GitHub API directly.)
vercel targetsVERCEL_ACCESS_TOKEN, ideally a project-scoped token.
render targetsRENDER_API_KEY (or numbered RENDER_<n>_API_KEY keys, one per Render team).
caprover targetsCAPROVER_ADMIN_PASSWORD.
dotenv targetsNothing extra.
caution

A 1Password Service Account token is a long-lived bearer credential. Scope the Service Account to only the vaults that your manifests reference. Never use an org-wide Service Account.

Write a manifest​

env-sync looks for secrets.manifest.yml in the current directory. Each service names a 1Password source (<vault>/<item-prefix>) and one or more targets:

secrets.manifest.yml
services:
api:
source: app-secrets/myapp/api
targets:
- platform: ssm
path: /myapp/api
- platform: github-actions
repo: myorg/myapp
github_env: dev
web:
source: app-secrets/myapp/web
targets:
- platform: vercel
project: myapp-web
vercel_targets: [development, preview]
- platform: dotenv
path: apps/web/.env.local

The 1Password item is resolved per environment. With --env dev, service api reads the item myapp/api/dev from the app-secrets vault. Every labeled field on that item is a key to sync. The notes field is skipped.

First run​

Run the commands in this order. Each step is safer than the next.

1. Validate. Check that the 1Password item exists with no empty fields and that every target is reachable:

env-sync validate --service api --env dev
[api] OK: app-secrets/myapp/api/dev exists with fields: DATABASE_URL, API_KEY
[api] target ssm:/myapp/api: reachable
[api] target github-actions:myorg/myapp:dev: reachable

2. Diff. See what differs, with no writes:

env-sync diff --service api --env dev
[api] ssm:/myapp/api: drift on [API_KEY]
[api] github-actions:myorg/myapp:dev: DATABASE_URL: present, value unverifiable; API_KEY: MISSING_FROM_GITHUB

3. Push. Without --apply, push is a dry run that prints the diff. With --apply, it writes:

env-sync push --service api --env dev --apply
[api] Succeeded: ssm:/myapp/api, github-actions:myorg/myapp:dev

That push ran without a prompt because every target is provably dev-scoped: SSM derives its path from --env, and the GitHub target has a dev-tier github_env. Add a Vercel, Render, or dotenv target, or use a non-dev --env, and env-sync asks you to confirm first. See push.