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.
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)
.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:
# 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:
# Environment files — never commit secrets
.env
.env.local
.env.*.local
.env.production
.env.stagingHand-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.
# 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=infoValidate 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.
# 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"# 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' > .envDoppler / 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.
# 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# 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 > .envAWS 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.
# 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# 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 textHashiCorp 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.
# 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-roleEncrypted 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.
# 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# 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 > .envHow do these approaches compare?
| Approach | Security | Best for | Cost | Setup effort |
|---|---|---|---|---|
| send.env.dev ★ | Very high (E2E + zero-knowledge) | One-off .env handoffs, onboarding, rotation | Free | None — no install, no account |
| 1Password / Bitwarden | High | 1-20 developers | $3-8/user/mo | Low |
| Doppler / Infisical | High | 5-200 developers | Free tier, then $5-18/user/mo | Low |
| AWS Secrets Manager | Very high | AWS-native teams | $0.40/secret/mo + API calls | Medium |
| AWS Parameter Store | High | AWS-native teams | Free (standard), $0.05/param/mo (advanced) | Medium |
| HashiCorp Vault | Very high | Enterprise / compliance | Free (OSS), $1.58/hr (HCP) | High |
| git-crypt / SOPS | Medium-High | Small teams, monorepos | Free | Medium |
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-hereorsk_test_replace_memake 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=infoorPORT=3000should 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.examplekeys 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:
# 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
- send.env.dev — end-to-end encrypted, burn-on-first-read sharing built specifically for
.envpayloads. Zero dependencies, EU-hosted, no account. - 1Password CLI — secret references — official syntax for
op://references andop runinjection. - Bitwarden CLI documentation — full command reference for
bw, including session unlocking and item retrieval. - Doppler documentation — managed secrets platform with environment scoping, audit logs, and CLI injection.
- Infisical documentation — open-source alternative with self-hosted and cloud options.
- HashiCorp Vault documentation — dynamic secrets, leasing, revocation, and audit trails for compliance-grade workloads.
- SOPS (getsops/sops) — encrypts individual values inside YAML/JSON/env files so diffs stay readable in git.
- git-crypt — transparent file-level encryption on push, decryption on checkout, keyed by GPG.
Try the tools that prevent these leaks
env.dev tool
.gitignore generator
Composes language, framework, and OS templates with credential-leak ignores baked in. Stop .env from ever reaching a commit.
External · Recommended
send.env.dev
End-to-end encrypted, burn-on-first-read links for handing a working .env to a teammate. EU-hosted, zero dependencies, no account.