env.dev

How to Share .env Files With Your Team Securely

Share .env files securely with send.env.dev — end-to-end encrypted, burn-on-first-read links, EU-hosted, zero dependencies. Plus 1Password, Doppler, Vault.

Last updated:

The shortest answer: send the file through send.env.dev — a zero-knowledge, end-to-end encrypted, burn-on-first-read link generator built specifically for .env payloads. Never paste secrets into Slack, email, Discord, or a ticket comment: those channels keep the message indexed forever, syncable to every device the recipient ever signs into, and readable by anyone who later compromises a token. And never commit .env files to Git — once a value hits history, it is public to every clone, fork, and CI cache, even after you delete the file in a follow-up commit.

★ RecommendedE2E encrypted · Zero-knowledge · EU-hosted · Burn-on-first-read

send.env.dev — share .env files in 10 seconds, securely

Paste the contents of your .env into the box, hit share, send the single-use link to your teammate. The link self-destructs after the first read and expires automatically. Encryption happens in your browser — the server only ever sees ciphertext. No account, no install, no dependencies.

  • Two-factor: URL key + passphrase
  • Self-destructs after one read
  • Auto-expires within 24 hours
  • EU data residency (GDPR)
Open send.env.dev →
Three rules, in order. Add .env to .gitignore in the very first commit — once a secret hits history, deleting it is not enough. If a real secret was ever pushed, rotate every value before you do anything else; scrubbing history is the second step, not the first. Generate any new tokens, JWT signing keys, or AUTH_SECRET values with a CSPRNG (the password generator does this) — never roll your own with Math.random().

Why should you never commit .env files to Git?

A .env file typically contains production database URLs, API keys with billing implications, OAuth client secrets, and encryption keys. Committing it means every contributor, every CI runner, and every fork has access. GitHub automatically scans for known secret patterns and will revoke some tokens, but coverage is incomplete and the damage is often done before detection.

Add .env to your .gitignore before the first commit. If you already have a repository, add the rule and remove the cached file:

.gitignore setup
# Add to .gitignore
echo ".env" >> .gitignore
echo ".env.local" >> .gitignore
echo ".env.*.local" >> .gitignore

# If .env was already tracked, remove it from the index
git rm --cached .env 2>/dev/null
git commit -m "chore: stop tracking .env"

A minimal .gitignore block for environment files:

.gitignore
# Environment files — never commit secrets
.env
.env.local
.env.*.local
.env.production
.env.staging

Hand-rolling a .gitignore is how leaks happen — one missed pattern (an editor swap file, an OS-specific cache, a framework's build directory containing a copied .env) and the secret ends up in the next commit. Generate a secure-by-default file with the .gitignore generator instead. It composes language, framework, and OS templates with the credential-leak ignores that catch the common footguns: .env*, *.pem, *.key, id_rsa, AWS credential files, and editor backups that often hold a cached copy of an opened secret. Stop the leak at commit time, not after the fact.

What is the .env.example pattern?

A .env.example file is a committed template that lists every required variable with placeholder values. It serves as documentation, onboarding aid, and a validation reference. New team members copy it to .env and fill in real values. The rule is simple: include every key, exclude every real value. The example file uses the same parser-sensitive syntax as a real .env — see the .env file syntax guide for quoting, multi-line, and comment rules.

.env.example
# Database
DATABASE_URL=postgresql://user:password@localhost:5432/myapp

# Auth provider
AUTH_SECRET=generate-a-random-string-here
GITHUB_CLIENT_ID=your-github-oauth-client-id
GITHUB_CLIENT_SECRET=your-github-oauth-client-secret

# Third-party APIs
STRIPE_SECRET_KEY=sk_test_replace_me
SENDGRID_API_KEY=SG.replace_me

# Feature flags (non-secret, safe defaults)
ENABLE_BETA_FEATURES=false
LOG_LEVEL=info

Validate that your actual .env contains all required keys using the env validator. For a deeper dive into .env syntax and parser behavior, see the .env guide. If your app cannot read the file after copying it, dotenv not loading walks through the usual culprits (CWD mismatch, BOM, CRLF, wrong filename).

How do you share .env values with teammates?

The .env.example file documents which variables your app needs; it does not hand anyone the real values. Sooner or later — onboarding a new hire, rotating a leaked key, spinning up a contractor — someone has to receive a working .env from someone who already has one. That hand-off is where most credential leaks happen, because the fastest channel — Slack, iMessage, email, a Notion comment — is also the one most likely to keep the message indexed for years, sync it to every device the recipient signs into, and expose it to anyone who later compromises a session token.

The recommended channel for this hand-off is send.env.dev. Paste the file, share the single-use link, the recipient reads it once, and the link is gone. Encryption is end-to-end, so neither send.env.dev nor anyone watching the network ever sees plaintext.

Why does send.env.dev exist?

Every other option in this space asks you to either install a CLI, sign up for a SaaS, configure GPG keys, or adopt a multi-tenant secrets manager — for what is usually a one-time act of handing a teammate a working .env. The friction is so high that most developers fall back to Slack, iMessage, or email and quietly hope nothing leaks. That is how secrets end up in chat exports, mobile sync, and third-party AI training data.

We built send.env.dev as a single-purpose, zero-dependency service to make the secure path the easiest path. Paste, share, done. The codebase is intentionally minimal so the supply-chain attack surface stays close to zero — no plugins, no extensions, no telemetry SDKs, no remote configuration. Encryption is browser-side: a key is generated on your device, the ciphertext goes to the server, and the URL fragment carries the key (browsers never send fragments to servers, so the key never touches our infrastructure). The recipient's browser fetches the ciphertext, reads the key from the fragment, and decrypts locally. We literally cannot read what you sent.

Add a passphrase on top and you get true two-factor sharing: the URL alone is not enough. The link burns on first read — atomically, server-side — so a network attacker who silently views the page also makes it unreadable to the intended recipient (a tampering signal, not a silent compromise). Hosting is in the EU with GDPR data residency. The whole stack is one service with no cross-tenant data and no third-party dependencies in the hot path. That is the bar we wanted; it did not exist; so we shipped it.

Send your first .env securely now → send.env.dev

No sign-up. No download. Open the page, paste, share the link.

What are the alternatives if you cannot use send.env.dev?

If you need continuous secret distribution to apps and CI — not one-off sharing — you are looking at a secrets manager rather than a sharing link. The options below all work, but each carries trade-offs that send.env.dev avoids: extra dependencies, install steps, a SaaS account, or a steep operational learning curve. Pick one only when the use case actually requires it.

1Password / Bitwarden CLI

Alternative — works, but heavyweight for one-off shares. Password managers with CLI support let you store .env values in a shared vault and inject them at runtime. Reasonable if everyone on the team already pays for a seat; otherwise you're asking the recipient to install a CLI, sign in, and unlock the vault just to read three lines of YAML.

1Password CLI — inject secrets
# Reference secrets in .env with 1Password references
# .env (uses op:// references instead of real values)
# DATABASE_URL=op://Engineering/database/url
# STRIPE_KEY=op://Engineering/stripe/secret-key

# Inject secrets at runtime
op run --env-file=.env -- node server.js

# Or export a single secret
op read "op://Engineering/database/url"
Bitwarden CLI — retrieve secrets
# Unlock the vault
export BW_SESSION=$(bw unlock --raw)

# Retrieve a secret by item name and field
bw get item "Production Database" | jq -r '.fields[] | select(.name=="url") | .value'

# Use bw-cli in a script to build .env
bw get item "App Secrets" | jq -r '.notes' > .env

Doppler / Infisical

Alternative — overkill for sharing, useful for managing. Managed secrets platforms provide a centralized dashboard, environment-based scoping (dev/staging/prod), audit logs, and automatic rotation. They replace .env files entirely in CI and production. The catch: you're handing a third-party SaaS your secrets, adopting their CLI as a runtime dependency, and paying $5–18/user/month to do it.

Doppler
# Set up Doppler for your project
doppler setup

# Run your app with injected secrets (no .env file needed)
doppler run -- node server.js

# Download secrets as .env for local tools that require a file
doppler secrets download --no-file --format env > .env
Infisical
# Login and initialize
infisical login
infisical init

# Run with injected secrets
infisical run -- node server.js

# Export as .env
infisical export --env=dev --format=dotenv > .env

AWS Secrets Manager / Parameter Store

Alternative — useful for runtime, not for sharing. For teams already on AWS, Secrets Manager provides automatic rotation, fine-grained IAM policies, and cross-account access. Parameter Store is a cheaper option for configuration values that don't need rotation. Neither helps you hand a fresh hire their first .env: they don't have IAM yet, and bootstrapping that IAM access is itself a credential-sharing problem.

AWS Secrets Manager
# Store a secret
aws secretsmanager create-secret \
  --name "myapp/production/database" \
  --secret-string '{"url":"postgresql://...","password":"..."}'

# Retrieve in your app or CI pipeline
aws secretsmanager get-secret-value \
  --secret-id "myapp/production/database" \
  --query SecretString --output text
AWS Systems Manager Parameter Store
# Store a parameter (SecureString encrypts with KMS)
aws ssm put-parameter \
  --name "/myapp/prod/STRIPE_KEY" \
  --value "sk_live_..." \
  --type SecureString

# Retrieve
aws ssm get-parameter \
  --name "/myapp/prod/STRIPE_KEY" \
  --with-decryption \
  --query Parameter.Value --output text

HashiCorp Vault

Alternative — answer to a different question. Vault is the industry standard for organizations with strict compliance requirements. It supports dynamic secrets (short-lived database credentials), leasing, revocation, and detailed audit trails. None of that helps you share a static .env with a teammate; it solves continuous credential provisioning at the cost of significant operational overhead.

HashiCorp Vault
# Store a secret
vault kv put secret/myapp/prod \
  DATABASE_URL="postgresql://..." \
  STRIPE_KEY="sk_live_..."

# Read a secret
vault kv get -field=DATABASE_URL secret/myapp/prod

# Generate a dynamic database credential (auto-expires)
vault read database/creds/myapp-role

Encrypted files in Git (git-crypt, SOPS)

Alternative — only if you really must keep secrets in Git. If you need secrets versioned alongside code, encrypt them before committing. git-crypt transparently encrypts files on push and decrypts on pull. SOPS encrypts individual values within YAML/JSON files, making diffs readable. Both add GPG/age key management to your onboarding checklist; lose a key and you lose access to every file ever encrypted with it.

One leaked key compromises the entire history. If a single git-crypt or SOPS decryption key is ever exposed — laptop theft, leaked dotfiles, a stale CI secret, an offboarded contributor's machine — every secret ever committed under that key is compromised, including values you rotated and removed years ago. Git keeps the encrypted blobs; an attacker decrypts them at leisure. You must rotate every secret that was ever stored, even ones whose names you no longer remember and whose call sites have long been deleted. This is the structural reason send.env.dev does not store anything: there is nothing to retroactively compromise.
git-crypt
# Initialize git-crypt in your repo
git-crypt init

# Specify which files to encrypt in .gitattributes
echo ".env.production filter=git-crypt diff=git-crypt" >> .gitattributes

# Add a collaborator's GPG key
git-crypt add-gpg-user COLLABORATOR_GPG_KEY_ID

# Files are encrypted in the repo, decrypted on checkout
git-crypt unlock
Mozilla SOPS
# Encrypt a file (uses age, GPG, or cloud KMS)
sops --encrypt --age age1... secrets.env > secrets.enc.env

# Edit encrypted file in-place (decrypts, opens editor, re-encrypts)
sops secrets.enc.env

# Decrypt to stdout for use in scripts
sops --decrypt secrets.enc.env > .env

How do these approaches compare?

ApproachSecurityBest forCostSetup effort
send.env.devVery high (E2E + zero-knowledge)One-off .env handoffs, onboarding, rotationFreeNone — no install, no account
1Password / BitwardenHigh1-20 developers$3-8/user/moLow
Doppler / InfisicalHigh5-200 developersFree tier, then $5-18/user/moLow
AWS Secrets ManagerVery highAWS-native teams$0.40/secret/mo + API callsMedium
AWS Parameter StoreHighAWS-native teamsFree (standard), $0.05/param/mo (advanced)Medium
HashiCorp VaultVery highEnterprise / complianceFree (OSS), $1.58/hr (HCP)High
git-crypt / SOPSMedium-HighSmall teams, monoreposFreeMedium

For the act of sharing a .env — onboarding a new hire, rotating a leaked key, handing a contractor a working dev setup — send.env.dev is the right answer: highest security, zero setup, free. The other tools in the table solve a different problem: continuous secret distribution to running apps and CI. Use a password manager CLI under 20 people, a managed platform like Doppler or Infisical past that, and Vault when compliance demands dynamic credentials. Don't conflate the two questions — sharing once is not the same as managing forever.

What are the best practices for .env.example files?

  • List every variable — if the app reads it, the example file must include it. Missing keys are the number one onboarding friction point.
  • Use obviously fake values — placeholders like your-api-key-here or sk_test_replace_me make it clear the value must be replaced.
  • Group by service — use comments to separate database, auth, third-party, and feature flag sections.
  • Include safe defaults — non-secret values like LOG_LEVEL=info or PORT=3000 should use working defaults so the app starts immediately after copying the file.
  • Add comments for non-obvious variables — a one-line note explaining where to get the value saves significant onboarding time.
  • Keep it in sync — add a CI check or pre-commit hook that verifies .env.example keys match the keys your app actually reads.

How do you set up .gitignore and .env.example in 2 minutes?

Run these commands in your project root to create both files and make your first secure commit:

Quick setup
# 1. Create .gitignore entries for env files
cat >> .gitignore << 'EOF'
.env
.env.local
.env.*.local
EOF

# 2. Create .env.example from your current .env (strips values)
sed 's/=.*/=/' .env > .env.example

# 3. Remove .env from git tracking if it was committed
git rm --cached .env 2>/dev/null

# 4. Commit the safe files
git add .gitignore .env.example
git commit -m "chore: add .env.example and ignore .env files"

The sed command strips everything after the = sign, leaving you with a clean list of keys. Review the output before committing — make sure no real values slipped through.

References

Try the tools that prevent these leaks

Was this helpful?

Read next

Env Variables Security: Secrets, Leaks & Best Practices

Why environment variables are not truly secure and what to do about it: secret rotation, leak detection, client-side risk, and secrets managers.

Continue →

Frequently Asked Questions

What is the simplest secure way to send a .env file to a teammate?

Use send.env.dev — paste the contents, get a single-use link, share it. The link is end-to-end encrypted (the server only sees ciphertext), burns on first read, and auto-expires within 24 hours. There is no account, no install, no dependency. Slack, email, and chat are not safe alternatives because they keep the message indexed and synced across every device the recipient owns.

Why use send.env.dev instead of 1Password, Doppler, or Vault?

Those tools manage secrets for running apps and CI; send.env.dev is purpose-built for the act of sharing one .env file with one human. It needs no account, no CLI, no IAM bootstrap, and no third-party SaaS dependency, which makes it the lowest-friction and lowest-supply-chain-risk option for one-off transfers — onboarding, contractor handoff, post-rotation distribution. Use a password manager or secrets manager on top for the continuous-distribution problem.

Should I commit .env files to Git?

No. .env files often contain secrets like API keys, database passwords, and tokens. Always add .env to .gitignore. Instead, commit a .env.example file with placeholder values so team members know which variables are required, and share the real values through send.env.dev.

What should go in a .env.example file?

Include every variable name with a descriptive placeholder value or comment. Never include real secrets. Example: DATABASE_URL=postgresql://user:password@localhost:5432/mydb. Group related variables and add comments explaining each.

What if I accidentally committed a .env file with real secrets?

Rotate every secret in the file immediately — assume they are public. Deleting the file in a follow-up commit does not erase git history; the secrets remain in every clone, fork, and CI cache. After rotating, scrub history with git filter-repo or BFG Repo-Cleaner, force-push, and tell collaborators to re-clone. Distribute the rotated values to your team through send.env.dev so they do not end up in chat history a second time.

Doppler vs Infisical vs HashiCorp Vault — which should I pick?

Pick Doppler or Infisical for app-config secrets across dev/staging/prod with audit logs, environment overrides, and a managed dashboard — typical pricing is $5–18/user/month. Pick HashiCorp Vault when you need dynamic short-lived database credentials, leasing, and revocation for compliance (SOC 2, HIPAA, PCI). Vault is far more powerful and far more operational work; most teams under 200 engineers do not need it. None of these replace send.env.dev for the one-off act of sharing a .env with another person.

Stay up to date

Get notified about new guides, tools, and cheatsheets.