Overview
crabenv is an env var management standard created to minimize env var schema + documentation drift in any codebase
crabenv is an env var management standard created by Carlo Taleon to minimize env var schema + documentation drift in any codebase. If you follow this standard, you'll find it extremely seamless to "develop locally" and "deploy to production" in any platform!
It's available as:
- a cli (recommended)
- a skill (for agents, no cli needed)
- a guide (for humans, no cli needed)
You're currently reading the "skill" / "guide". If you're planning to use the CLI, just read the concepts and then use crabenv --help and you'll understand how to use it.
Goals
- Typesafety & Validation
- Good documentation
- Seamless local development -> deployment story.
Concepts
Env Management in production codebases is essentially:
- Local (
.env) - Can be absent. Always one. - Schema (
env.*.ts,env.rs,env.py,env.dart, etc.) - Required. These are opinionated names, deal with it 😎 - Template (
.env.example) - Required. - Sinks (
docker.compose.yml,.github/actions/*.yml,Dockerfile, etc.) - Can-be-absent. Can include the subset of envs i.e.NEXT_PUBLIC_*vars that are essential for builds.
Agnostic Rules
# File structure (ts for example)
- .env
- .env.example
- src/
- env.*.tsThis is applicable for every language.
- Locally, always only one
.env. Even in monorepos. - Always make sure that a variable defined in "Schema" is defined in "Template", "Local", "Sinks".
- In Template (
.env.example) - always add a default value if you can. - In Template (
.env.example) - you can indicate to make default random values with"$(openssl rand -hex 32)"or"$(pwd)/local.db"- this helps in self-hosted deployments, etc. - Documentation should live in the "schema" file. i.e. "I got this variable from"
- As much as possible the structure/sorting should be equal for:
.env.example(example values) =.env(real values)
Special monorepo/multi-language repo rules:
# File Structure (ts for example)
- .env
- .env.example
- apps/
- app1/
- src/env.*.ts
- .env.example
- app2/
- src/env.*.ts
- .env.example-
Again, always have one
.envat the very root of the codebase. It makes definition simpler. -
Use a
"with-env"script to always channel the root env into sub-apps in a monorepo. -
NEVER add envs in sub-packages (i.e.
packages/*in npm monorepos) -
Using the same name ALWAYS MEANS "shared variable" i.e.
DATABASE_URLin app1 and app2 should always mean the same thing. If it's not meant to be shared, just call it differently. (It really helps to make a distinction for it) -
For the ROOT
.envand.env.example, the structure should look like this (note the comment groupings):# shared NODE_ENV="production" DATABASE_URL="" # apps/app1 RSA_PRIVATE_KEY="123" # apps/app2 CMS_URL="http://localhost:3001"
For language-specific rules/examples, visit Language Guides.