To share an env file with your team, never commit it to Git or paste it into chat. For a one-off laptop setup, send the contents as a one-time link that self-destructs after one view, with a passcode sent separately. For ongoing access, keep the variables in a secrets manager your team pulls from.
Key takeaways
- Keep .env out of Git with .gitignore and commit a .env.example with placeholder values instead.
- Use a one-time link for bootstrapping: one view, short expiry, passcode sent over a different channel.
- Use a secrets manager when many people or machines need the same values over time.
- Send development credentials to laptops, not production ones.
- If a .env file ever landed in chat history or a repo, rotate every secret in it.
What's the safest way to share an env file with your team?
It depends on whether you are solving a one-time problem or an ongoing one. Most teams have both.
The one-time problem: a new developer joins on Monday, clones the repo, runs the app and gets a wall of errors because DATABASE_URL and STRIPE_TEST_KEY are missing. Someone needs to get them a working .env today.
The ongoing problem: ten people and three CI pipelines need the same values, those values change, and you need to know who has access. That calls for a secrets manager, not a better way of passing files around.
If you only remember one rule, make it this: the file should never sit anywhere permanent that wasn't designed to hold secrets. That rules out Git, chat history, wikis, tickets and shared drives.
Why you should never commit .env to Git
A committed .env is copied to every clone, every fork, every CI runner and every backup of the repo. Deleting it in a later commit doesn't remove it from history. Anyone who can read the repo, now or in the future, can read the secrets.
Private repos don't fix this. Contractors get added, laptops get stolen, access tokens leak, and repos occasionally get made public by mistake.
Set this up once and you rarely have to think about it again:
echo ".env" >> .gitignore
echo ".env.*" >> .gitignore
echo "!.env.example" >> .gitignore
git add .gitignore .env.example
git commit -m "Ignore env files, add example"Your .env.example lists every variable the app needs, with fake or empty values and a comment saying where to get the real one. It documents the shape of the config without exposing anything.
If a real .env was already committed, rewriting history is worth doing, but it is not enough on its own. Treat every value in that file as exposed and rotate it. The OWASP Secrets Management Cheat Sheet covers rotation and detection in more depth.
How to share a .env file securely with a one-time link
For getting one person's laptop running, a one-time link is hard to beat. The contents exist in a readable form for as long as it takes your teammate to open it, then the link stops working. Nothing lingers in Slack search or someone's inbox.
Here is the process with SecureNotes:
- Prepare the file. Start from
.env.exampleand fill in development or staging values only. Remove anything the person doesn't need for their role. - Paste the contents. Go to SecureNotes and create a self-destructing note. Paste the full file. Notes hold up to 10,000 characters, which covers most env files.
- Choose when it self-destructs. Pick 1 view and 1 hour or 24 hours, whichever comes first. One view means you'll know if anyone else got there first.
- Add a passcode. Set a short passcode the recipient must enter to open the note. This protects you if the link ends up in the wrong place.
- Turn on the read notification. SecureNotes can email you when the note is opened, so you know it arrived.
- Send the link. Drop it in a direct message, or let SecureNotes email it to the new hire's work address.
- Send the passcode another way. Say it on your onboarding call, or text it. Never in the same thread as the link.
- Confirm and clean up. Ask them to save it straight to
.envin the project root and runchmod 600 .env. If they say the link was already used when they clicked it, rotate the secrets.
Each note is encrypted with AES-256 using its own random key before it is stored, and the link stops working once the view limit or time limit is reached. For what a one-time link does and doesn't protect against, see one-time links vs password vaults.
The env file is usually one of several things a new developer needs in week one. Onboarding a new hire: the first ten secrets they actually need covers the rest.
How to send an env file from the command line with the SecureNotes API
If you onboard people often, or you want this baked into a setup script, the free SecureNotes REST API lets you create notes without opening a browser.
The pattern below reads the file directly, builds the JSON body with jq and pipes it to curl. The secret never appears as a command-line argument, so it doesn't end up in your shell history or the process list.
# 1. Check the file fits in a single note (10,000 character limit)
wc -m .env.dev
# 2. Set the endpoint from the API docs
export SECURENOTES_ENDPOINT="<endpoint from the API docs>"
# 3. Build the request from the file and create the note
jq -Rs '{content: ., max_views: 1, expires_in: "1h"}' .env.dev \
| curl -s -X POST "$SECURENOTES_ENDPOINT" \
-H "Content-Type: application/json" \
--data @-The field names here are placeholders to show the shape of the request. Check the API docs for the exact endpoint, parameter names for views, expiry and passcode, and the format of the response that contains the link.
A few things to get right when scripting this:
- Read from a file or stdin, not a variable you typed.
SECRET=abc123 ./script.shlands in history. - Print only the link. Pipe the response through
jqto extract the URL so the script output doesn't echo anything else. - Keep the defaults strict. Hard-code one view and a short expiry so nobody accidentally creates a 30-day, 10-view link.
- Don't log the request body in CI or wrapper scripts.
You can wrap this in a small share-env function in your dotfiles and hand it to every tech lead on the team.
When should your team use a secrets manager instead?
One-time links are for handoffs. They don't give you access control, audit logs, versioning or automatic distribution. Once you need any of those, it's time for a secrets manager such as HashiCorp Vault, AWS Secrets Manager, Google Secret Manager, Doppler, Infisical or a team password manager with CLI support.
Move to a secrets manager when:
- More than a handful of people need the same values.
- CI/CD pipelines or servers need the secrets, not just humans.
- Values change often and you're tired of re-sending files.
- You need to revoke one person's access without rotating everything.
- Someone, such as an auditor or a customer, asks who can see production credentials.
A common setup: developers authenticate to the secrets manager with their SSO login, then run a CLI command that writes a local .env or injects variables at runtime. The one-time link then shrinks to a single job, getting a new hire the bootstrap credential for the secrets manager itself if SSO doesn't cover it.
Slack, email, repo or one-time link: how the options compare
| Method | Where the secret ends up | Good for | Main risk |
|---|---|---|---|
| Committed to Git | Every clone, fork and backup, forever | Nothing | Exposure to anyone with repo access, now or later |
| Slack or Teams message | Searchable chat history and workspace exports | Nothing secret | Lingers for years, visible to admins and integrations |
| Email attachment | Both mailboxes, server copies, backups | Nothing secret | Forwarding, compromised mailboxes, retention |
| Shared drive or wiki page | A document with shifting permissions | Non-secret setup docs | Access sprawl, copies, version history |
| One-time link | Stored encrypted until viewed or expired, then gone | Bootstrapping one laptop, one-off handoffs | Recipient copies it somewhere unsafe; no ongoing access control |
| Secrets manager | A purpose-built store with access control | Ongoing team and CI access | Setup effort; misconfigured permissions |
If you're handing keys to someone outside the company, the trade-offs shift a little. Sharing API keys with a contractor walks through that case.
Common mistakes when you send secrets to a developer
Sending production credentials to a laptop
Most developers don't need production database passwords to write code. Give them dev or staging values and let production secrets live only in your deployment environment.
Putting the link and passcode in the same place
If both sit in one Slack DM, anyone who reads that DM has everything. Split them across channels: link in chat, passcode on a call.
Choosing long expiry and many views
A 30-day, 10-view link is a semi-permanent secret with extra steps. For an env file, one view and a short window is almost always right.
Ignoring a link that was already opened
Some chat tools fetch links to build previews, and links get forwarded. If your teammate says the note was gone before they opened it, assume someone else saw it and rotate the values.
The recipient saving it somewhere worse
A one-time link can't stop someone pasting the contents into a notes app, a personal email or an AI chat. Tell people where the file goes and why.
Forgetting to rotate when people leave
Every key on a departing developer's laptop is still valid until you change it. Keep a list of what was shared with whom so offboarding is a checklist, not guesswork.
Letting .env.example drift
When the example file is out of date, people fill the gaps by asking in public channels, and secrets end up in chat anyway. Update it in the same pull request that adds a new variable.
Frequently asked questions
Can I share a .env file over Slack if I delete the message afterwards?
Deleting helps less than you'd think. The file may already be in notifications, workspace exports, integrations or the recipient's downloads before you delete it, and some workspaces retain deleted content for admins. If you already sent a .env over Slack, delete it and rotate the secrets. Next time, send a one-time link and keep the passcode off Slack.
Is it OK to keep .env files in a private Git repository?
No. Private repos still get cloned to many laptops, mirrored to CI, backed up and shared with contractors, and their access lists change over time. Secrets in history stay readable to anyone who ever gains access. Commit a .env.example with placeholders and store real values in a secrets manager or hand them over individually.
What should go in a .env.example file?
Every variable the app reads, with a fake, empty or obviously local value, plus a short comment explaining what it is and where to get the real one. For example, STRIPE_SECRET_KEY= followed by a note pointing to the secrets manager path. Non-sensitive defaults like PORT=3000 can stay as real values.
What if my .env file is longer than 10,000 characters?
A SecureNotes note holds up to 10,000 characters, so you can split a large file across two notes, each with its own passcode. But a file that size usually contains far more than one developer needs, and it's a strong signal your team has outgrown file handoffs. Trim it to the essentials or move to a secrets manager.
How do I remove a .env file that was committed to Git?
Remove it from tracking with git rm --cached .env, add it to .gitignore, then rewrite history with a tool like git filter-repo and force-push. Ask collaborators to re-clone. Most importantly, rotate every secret the file contained, because rewriting history can't recall copies that already exist in clones, forks or CI caches.