boltenv/docs
CLI Reference v4

Documentation

Push and pull AES-256-GCM encrypted .env files using GitHub permissions as access control. Zero infrastructure. No new accounts.

Introduction

boltenv is a CLI tool for sharing encrypted .env files across your team using GitHub as the access layer. There is no new dashboard to learn, no new accounts to create, and no infrastructure to manage.

Every .env file is encrypted locally on your machine with AES-256-GCM before it leaves your computer. The server stores only ciphertext — it mathematically cannot decrypt your secrets. Access control is determined entirely by GitHub repository permissions: if a teammate has write access to the repo, they can pull secrets. Remove them from GitHub, they lose access immediately.

boltenv is designed for small-to-medium engineering teams who are already using GitHub and want encrypted secret sharing without the complexity and cost of dedicated secrets management platforms like Doppler, HashiCorp Vault, or Infisical.

Installation

boltenv requires Node.js 22 or later. Install globally using any Node.js package manager:

bash
# npmnpm install -g @boltenv.dev/cli# pnpmpnpm add -g @boltenv.dev/cli# yarnyarn global add @boltenv.dev/cli# bunbun add -g @boltenv.dev/cli

Or use the one-line install script (works on macOS and Linux, no Node.js required):

bash
curl -fsSL https://boltenv.dev/install | sh

After installation, verify it works:

bash
$ boltenv --versionboltenv 4.0.0

Quickstart

Get your team synced in under 60 seconds. The person who owns the repository does steps 1–3. Teammates only need steps 4–5.

bash
# Step 1 — authenticate with GitHub (one time per machine)boltenv login# Step 2 — push your .env (auto-detects repo from git remote)boltenv push# Step 3 — export the encryption key and share it securely with teammatesboltenv key export

Teammates run:

bash
# Step 4 — import the key shared by the repo ownerboltenv key import <base64-key># Step 5 — pull and decryptboltenv pull
The encryption key is a secret — treat it like a password. Never paste it into Slack, email, or group chats. Use a secure channel like 1Password shared vaults, Signal, or a password manager.

Zero-knowledge encryption

boltenv uses a zero-knowledge encryption architecture. This means the server stores your ciphertext but is cryptographically incapable of decrypting it — even if an attacker has full access to the server database.

text
Encryption algorithm:  AES-256-GCMKey derivation:        HKDF-SHA256 with domain separation  — Encryption subkey: "boltenv-v1-encrypt"  — HMAC subkey:       "boltenv-v1-hmac"IV:                    12 bytes, cryptographically random per pushAuth tag:              16 bytes (GCM authentication tag)Master key:            256 bits (32 bytes), random or PBKDF2-derivedKey stored at:  ~/.boltenv/keys/{owner}/{repo}.keyServer stores:  ciphertext + IV + auth tag + key fingerprintServer never:   sees the master key or plaintext

A fresh random IV is generated for every push. This means encrypting the same .env twice produces completely different ciphertext each time — even if only one character changed. The 16-byte GCM authentication tag ensures tamper detection: any modification to ciphertext in transit is detected and rejected on pull.

Key names are stored as HMAC-SHA256 hashes on the server, not in plaintext. The server cannot determine what keys you have stored — only that they exist.

Authentication

boltenv uses GitHub OAuth Device Flow for authentication. No username or password — you authenticate your machine against GitHub once, and boltenv uses the resulting token for all API calls.

bash
# Authenticate this machine with GitHubboltenv login# Prints the currently authenticated userboltenv whoami# Remove stored credentials from this machineboltenv logout

The GitHub token is stored at ~/.boltenv/auth.json with file permissions 0600 (readable only by you). boltenv requests only the repo scope — the minimum required to verify repository write access.

On every push or pull, boltenv calls the GitHub API (GET /repos/{owner}/{repo}) and reads your permissions.push field. If you don't have write access, the request is rejected before any data is transmitted. This means access control is always enforced in real time — there is no cached permission state that can become stale.

Environments

boltenv uses your current git branch to automatically determine which environment you're targeting. This means switching environments is just switching branches — no extra flags needed for daily usage.

text
Branch           Environment───────────────────────────────main, master  →  productionstaging       →  stagingdevelop       →  developmentrelease/*     →  staging       (configurable)anything else →  development   (default fallback)

Override the auto-detected environment with the -e flag:

bash
# Push to production explicitlyboltenv push -e production# Pull staging secrets while on a feature branchboltenv pull -e staging

Customize the branch-to-environment mapping in .boltenv.yaml using glob patterns. Wildcard patterns (release/*, hotfix/*) are supported.

yaml
# .boltenv.yamlenvironments:  production:    - main    - master  staging:    - staging    - "release/*"    - "hotfix/*"  development:    - develop    - "feat/*"

Version history

Every push creates a new versioned snapshot. boltenv keeps the last 10 versions on the free tier and 50 versions on the Team plan. Versions are immutable — you can always roll back to any previous state.

bash
# List all versions for the current environmentboltenv ls# Output:#   v5  2026-06-13 09:41  alice     12 vars#   v4  2026-06-12 17:22  bob       11 vars#   v3  2026-06-11 14:05  alice     11 vars#   v2  2026-06-10 10:30  alice     10 vars#   v1  2026-06-09 08:15  alice     10 vars# Pull a specific version (rollback)boltenv pull --revision 3# Pull the latest version explicitlyboltenv pull --revision latest
Rollbacks are non-destructive — pulling an older version does not delete newer versions. To permanently set production to v3, pull v3 then push it: boltenv pull --revision 3 && boltenv push

boltenv push

Encrypts your .env file locally using AES-256-GCM and uploads only the ciphertext to boltenv cloud. The plaintext and encryption key never leave your machine.

bash
# Push .env in current directory (auto-detects repo and environment)boltenv push# Push a different fileboltenv push .env.production# Push to a specific environmentboltenv push -e production# Skip the confirmation prompt (useful in scripts)boltenv push -y# Push to a specific repo (when no .git directory is present)boltenv push -r myorg/myapp# Push multiple filesboltenv push .env .env.local

If this is the first push for a repository, boltenv auto-generates a 256-bit encryption key and saves it to ~/.boltenv/keys/. Share this key with teammates using boltenv key export.

boltenv performs a three-way merge if two teammates push simultaneously. Keys modified on only one side auto-merge cleanly. Keys modified on both sides get standard git-style conflict markers (<<<<<<< / ======= / >>>>>>>) in your .env file — your editor already knows how to handle these.

boltenv pull

Downloads ciphertext from boltenv cloud, fetches the encryption key (gated by GitHub permissions), and decrypts the file locally. The server never decrypts anything on your behalf.

bash
# Pull latest .env for the current environmentboltenv pull# Pull from a specific environmentboltenv pull -e staging# Pull a specific version number (rollback)boltenv pull --revision 3# Skip overwrite confirmationboltenv pull -y# Print decrypted output to stdout (don't write file)boltenv pull --stdout# Output as JSON objectboltenv pull --format json# Output as shell export statementsboltenv pull --format shell# Pull from a specific repoboltenv pull -r myorg/myapp
.env files are written atomically: boltenv writes to a temp file first, then renames it to the final path. This prevents partial writes if the process is interrupted. Written files always have 0600 permissions (owner read/write only).

boltenv key

Manages the local encryption key for a repository. The key is a 256-bit random value stored at ~/.boltenv/keys/{owner}/{repo}.key.

bash
# Export the key as base64 (to share with a teammate)boltenv key export# Import a key from a teammateboltenv key import dGhpcyBpcyBhIDMyIGJ5dGUga2V5IGV4YW1wbGU=# Check key status for the current repoboltenv key status# Show key fingerprint without exporting the raw keyboltenv key fingerprint# Rotate the key (generates a new key, re-encrypts all versions)boltenv key rotate
Key rotation re-encrypts all stored versions server-side. Every teammate must run 'boltenv pull' after a rotation to receive the new key. Until they do, they cannot decrypt new pushes.

boltenv init

Initializes boltenv in a project directory. Detects your framework, package manager, and existing .env files automatically.

bash
# Interactive setup with promptsboltenv init# Use all defaults (no prompts, safe for CI)boltenv init -y

init creates a .boltenv.yaml config file and adds all detected .env patterns to .gitignore. Commit the config file so your teammates share the same environment-to-branch mapping.

yaml
# Generated .boltenv.yamlrepo: myorg/myappfiles:  - .env  - .env.localenvironments:  production:    - main  staging:    - staging  development:    - develop

boltenv doctor

Runs a full diagnostic check of your boltenv setup. Each check is run in dependency order — if check 3 fails, checks 4–7 are skipped since they depend on it.

bash
$ boltenv doctor  ✓ Git remote         myorg/myapp  ✓ GitHub token       Loaded for alice  ✓ GitHub API         alice — scopes: repo  ✓ Token scope        repo scope present  ✓ Repo access        write access to myorg/myapp  ✓ Encryption key     32-byte key (fp: 509f94d5b2d0e38b)  ✓ boltenv API        https://boltenv.dev (120ms)  Summary: 7/7 checks passed

When a check fails, doctor prints the exact command or action needed to fix it — no Googling required.

GitHub Actions

Use boltenv in GitHub Actions workflows to pull encrypted secrets into your CI environment. Store BOLTENV_TOKEN and BOLTENV_KEY as repository secrets in GitHub Settings → Secrets.

yaml
# .github/workflows/deploy.ymlname: Deployon:  push:    branches: [main]jobs:  deploy:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v4      - name: Install boltenv        run: npm install -g @boltenv.dev/cli      - name: Pull secrets        env:          BOLTENV_TOKEN: ${{ secrets.BOLTENV_TOKEN }}          BOLTENV_KEY:   ${{ secrets.BOLTENV_KEY }}          BOLTENV_REPO:  myorg/myapp        run: boltenv pull -e production -y      - name: Build & deploy        run: npm run build && npm run deploy
Use secrets.GITHUB_TOKEN instead of a PAT when possible — it's automatically available in every workflow and scoped to the current repository. Set BOLTENV_TOKEN to secrets.GITHUB_TOKEN in the env block.

GitLab CI

boltenv works in GitLab CI pipelines using environment variables. Store BOLTENV_TOKEN and BOLTENV_KEY in your project's CI/CD variables (Settings → CI/CD → Variables).

yaml
# .gitlab-ci.ymlstages:  - deploydeploy:  stage: deploy  image: node:22  script:    - npm install -g @boltenv.dev/cli    - boltenv pull -e production -y    - npm run build    - npm run deploy  only:    - main

Docker

Pull secrets into a Docker build or at container startup using environment variables. Never bake secrets into Docker images — use boltenv to inject them at runtime.

dockerfile
# Dockerfile — pull secrets at build timeFROM node:22-alpine# Install boltenvRUN npm install -g @boltenv.dev/cliWORKDIR /appCOPY . .# Pull secrets (requires BOLTENV_TOKEN, BOLTENV_KEY, BOLTENV_REPO at build time)RUN boltenv pull -e production -yRUN npm install && npm run buildCMD ["node", "dist/index.js"]

For runtime injection (recommended — keeps secrets out of image layers):

dockerfile
# entrypoint.sh#!/bin/shboltenv pull -e production -yexec "$@"
bash
# Run with secrets injected at container startdocker run \  -e BOLTENV_TOKEN="ghp_xxxx" \  -e BOLTENV_KEY="dGhpcyBpc..." \  -e BOLTENV_REPO="myorg/myapp" \  myapp:latest

CI/CD (general)

boltenv supports any CI/CD system through three environment variables. Set these in your CI platform's secret store — never hardcode them.

bash
# Required for non-interactive / headless usage:export BOLTENV_TOKEN="ghp_xxxxxxxxxxxx"   # GitHub PAT with repo scopeexport BOLTENV_KEY="dGhpcyBpcyBhIDMy..."  # From: boltenv key exportexport BOLTENV_REPO="myorg/myapp"          # Override git remote detection# Pull in CI (skip all interactive prompts)boltenv pull -e production -y

BOLTENV_TOKEN must be a GitHub Personal Access Token with the repo scope. For GitHub Actions, you can use the built-in secrets.GITHUB_TOKEN which is automatically scoped to the current repository.

Configuration (.boltenv.yaml)

boltenv.yaml controls per-project settings. Commit this file — it's not secret. It contains no credentials.

yaml
# .boltenv.yaml — full reference# GitHub repository (owner/repo). Auto-detected from git remote if omitted.repo: myorg/myapp# Files to push/pull. Supports glob patterns.files:  - .env  - .env.local  - .env.*.local# Branch-to-environment mapping. Supports glob patterns.environments:  production:    - main    - master  staging:    - staging    - "release/*"    - "hotfix/*"  development:    - develop    - "feat/*"    - "*"        # fallback: any other branch# Server URL (override for self-hosted, when available)# server: https://boltenv.dev# Default push behaviorpush:  confirm: true     # prompt before push (default: true)  merge: true       # enable three-way merge (default: true)# Default pull behaviorpull:  confirm: true     # prompt before overwrite (default: true)  format: env       # output format: env | json | shell

Command reference

Complete list of all boltenv commands and their flags.

text
boltenv <command> [flags]COMMANDS  login              Authenticate with GitHub via Device Flow  logout             Remove stored GitHub credentials  whoami             Print the authenticated GitHub user  push [file]        Encrypt and push .env to boltenv cloud  pull               Pull and decrypt .env from boltenv cloud  ls                 List available versions for an environment  key export         Export the repo encryption key as base64  key import <key>   Import a base64 encryption key  key status         Check if a key exists for this repo  key fingerprint    Print the key fingerprint (safe to share)  key rotate         Generate a new key and re-encrypt all data  init               Initialize boltenv in a project directory  doctor             Run full diagnostic checks  version            Print version informationGLOBAL FLAGS  -r, --repo <owner/repo>     Override git remote detection  -e, --env <environment>     Override branch-based env detection  -y, --yes                   Skip all confirmation prompts  --debug                     Enable verbose debug output  --help                      Show help for any commandPUSH FLAGS  [file]                      Path to .env file (default: .env)  -m, --message <msg>         Version commit messagePULL FLAGS  --revision <n|latest>       Pull a specific version number  --stdout                    Print to stdout instead of writing  --format <env|json|shell>   Output format (default: env)

Security model

boltenv's security model is designed around one principle: the server should never be able to read your secrets, even if it is fully compromised.

text
YOUR MACHINE                          BOLTENV CLOUD┌───────────────────────────┐        ┌───────────────────────────┐│ plaintext .env             │        │ ciphertext (AES-256-GCM)  ││ master key (256-bit)       │──────▶│ IV (12 bytes, random)     ││ HKDF-SHA256 key derivation │        │ auth tag (16 bytes)       ││ AES-256-GCM encryption     │        │ key fingerprint (HMAC)    ││ fresh IV per push          │        │                           ││ GCM auth tag               │        │ cannot decrypt            ││                            │        │ validates GitHub auth      ││ key never transmitted      │        │ no master key stored       │└───────────────────────────┘        └───────────────────────────┘

What boltenv defends against: secrets leaked via a compromised server database, insider threats at the hosting provider, man-in-the-middle attacks (TLS + GCM auth tag), .env files accidentally committed to git, secrets shared via insecure channels (Slack, email), stale access after a teammate is removed from GitHub.

What boltenv does NOT defend against: an attacker who has both the server database AND the BOLTENV_KEY_WRAPPER environment variable (full server compromise). Supply-chain attacks against the boltenv npm package itself. Authorized-but-malicious teammates (someone who already has the key). Secrets already stored in plaintext elsewhere.

Onboarding a teammate

Adding a new teammate to boltenv takes about 2 minutes. The repo owner exports the key; the teammate imports it.

bash
# Repo owner: export the key and share it securelyboltenv key export# → prints: dGhpcyBpcyBhIDMyIGJ5dGUga2V5...# Teammate: install boltenv, login, and import the keynpm install -g @boltenv.dev/cliboltenv loginboltenv key import dGhpcyBpcyBhIDMyIGJ5dGUga2V5...boltenv pull
Only share the key via a private, encrypted channel — 1Password shared vaults, Signal, or a secure password manager. Never paste it in a team Slack channel, email thread, or pull request comment.

To revoke access: remove the teammate from the GitHub repository. From that moment, any push or pull attempt with their token will be rejected by the server (GitHub permissions are checked on every request, not cached).

Troubleshooting

Run boltenv doctor first — it diagnoses the most common issues automatically.

text
PROBLEM                          SOLUTION──────────────────────────────────────────────────────────────Not authenticated                boltenv loginNo key for this repo             boltenv key import <base64-key>Wrong repo detected              boltenv push -r owner/repoDecryption failed                Key mismatch — re-import keyPermission denied                Ask repo owner to add you to GitHub repoNo .git directory in CI          Set BOLTENV_REPO env varNetwork timeout                  Check https://status.boltenv.devConflict markers in .env         Resolve manually then boltenv push -yToken expired                    boltenv logout && boltenv login

For unexpected errors, enable debug output:

bash
BOLTENV_DEBUG=1 boltenv pull

Migrating from Doppler

Migrating from Doppler to boltenv takes about 10 minutes. Export your secrets from Doppler, push them to boltenv, update your CI pipelines.

bash
# Step 1: export secrets from Dopplerdoppler secrets download --no-file --format env > .env# Step 2: install boltenv and pushnpm install -g @boltenv.dev/cliboltenv loginboltenv push# Step 3: share the key with your teamboltenv key export# Step 4: update CI — replace Doppler env vars with:# BOLTENV_TOKEN, BOLTENV_KEY, BOLTENV_REPO

Key differences: boltenv is client-side encrypted (Doppler is server-side). boltenv uses GitHub for access control (Doppler has its own IAM). boltenv has no web dashboard — it's CLI-only. boltenv free tier supports up to 3 users vs Doppler's 1 user on free.

Migrating from dotenv-vault

If you're using dotenv-vault or a shared .env file in a private git repo, migrating to boltenv gives you proper encryption and access control.

bash
# If you have a .env already, just push it:boltenv loginboltenv push# Remove .env from git history if it was committed:git rm --cached .envecho ".env" >> .gitignoregit commit -m "chore: move secrets to boltenv"