Documentation
๐ Quick Start Guide
Go from a chaotic environment to a single Environment Contract โ documented, validated, and compiled into typed code โ in less than 5 minutes. This guide will walk you through the essential workflow.
๐ฌ Prefer visual learning? Check out the Features & Examples page for real-life walkthroughs with before/after scenarios and animations.
1. Install EnvShield
You'll need Python 3.10 or newer. Install EnvShield directly from PyPI โ it's a standalone CLI, no dependencies on your project's stack.
pip install envshield
2. Initialize Your Project (Three Paths)
Choose the path that fits your project. All three create a schema (`env.schema.toml`) that becomes your single source of truth.
# Scaffolds a schema from your framework (Next.js, Django, Flask, etc.)
# Also creates a git hook and updates .gitignore
envshield init
# Reads your existing .env file and auto-generates 90% of the schema
# The tool detects secrets, suggests defaults, and saves you manual work
envshield import .env.production --interactive
# Finds every service (api, web, worker, ...), registers them, and seeds
# each schema from that service's own real, current config -- in one command
envshield service discover
๐ก Verified example: we ran envshield import against a real 59-variable Flask config โ it correctly classified all 27 secrets and suggested real default values for 15 of the non-secret variables, with zero manual TOML written.
3. Curate Your Schema (The Contract)
Open the newly created `env.schema.toml`. This is your Environment Contract โ the single source of truth for all configuration. Review each variable, add human-readable descriptions, and mark which ones are secrets. This is the ONLY file you'll hand-edit.
[DATABASE_URL]
description = "The full connection string for the database."
secret = true
[LOG_LEVEL]
description = "Controls the application's log verbosity (DEBUG, INFO, WARNING, ERROR)"
secret = false
defaultValue = "info"
[STRIPE_API_KEY]
description = "Stripe API secret for payment processing"
secret = true
๐ก Why this matters: This schema now drives everything โ your `.env.example` generation, your typed config code, your validation, your onboarding wizard. Once it's right, everything stays in sync automatically.
4. Sync Documentation & Setup Your Environment
Now generate your `.env.example` (documentation) from the schema, and create your local `.env` file interactively. EnvShield will prompt you for each variable, hide secrets as you type, and validate everything.
# Generate .env.example from your schema (docs stay in sync)
envshield schema sync
# Interactively create your local .env (you'll be prompted for each var)
envshield setup
# Or create a different env file:
envshield setup .env.local
๐ก What just happened: Your `.env.example` was regenerated from the schema (never stale again), and you created your local `.env` without any manual copy-paste or guessing about which vars are secrets.
5. You're All Set!
Your environment is now secure and documented. The Git pre-commit hook is active and will scan for secrets before each commit. Your configuration is guaranteed to be in sync with your schema. You're ready to go!
# Verify everything is in order
envshield doctor
# Now build something amazing!
python app.py # or npm start, etc.
6. (Optional) Compile Your Contract Into Code
Turn the schema into the actual config your app
imports โ typed, validated, and with secrets
masked by default. Auto-detected for your
stack, or set explicitly with
--lang.
# Python (pydantic-settings)
envshield generate --lang python
# TypeScript (zod)
envshield generate --lang typescript
๐ก Core Concepts: The Environment Contract
EnvShield treats configuration as a **contract** โ a formal agreement between your schema and your application. Understanding these three artifacts is key to mastering this workflow. Only the first one is hand-written โ the other two are always generated from it.
- The Schema (`env.schema.toml`): This file is the **Environment Contract** itself. It's the undisputed source of truth, defining every variable your project needs, what it does, whether it's a secret, and if it has a default value. It lives in your repository and is version-controlled like the rest of your code.
- The Example File (`.env.example`): This file is the **human-readable documentation**. It's a build artifact that is automatically generated from your schema via the `schema sync` command. You never edit this file by hand; you commit it so that anyone browsing your repository can quickly understand the configuration requirements without needing the tool installed.
- The Generated Config Module: This is the **machine-readable enforcement** of the contract. Running `envshield generate` compiles the schema into real, importable `pydantic-settings` (Python) or `zod` (TypeScript) code โ your application reads its configuration through this typed, validated module instead of raw `os.getenv`/`process.env` calls.
๐ฏ Why EnvShield is Different
Most configuration tools solve one piece of the problem โ scanning, encryption, or cloud storage. EnvShield's focus is different: a schema-driven contract that works across multiple services in the same repo. Here's how it compares to the tools people usually reach for instead:
| Feature | EnvShield | Gitleaks | dotenvx | Infisical |
|---|---|---|---|---|
| Schema-driven configuration | โ Unique | โ | โ | โ |
| Multi-service support | โ Built-in | โ | โ | โ |
| Typed config code generation | โ Unique | โ | โ | โ |
| Interactive onboarding | โ | โ | โ | โ Cloud-only |
| Works offline | โ | โ | โ | โ |
The bottom line: Gitleaks detects secrets. dotenvx encrypts files. Infisical stores secrets in the cloud. EnvShield takes a different approach: a versioned schema that drives documentation, validation, onboarding, and typed code generation โ for one service or many โ all in one local-first CLI.
๐ A-to-Z Command Reference
๐๏ธ init
The "zero-to-hero" command. Run this first in a new project to scaffold a complete, best-practice configuration foundation.
What it does:
- Intelligently inspects your project to detect the framework (e.g., Next.js, Django).
- Creates an `env.schema.toml` file with smart defaults for that framework.
- Creates a simple `envshield.yml` configuration file.
- Safely updates your `.gitignore` file with necessary patterns.
- Automatically installs the Git pre-commit hook for proactive security.
Flags:
--force or -f: Allows
`init` to overwrite existing EnvShield files. It
will always ask for a final confirmation before
proceeding.
Use Case
You're starting a new Django project. You run `envshield init`. The tool detects Django, creates a schema with `SECRET_KEY` and `DATABASE_URL`, updates your `.gitignore`, and installs the security hook. Your project is set up for success in one command.
Already have more than one service in this repo? `init` bootstraps a single schema โ for a multi-service project, use `envshield service discover` instead.
๐ import
The "get started yesterday" command. This is the fastest way to adopt EnvShield for an existing project with a large, messy `.env` file.
What it does:
- Reads an existing `.env` file (like `.env.production`).
- Intelligently analyzes each variable's key and value.
- Automatically marks known secrets (API keys, tokens) using its built-in scanner logic.
- Suggests default values for common variables (like `DEBUG` or `PORT`).
- Generates a complete `env.schema.toml` file for you.
Arguments & Flags:
-
<file>: (Required) The path to the `.env` file you want to import. -
--outputor-o: Specify a different output path for the schema file (default: `env.schema.toml`). -
--forceor-f: Allows `import` to overwrite an existing schema file. -
--interactive: Walks you through each variable one by one, letting you confirm if it's a secret and if you want to set a default value.
Use Case
You want to adopt EnvShield for a 2-year-old project. You run the command:
envshield import .env --interactive
The tool guides you through all 50 variables, correctly guessing 45 of them, and generates a perfect schema file in two minutes instead of an hour of manual work.
๐ญ service
The fast path for multi-service projects. A
subcommand with three actions:
discover, add, and
list.
discover โ What it does:
-
Scans your repo for directories that look
like independent services โ a real dotenv
file (any
.env.*name, not just.env), or a recognizable Python config module. -
Skips a directory that only has a generic
project marker (
pyproject.toml,package.json) with no actual config in it โ a shared library sitting next to your real services won't get mistaken for one. - Shows you what it found and asks before writing anything.
-
On confirmation, registers each service in
envshield.ymland seeds its schema straight from its real, current config โ the same logic asimport. - Safe to run again later: already-registered services are never re-suggested or touched. It bootstraps a fresh setup from nothing, or extends an existing one with whatever's new.
$ envshield service discover
Discovered Services
โโโโโโโโโโณโโโโโโโโโโโโโโโโโณโโโโโโโโโณโโโโโโโโโโโโโโโโโโโโโโโโ
โ Name โ Directory โ Format โ Config File โ
โกโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฉ
โ api โ services/api โ dotenv โ (default .env) โ
โ web โ services/web โ dotenv โ (default .env) โ
โโโโโโโโโโดโโโโโโโโโโโโโโโโโดโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโ
? Add these services to envshield.yml? (api, web pre-selected) Yes
โ Registered api โ services/api/env.schema.toml
โ Registered web โ services/web/env.schema.toml
add & list
envshield service add <name> <directory>
registers one service by hand โ useful when you'd
rather be explicit than rely on detection, with
--local-file, --description,
and --import <file> to seed its
schema in the same step.
envshield service list prints every
service currently configured.
Use Case
You're adopting EnvShield in an existing Turborepo
with five apps. Instead of hand-writing
envshield.yml and running
import five times, one command finds
them all, and one confirmation seeds all five
schemas from their real, current
.env files.
๐ช scan
Your project's personal bodyguard. It scans files for hardcoded secrets and undeclared environment variables used in your code.
Arguments & Flags:
-
[PATHS]...: The specific files or directories to scan. If you don't provide a path, it scans the current directory. -
--staged: Scans only the files you've staged for your next Git commit. This is the heart of the pre-commit hook. -
--config <file>: Use a different `envshield.yml` for this specific scan. -
--exclude <pattern>: A glob pattern to exclude from this specific scan. Can be used multiple times.
Use Case
Your pre-commit hook is blocking a commit because of a secret in a test file. You realize you forgot to add an exclusion rule. You can add it to `envshield.yml` to fix it permanently, or use a one-off command to bypass it for now:
git commit -m "My commit" --no-verify # Bypass the hook for now
envshield scan . --exclude "**/tests/*"
๐ install-hook
Manually installs the Git pre-commit hook if you skipped it during `init` or if it was removed.
What it does:
Creates (or overwrites) a `pre-commit` script in your `.git/hooks/` directory that runs `envshield scan --staged`.
Use Case
You've added `envshield` to a project that already had a different pre-commit hook. After you manually merge the two scripts, you can run `envshield install-hook --force` to create the final, combined hook.
๐ schema
The `schema` command is a subcommand with one action: `sync`. It's your primary tool for keeping your project's documentation (`.env.example`) perfectly in sync with your schema.
Usage
envshield schema sync
Use Case
You add a new `REDIS_URL` variable to your `env.schema.toml`. Before you commit, you run `envshield schema sync`. The `.env.example` is instantly and correctly updated with the new variable and its description, ready to be committed.
โ check
The "is it plugged in?" command for your local setup. It validates a local environment file against the official contract in `env.schema.toml`.
What it does:
It reports variables missing entirely, variables declared but still left blank (e.g. a required secret checked in as an empty placeholder), and extra variables that aren't in the schema โ helping you find configuration errors before they cause runtime bugs, not after.
Use Case
Your app fails to start after a teammate's PR. You run the command:
envshield check .env.local
The tool reports `Missing in Local: NEW_SERVICE_API_KEY`, instantly telling you what's wrong.
๐ช setup
A taste of the automated onboarding magic. This is the perfect command for getting started on a project.
What it does:
It looks at whatever you already have โ your real local file if one exists, or `.env.example` as a template if not โ and prompts you only for variables that are still blank or missing, showing each one's description and masking input for secrets. On a multi-service project, running it with no `--service` asks which one (or All services, walking through each service's wizard in turn). If your local config isn't a dotenv file โ e.g. a Python module โ it patches just the missing values into it in place, instead of overwriting the file.
Use Case
You just cloned a new project. You run `envshield setup`. The tool asks you for the `DATABASE_URL` and `STRIPE_API_KEY`, then generates your fully-populated `.env` file. You are ready to run the project in minutes.
๐ฉบ doctor
The "turn it off and on again" command for your entire configuration. It runs a comprehensive suite of health checks on your project's `envshield` setup.
What it does:
- Checks that your `envshield.yml` and `env.schema.toml` files exist and are valid.
- Validates your local `.env` file against the schema.
- Ensures your `.env.example` file is in sync with the schema.
- Verifies that the security hook is installed and active.
Flags:
--fix: The magic wand. If the doctor
finds a problem, it will interactively ask you if
you want to fix it automatically.
Use Case
Something just feels wrong with your setup. You run `envshield doctor`. It reports that your `.env.example` is out of date and the Git hook is missing. You run `envshield doctor --fix`, answer "Yes" to both prompts, and the tool fixes everything for you.
๐งฌ generate
The command that turns your contract into code. It compiles `env.schema.toml` into a typed, validated config module โ no more raw `os.getenv()` / `process.env` calls scattered through your codebase, and no more secrets that can accidentally end up in a log line.
What it does:
- Renders every variable in your schema into a real, importable module: `pydantic-settings` for Python, or a `zod`-validated module for TypeScript.
- Infers each variable's type (`str`, `int`, `bool` / `string`, `number`, `boolean`) from its `defaultValue`. Variables with no default become required fields โ the module raises a validation error at import time if they're missing.
- Wraps every `secret = true` variable in a masked type (`SecretStr` in Python, a local `Secret<T>` wrapper in TypeScript) so it can't accidentally leak via a `print()`, `console.log`, `JSON.stringify`, or stack trace. You call `.get_secret_value()` / `.value` explicitly to read it.
Arguments & Flags:
-
[output_file]: Where to write the generated module. Defaults to `config.py` or `config.ts` depending on the resolved language. -
--langor-l: `python` or `typescript`. If omitted, EnvShield auto-detects from your project the same way `init` does โ Next.js, Vite, and Node.js projects default to TypeScript; everything else defaults to Python. -
--forceor-f: Allows `generate` to overwrite an existing output file.
Use Case
Your Next.js app currently reads `process.env.STRIPE_SECRET_KEY` directly in six different files, with no validation that it's actually set. You run:
envshield generate --lang typescript
EnvShield writes `config.ts` with a `zod` schema built from your contract. You replace the six direct `process.env` reads with `import { env } from './config'` โ now a missing or malformed variable fails loudly at startup instead of silently at runtime, and `env.STRIPE_SECRET_KEY` prints as `**********` anywhere it's accidentally logged.
โ๏ธ The `env.schema.toml` File
This file is the heart of your configuration. It's a TOML file where you define every environment variable your project needs. Here's a breakdown of the keys for a variable:
[DATABASE_URL]
# (Required) A human-readable explanation of what this variable is for.
# This is used to generate comments in your .env.example file.
description = "The full connection string for the PostgreSQL database."
# (Required) A boolean that marks the variable as sensitive. Used right now
# by `setup` (hides the value as you type it) and `generate` (wraps it in
# SecretStr / a Secret type so it can't leak into a log line by accident).
secret = true
# (Optional) A default value for the variable.
# If a variable has a defaultValue, `envshield check` will not report it as missing.
# It will also be pre-filled in your .env.example file.
defaultValue = "postgres://user:pass@localhost:5432/mydb"
โ๏ธ The `envshield.yml` File
This file controls EnvShield's own settings โ and, for a
multi-service project, it's where every service is
registered. envshield service discover
writes this file for you (see below); this is what it
looks like under the hood.
# The name of your project (used for display purposes).
project_name: my-project
# Global settings for the secret scanner.
secret_scanning:
# A list of file patterns to ignore during scans (e.g., test files).
exclude_files:
- "**/tests/*"
- "**/test/*"
services:
api:
path: services/api/env.schema.toml
web:
path: services/web/env.schema.toml
# A service whose local config isn't a dotenv file at all -- e.g. a
# Flask app that keeps its local config in a plain Python module --
# points `local_file` at it directly. EnvShield reads/writes it as
# source, patching or appending plain assignments in place rather
# than treating it like a dotenv file.
worker:
path: services/worker/env.schema.toml
local_file: services/worker/config/settings.local.py
Every command accepts --service <name>.
Omit it on a single-service project and nothing changes;
omit it on a multi-service project and you're prompted โ
pick one service, or All services to run
against every one of them in the same command.
๐ฃ๏ธ Roadmap: The Future is Bright
Phase 1 is the free, powerful foundation. But the journey doesn't end here. Upcoming paid tiers will turn EnvShield into a complete collaboration and automation platform for teams and enterprises.
Phase 1: The Local Guardian (Free, Live Now) โ
Everything you need for a single developer or small team:
- Schema-driven configuration management
- Multi-service support, with automatic service discovery
- Typed config code generation (Python + TypeScript)
- Interactive onboarding wizard
- Configuration drift detection
- Pre-commit secret scanning
Phase 2: The Team Collaborator (Paid Tier, Coming Soon)
Scale to teams with environment profiles and automation:
- Environment Profiles: Switch between dev/staging/prod configurations with one command.
- Schema Diffing: See exactly what configuration changed between environments.
- Automated Onboarding: Setup command that also runs database migrations, docker compose, and custom scripts.
- Team Collaboration: Securely share secrets with teammates via encrypted links.
- CI/CD Integration: Validate configuration before deployment, inject secrets into pipelines.
Phase 3: The Enterprise System (Paid Tier, Future)
Mission-critical features for large organizations:
- Cloud Secret Vault: Optional centralized backend for teams that need it (not required, everything still works locally).
- Vault Integration: Pull secrets from HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, etc.
- Audit Logs & RBAC: Complete compliance trail of all secret access with role-based access control.
- Policy Engine: Enforce naming conventions, require descriptions, mandate secrets for certain patterns.