Hello readers,
Here's a scenario I've lived through more times than I'd like to admit. You git pull, run the dev server, and get some cryptic error that takes you twenty minutes to debug — only to find that someone added STRIPE_WEBHOOK_SECRET to .env.example three days ago and nobody told you.
You check the PR. There it is. A one-line change. You missed it.
This is .env drift. It happens to every team. It's boring to fix every time. So I built env-pull to fix it once.
What is the actual problem?
.env.example is the contract. It says "these are the variables this project needs." Your .env is your local copy, filled with your actual secrets.
The problem is keeping these two in sync. Every time someone adds a new variable, renames one, or updates a comment explaining what a value should look like — your .env knows nothing about it. You have to manually diff the two files and figure out what changed.
Comments matter more than people think. A teammate might change # your Stripe test key to # use the live key in staging or add # see Notion doc: stripe-setup next to a variable. That context is genuinely useful. But if it only lives in .env.example and never makes it into your local .env, you'll never see it when you actually need it.
Nobody does this well. You either copy the whole example (losing your values) or forget entirely (breaking your setup). Both are bad.
The fix is one command
Run npx env-pull after any git pull and it will:
- >Find your
.env.example(or.env.sample,.env.template— it auto-detects all of them) - >Compare it against your
.env - >Show you exactly what's new, what changed, and what's in your local env but not in the example
- >Ask you for values on new variables — or just fill in the defaults if you're in a hurry
Your existing secrets stay untouched. It only adds what's missing.
Set it and forget it
The even better way to use it is to never think about it again. Run env-pull init to install a post-merge git hook. Now every time you git pull and there are changes, env-pull runs automatically. You'll see a prompt if new variables were added. Nothing happens if everything is already in sync.
If you're using Husky, add this to .husky/post-merge:
#!/bin/sh
npx env-pull -q
The -q flag skips the interactive prompts and fills in example values automatically. Good for CI, good for teammates who just want things to work.
The flags worth knowing
| Flag | Behaviour |
|---|---|
| (none) | Interactive — shows diff, prompts for values |
-q | Quiet — fills defaults, no prompts |
--dry-run | Preview what would change, writes nothing |
--backup | Creates .env.backup before touching anything |
check | Exits with code 1 if .env is out of sync |
env-pull check is particularly useful in CI pipelines. Put it in your GitHub Actions workflow and your build will fail loudly if someone pushes a new env variable without updating the docs:
- run: npx env-pull check
Now the person who added the variable has to make sure everyone knows about it. Good.
Here's where it gets interesting: AI coding agents
I built env-pull for human developers. But since I've been using Claude Code and Cursor heavily for the past year, I've noticed something — AI agents have the same problem, except worse.
When an AI agent clones a repo or starts working in a fresh environment, it has no idea what your .env should look like. It might read your .env.example and try to fill it in, but it's guessing. It might hallucinate values. It might skip variables it doesn't understand. And because agents don't always check whether the app actually boots cleanly before writing code, you end up with a setup that silently fails at runtime.
env-pull solves this at the process level rather than relying on the agent to "figure it out."
Adding env-pull to your CLAUDE.md
If you use Claude Code, you can add instructions to your CLAUDE.md file so the agent runs env-pull as part of setup:
## Environment Setup
Before starting any dev server or running tests, ensure the .env file is in sync:
npx env-pull -q
If `env-pull check` exits with code 1, stop and report which variables are missing
before proceeding with any implementation.
Now the agent handles env sync as a first step — automatically, every time, without you having to remind it.
Use it in your setup scripts
A lot of teams have a scripts/setup.sh or a Makefile target. Adding env-pull here means any agent (or new teammate) that runs setup gets a properly synced env:
#!/bin/bash
echo "Installing dependencies..."
npm install
echo "Syncing environment variables..."
npx env-pull -q
echo "Running migrations..."
npm run db:migrate
echo "Setup complete."
When an agent is asked to "set up the project and get it running," it will find this script, run it, and have a correct .env before touching a single line of application code.
Validating before every run
In my own projects I've started adding this to the dev script in package.json:
{
"scripts": {
"predev": "npx env-pull check",
"dev": "next dev"
}
}
predev runs before dev. If the env is out of sync, the dev server never starts. The agent sees the error, understands it needs to sync the env, runs env-pull, and tries again. Clean feedback loop.
This matters a lot with agents because they tend to retry things multiple times. If your env is broken silently, the agent will keep writing code and running tests against a misconfigured environment and give you a completely wrong diagnosis of what's broken.
The check command is perfect for agent workflows
Agents work best when they have clear, binary signals. env-pull check is exactly that — it exits 0 if everything is fine and 1 if something is missing. Agents can run this as a health check at any point without worrying about modifying anything. No side effects. No prompts. Just a clear answer.
Edge cases it handles (so you don't have to)
A few things I made sure worked properly because I ran into them myself:
Multiline values — things like private keys that span multiple lines with \n are handled correctly. It won't mangle your RSA key.
Inline comments — if your example has DATABASE_URL=postgres://localhost # change in prod, the comment comes along for the ride. This also means when someone updates a comment in .env.example — to add a link to docs, clarify the expected format, or flag a staging-vs-production difference — that update propagates to your .env on the next sync. The comment is part of the contract too.
export syntax — some projects use export VAR=value. env-pull understands this and doesn't break it.
Special characters — values with spaces, #, or = in them get auto-quoted so they don't corrupt your file.
Local-only variables — if you have variables in your .env that aren't in the example (like personal debug flags or local overrides), they don't get deleted. They get moved into a clearly labelled section at the bottom.
Install it
Use it without installing via npx env-pull, install it globally with npm install -g env-pull (or the bun/pnpm equivalents), or add it as a dev dependency with npm install --save-dev env-pull.
Works with Node.js 18 and above. No config files, no setup beyond the optional git hook.
Make it even faster with a shell alias
If you install it globally, consider adding a short alias to your .bashrc or .zshrc:
alias ep="env-pull"
alias epc="env-pull check"
alias epq="env-pull -q"
Then ep syncs interactively, epq fills in defaults quietly, and epc gives you a quick health check. Three characters instead of eight. It adds up.
The source is on GitHub and it's MIT licensed. If you run into a file pattern it doesn't detect or an edge case it handles badly, open an issue. I actively maintain it.
The irony is that environment variable management is one of those problems that feels too small to solve properly — so everyone just accepts the pain. But it adds up. Every "why isn't this working" that turns out to be a missing env var is ten to twenty minutes wasted. Multiply that by a team, multiply that by a year.
env-pull is small. It does one thing. But that one thing is actually worth doing.
Feel free to connect if you have questions, run into issues, or just want to tell me this saved you from another late-night debugging session.