npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

git-env-vault

v0.6.2

Published

CLI + TUI for managing encrypted environment variables in monorepos with SOPS + age

Downloads

410

Readme

git-env-vault

npm version npm downloads Release CI License Node Maintainer Website

Encrypted .env secrets in Git for monorepos. SOPS + age, policy-based access control, CLI, and interactive TUI.

Now includes a JS decrypt backend fallback for smoother onboarding (pull/decrypt) while keeping system sops + age as the primary full-featured workflow.

Why git-env-vault

Managing secrets across multiple services and environments is hard:

  • Sharing .env files in chat/email is unsafe.
  • Keeping secrets in CI settings is hard to review and version.
  • Onboarding and offboarding access is often manual and error-prone.
  • Access revocation usually requires additional manual cleanup.

git-env-vault keeps encrypted secrets next to code while controlling who can decrypt each environment/service.

Key features

  • Encrypted secrets stored in Git (*.sops.yaml).
  • Service-to-output mapping (envvault.config.json).
  • Policy-based recipients (envvault.policy.json + .sops.yaml).
  • Safe-by-default diffs (keys only, no values by default).
  • Access lifecycle commands (grant, revoke, updatekeys, rotate).
  • Local override promotion (promote, promote-all).
  • CI validation (ci-verify).
  • Interactive terminal UI (envvault tui).

Requirements

  • Node.js 18+
  • Git 2+
  • SOPS 3.8+ (recommended, required for full feature set)
  • age 1.1+ (recommended, required for full feature set)

Installation

# project dependency (recommended)
npm i -D git-env-vault

# global install
npm i -g git-env-vault

Run without installing globally (npx / bunx)

# one-off command (npm)
npx git-env-vault@latest doctor
npx git-env-vault@latest pull --env dev

# one-off command (Bun)
bunx git-env-vault@latest doctor
bunx git-env-vault@latest pull --env dev

Global usage example:

npm i -g git-env-vault
envvault --version
envvault doctor

Install prerequisites by OS (full mode)

Use this if you want the full feature set (edit, set, grant, revoke, updatekeys, rotate).

Windows (winget)

# Node.js LTS + Git
winget install --id OpenJS.NodeJS.LTS -e
winget install --id Git.Git -e

# SOPS + age
winget install --id Mozilla.SOPS -e
winget install --id FiloSottile.age -e

macOS (Homebrew)

# Install Homebrew first if needed: https://brew.sh

# Node.js + Git
brew install node git

# SOPS + age
brew install sops age

Linux (Debian / Ubuntu)

sudo apt-get update
sudo apt-get install -y nodejs npm git sops age

Linux (Fedora / RHEL)

sudo dnf install -y nodejs npm git sops age

Linux (Arch)

sudo pacman -S --needed nodejs npm git sops age

Generate age key (all OS)

# Linux/macOS
mkdir -p ~/.config/sops/age
age-keygen -o ~/.config/sops/age/keys.txt
# Windows (PowerShell)
New-Item -ItemType Directory -Force "$env:APPDATA\\sops\\age" | Out-Null
age-keygen -o "$env:APPDATA\\sops\\age\\keys.txt"

Quick start (easy mode, no system SOPS required for pull)

1) Install package

npm i -D git-env-vault

# optional: prefer JS backend for basic usage
# set "cryptoBackend": "js" in envvault.config.json

2) Create your age key

age-keygen -o ~/.config/sops/age/keys.txt

3) Initialize repository config

envvault init

Generated files:

  • envvault.config.json
  • envvault.policy.json
  • .sops.yaml
  • secrets/

4) Decrypt secrets (pull)

envvault pull --env dev

If system sops is missing, envvault will try the JS backend automatically in cryptoBackend: "auto" mode.

5) Full mode (recommended for teams / production workflows)

Install system tools to enable editing and key management:

# macOS
brew install sops age

# Windows (winget)
winget install --id Mozilla.SOPS -e
winget install --id FiloSottile.age -e

# Linux examples
sudo apt-get install -y sops age
sudo dnf install sops age
sudo pacman -S sops age

Use built-in guidance:

envvault setup
envvault doctor --fix

6) Grant access (full mode)

envvault grant --env dev --service api --recipient age1...

7) Work with secrets

# interactive mode
envvault tui

# or direct commands
envvault edit --env dev --service api
envvault pull --env dev
envvault pull --env dev --service api --confirm
envvault push --env dev --service api --confirm
envvault diff --env dev --service api
envvault status --env dev

8) CI check

envvault ci-verify

Crypto backends

envvault.config.json supports:

{
  "cryptoBackend": "auto",
  "placeholderPolicy": {
    "preserveExistingOnPlaceholder": true,
    "patterns": ["__MISSING__", "CHANGEME*", "*PLACEHOLDER*"]
  },
  "localProtection": {
    "global": ["BOT_TOKEN", "TELEGRAM_BOT_TOKEN"],
    "services": {
      "core-bot": ["BOT_TOKEN"]
    }
  }
}
  • auto (default): try system sops first, then JS fallback for supported commands
  • system-sops: require system sops binary
  • js: force JS backend (basic decrypt/pull only)
  • placeholderPolicy: prevents generated placeholder values (for missing required keys) from overwriting an existing local value
  • localProtection: preserve selected local-only keys during pull / protect during push

Backend capability matrix

| Command / capability | JS backend (sops-age) | System SOPS | | --- | --- | --- | | pull / decrypt | Yes | Yes | | doctor capability detection | Yes (reported) | Yes | | edit | No | Yes | | set | No | Yes | | grant | No | Yes | | revoke | No | Yes | | updatekeys | No | Yes | | rotate | No | Yes |

Limitations of JS backend

  • Intended for decrypt flows (pull) only.
  • Does not replace system sops for write/re-encrypt/key-rotation operations.
  • Output formatting may differ from sops -d when using decryptToString.
  • Best used for onboarding/local read-only workflows; keep system sops + age for production maintenance.

Monorepo DX (v0.5.0)

Gitignore management

envvault gitignore check
envvault gitignore fix
envvault gitignore fix --dry-run

Refresh / rescan monorepo env files

# preview changes (config/schema only)
envvault refresh --dry-run
envvault sync --dry-run   # alias for refresh

# add extra excludes
envvault refresh --dry-run --exclude "apps/legacy/**"

# smarter service naming (dirname|path|fullpath-slug)
envvault refresh --dry-run --name-strategy dirname

# merge into existing config/schema instead of replacing
envvault refresh --dry-run --merge-config --merge-schema

# write config + schema
envvault refresh

# optional: create encrypted secrets snapshots (requires system SOPS)
envvault refresh --write-secrets

Name strategies:

  • dirname (default): apps/core-bot/.env -> core-bot
  • path: path-based composite name (safer when many duplicate dir names)
  • fullpath-slug: full relative path slug (most collision-resistant)

What refresh updates:

  • envvault.config.json (services map)
  • envvault.schema.yaml (keys per service)

What refresh does not do:

  • does not overwrite local .env files
  • preserves existing secretsDir / cryptoBackend config settings

Merge modes:

  • --merge-config: keep existing services and merge discovered ones
  • --merge-schema: keep existing schema services and merge discovered keys

Safe diff + confirm for pull

# preview key changes before writing local .env
envvault pull --env dev --service api --confirm

# machine-readable preview (no write)
envvault pull --env dev --service api --plan
envvault pull --env dev --service api --json

# keep local developer-only token untouched during pull
envvault pull --env dev --service core-bot --confirm --preserve-local BOT_TOKEN

# non-interactive apply (CI/automation)
envvault pull --env dev --service api --confirm --yes

# apply only selected changed keys (comma-separated)
envvault pull --env dev --service api --confirm --select-keys DATABASE_URL,REDIS_URL

# show secret values in diff (unsafe)
envvault pull --env dev --service api --confirm --unsafe-show-values

By default, diffs show only key names (added/removed/changed), not values.

pull --plan and pull --json are preview-only and do not write files.

Batch pull (multiple services)

# default behavior (when --service is omitted): process all configured services for the env
envvault pull --env dev

# explicit form (same behavior as above)
envvault pull --env dev --all-services

# wildcard filter
envvault pull --env dev --service-pattern "core-*"

# batch preview (no write)
envvault pull --env dev --service-pattern "core-*" --plan
envvault pull --env dev --all-services --json

Constraints:

  • use only one of --service, --service-pattern, or --all-services
  • --json / --plan are recommended for CI/review automation

Compare local env vs vault (no write)

envvault diff --env dev --service api
envvault diff --env dev --service api --unsafe-show-values
envvault diff --env dev --service api --plan
envvault diff --env dev --service api --json

Push local .env to encrypted secret (service-level)

envvault push --env dev --service core-bot --dry-run
envvault push --env dev --service core-bot --confirm
envvault push --env dev --service core-bot --confirm --yes
envvault push --env dev --service core-bot --confirm --preserve-local BOT_TOKEN
envvault push --env dev --service core-bot --exclude-keys DEBUG,DEV_ONLY_FLAG
envvault push --env dev --service core-bot --dry-run --json

Notes:

  • push requires system sops (JS backend is decrypt/pull only)
  • --preserve-local and config localProtection prevent selected local keys from being pushed into vault
  • --exclude-keys removes selected local keys from the sync input before encryption

Status (drift overview)

envvault status --env dev
envvault status --env dev --service core-bot
envvault status --env dev --json

status compares local envOutput files with vault secrets and reports key-level drift counts (+/-/~).

Non-interactive flags

  • pull --confirm --yes
  • set --confirm --yes
  • push --confirm --yes

CI workflows (special CI key + payloads)

Use a dedicated CI key (for example GitHub Actions secret ENVVAULT_CI_KEY) to create a transport payload that CI can decode without direct SOPS usage in the job step.

Create CI payload (local/dev machine or release bot)

From a vault secret:

envvault ci-seal --env dev --service api > ci-api-dev.payload

From a plaintext file:

envvault ci-seal --from-file apps/api/.env > ci-api-dev.payload

JSON output (for automation):

envvault ci-seal --env dev --service api --json

Decode CI payload in CI

# payload can come from CI secret/variable ENVVAULT_CI_BLOB
envvault ci-unseal --out apps/api/.env --validate-dotenv

Or pass payload directly:

envvault ci-unseal --payload "$ENVVAULT_CI_BLOB" --out apps/api/.env --validate-dotenv

CI verification

ci-verify now also checks for uncommitted .env* changes (for example .env.local) in git status.

envvault ci-verify --allow-unsigned

# bypass dirty .env check only when intentionally needed
envvault ci-verify --allow-unsigned --allow-dirty-env

Recommended CI secrets:

  • ENVVAULT_CI_KEY: symmetric key used by ci-seal / ci-unseal
  • ENVVAULT_CI_BLOB: encrypted payload generated by ci-seal

localProtection behavior (important for BOT tokens)

If a key is listed in localProtection, then:

  • during pull: local value is kept (vault value does not overwrite it)
  • during push: local value is not written into encrypted secret

This is useful for developer-specific tokens like BOT_TOKEN.

Placeholder-safe pull behavior (important for local CI/API tokens)

When schema validation adds placeholders for missing required keys (for example __MISSING__), pull will keep an existing local non-empty value instead of overwriting it with a placeholder.

This is useful when:

  • real values are injected only in CI via GitHub Actions secrets
  • developers already know and configured a local token manually
  • you still want schema-required keys to appear as placeholders for newcomers

Example:

  • vault/schema would produce BOT_TOKEN=__MISSING__
  • developer already has BOT_TOKEN=123... locally
  • envvault pull keeps the local BOT_TOKEN=123...

Config example:

{
  "placeholderPolicy": {
    "preserveExistingOnPlaceholder": true,
    "patterns": ["__MISSING__", "CHANGEME*", "*PLACEHOLDER*", "TODO_*", "<set-me>*"]
  }
}

Disable if needed:

{
  "placeholderPolicy": {
    "preserveExistingOnPlaceholder": false
  }
}

Documentation

Command overview

Core commands

  • envvault init
  • envvault pull --env <env> [--service <service>]
  • envvault push --env <env> --service <service>
  • envvault diff --env <env> --service <service>
  • envvault status --env <env> [--service <service>]
  • envvault refresh [--dry-run] [--write-secrets]
  • envvault sync [--dry-run] [--write-secrets] (alias for refresh)
  • envvault edit --env <env> --service <service>
  • envvault set --env <env> --service <service> KEY=VALUE...
  • envvault doctor
  • envvault ci-seal
  • envvault ci-unseal

Access control

  • envvault grant --env <env> --service <service> --recipient <age-public-key>
  • envvault revoke --env <env> --service <service> --recipient <age-public-key>
  • envvault updatekeys [--env <env>] [--service <service>]
  • envvault rotate --env <env> [--service <service>]

Local overrides

  • envvault promote --env <env> --service <service> --key <key>
  • envvault promote-all --env <env> --service <service>

Utilities

  • envvault hooks install --type pre-push|pre-commit
  • envvault hooks uninstall --type pre-push|pre-commit
  • envvault hooks status
  • envvault gitignore check
  • envvault gitignore fix [--dry-run]
  • envvault setup
  • envvault wizard
  • envvault up --env <env>
  • envvault ci-verify [--allow-unsigned]
  • envvault tui

Open source readiness check

Core files are present in this repository:

  • README.md
  • LICENSE
  • CONTRIBUTING.md
  • CODE_OF_CONDUCT.md
  • SECURITY.md
  • SUPPORT.md
  • CHANGELOG.md
  • .github/ISSUE_TEMPLATE/*
  • .github/PULL_REQUEST_TEMPLATE.md

Development

npm install
npm run build
npm run test
npm run lint

Cross-platform notes

  • .sops.yaml creation rules use a path-separator-safe regex ([\\/]) for Windows/macOS/Linux compatibility.
  • envvault setup prints OS-specific install commands for sops + age.

Support

Maintainer

Maintained by PAS7 Studio.

Funding

Ko-fi PayPal

License

MIT. See LICENSE.