DEV Community

hillel ilany freedman
hillel ilany freedman

Posted on

I built a CLI to safely share .env files across teams

Every developer has done it. You finish setting up a project, and then you need to share the .env file with your teammate. So you paste it into Slack. Or email it. Or worse, you commit it to git by accident.
None of these are good options. Slack logs are searchable. Emails get forwarded. Git history is forever.
So I built envsync — a CLI tool that encrypts your .env locally and pushes the encrypted blob to Firebase Firestore. Your teammates pull it down and decrypt it with a shared key. The secrets never touch git, and Firestore only ever holds an encrypted blob that is useless without the key.

How it works
The encryption is done with Fernet, a symmetric encryption scheme from the Python cryptography library. You generate a key once, share it with your team through a password manager, and that key is the only thing that can decrypt the env file.
The workflow looks like this:
bash# First time setup
envsync init
envsync keygen
bash# Push your .env to Firestore
envsync push --key YOUR_KEY
bash# Teammate pulls and decrypts
envsync pull --key YOUR_KEY
That is the entire workflow. No servers to manage, no complicated setup. Just Firebase as the transport layer and Fernet as the encryption layer.

Why Firebase
Firestore is free for small teams, requires zero infrastructure, and has SDKs for every language. For a tool like this it is a perfect fit — you only need one document per project to store the encrypted blob.
The data structure in Firestore is dead simple:
envsync/
my-project/
env: "gAAAAABh3x..."
updated_at: timestamp

Security model
This is the part I thought hardest about.
The key is intentionally kept out of the tool. envsync never stores it, never logs it, and never sends it anywhere. You generate it with envsync keygen, copy it once, and share it through a password manager like 1Password or Bitwarden.
Firestore holds the encrypted blob. The key lives only with the people who need it. Neither one alone is enough to read your secrets.
The one thing you need to be careful about is the Firebase service account JSON. That file gives full access to your Firebase project, so it must never be committed to git. envsync stores the path to it in ~/.envsync/config.toml on your machine — it never touches your repo.

Install it
bashpip install envsync-secure
The package is called envsync-secure on PyPI because envsync was already taken.

What I learned building this
This was my first CLI tool published to PyPI and the packaging side was honestly harder than the actual code. Getting pyproject.toml right, dealing with Python version conflicts, and figuring out PyPI authentication took longer than writing the encryption and Firebase layers combined.
The actual encryption code is about 15 lines. The CLI wiring with Typer was clean and fast. Firebase setup was straightforward once I had the service account JSON.
If you are thinking about building a CLI tool in Python, Typer is the way to go. It turns function signatures into CLI commands automatically and gives you rich help text and error messages for free.

What is next
I want to add a LocalVault backend for teams that do not want to use Firebase — just save the encrypted blob to a file on a shared network drive. The BaseVault abstraction is already in the code so it will be a clean addition.
I also want to add team management — right now the key sharing is manual. A future version could handle key rotation and access revocation.

Check it out on PyPI and let me know what you think. If you have ever pasted a .env into Slack you know why this exists.
GitHub: https://github.com/oh4-beep/envsync
PyPI: pypi.org/project/envsync-secure

Top comments (0)