Envvars is a spreadsheet for your .env files. It gives you one grid to hold every environment — Local, Staging, Production, or however your team names them — as columns, and every variable as a row, so you can see at a glance what's set, what's missing, and what's different between environments.
Everything runs entirely in your browser. There is no backend, no database, and no API call that carries your values off the page — state is kept in localStorage on the machine you're using. That makes Envvars a good fit for handling real secrets and config internally: nothing is transmitted or stored anywhere but the tab you're looking at.
Copy-pasting values between .env files, Slack messages, and password managers is error-prone — it's easy to miss a variable in staging, ship a stale API_URL, or lose track of which environment actually has FEATURE_FLAG_X turned on. Envvars turns that into a single sortable, diffable table with import/export built in, instead of juggling several text files by hand.
- Spreadsheet-style grid — variables as rows, environments as columns, with spreadsheet-style column letters (A, B, C…) and sticky headers/row numbers.
- Missing-value detection — a cell is highlighted red when a variable is set in at least one environment but missing in another, so gaps are obvious before they cause an incident.
- Duplicate-name warnings — flags variables accidentally defined twice.
- Environments as columns — add, rename, remove, resize, and drag-and-drop to reorder environments.
- Sorting — sort variables A→Z or Z→A by name.
- Smart value styling — booleans and URLs are colored and, for URLs, clickable.
- Import — paste or upload a
.envor JSON file; format is auto-detected. Import into an existing environment or create a new one on the fly. - Export — export a single environment as
.envor JSON, or export multiple environments at once as CSV. Copy to clipboard or download. - Local persistence — your sheet is saved to
localStorageautomatically and restored on your next visit. A "Reset" button restores the sample data. - No account, no server round-trip — the entire app is client-rendered state; nothing you type is sent anywhere.
- TanStack Start (React 19, file-based routing via TanStack Router)
- Tailwind CSS v4
- dnd-kit for drag-and-drop column reordering
- TanStack Virtual for row virtualization
- Vite + Cloudflare Vite plugin for building/deploying to Cloudflare Workers
- Biome for linting/formatting, Vitest for tests
This project uses pnpm. Install dependencies and start the dev server:
pnpm install
pnpm devThe app runs at http://localhost:3000.
Other scripts:
pnpm build # production build (client + SSR bundles)
pnpm preview # serve the production build locally
pnpm test # run the Vitest suite
pnpm check # Biome lint + format checkEnvvars ships pre-configured to deploy to Cloudflare Workers (see wrangler.jsonc). Because the app has no backend of its own, "deploying" just means putting the static/SSR bundle somewhere your team can reach it — the guides below cover the two most common setups.
- Install Wrangler if you don't have it:
npm install -g wrangler - Authenticate once per machine:
wrangler login - Build and deploy:
(or
pnpm build wrangler deploy
pnpm run deploy, which runs both steps — note the explicitrun, sincepnpm deployalone invokes pnpm's own built-in deploy command instead of this script) - Wrangler prints the
*.workers.devURL for the deployment. To use a real internal domain, add a custom domain route inwrangler.jsoncor the Cloudflare dashboard.
Restricting it to your team. Envvars has no login screen by design — access control is expected to live in front of it. If your organization is on Cloudflare, the simplest way to make this an internal tool is Cloudflare Access:
- In the Cloudflare Zero Trust dashboard, create an Access application pointed at your Workers route.
- Add a policy that allows only your company's identity provider (Google Workspace, Okta, Entra ID, GitHub org, etc.) or a specific list of emails.
- Once enabled, anyone hitting the URL is prompted to authenticate before the app ever loads — no code changes required.
If your team isn't on Cloudflare, you can run the built app as a plain Node process behind whatever internal access control you already use (VPN, reverse proxy with SSO, IP allowlist, etc.):
pnpm build
pnpm preview --host 0.0.0.0 --port 4173Run that under a process manager (pm2, systemd, a Docker container, etc.) and put it behind your internal reverse proxy (nginx, Caddy, Cloudflare Tunnel, Tailscale) so it's only reachable on your private network. Since there's no database or environment variable configuration required by the app itself, the only thing to manage is the process staying up.
- Envvars stores everything in the browser's
localStorage, scoped per browser/device — it is not synced between teammates or devices. Treat it as a personal scratchpad for organizing values before distributing them (e.g. via your secrets manager), not a shared source of truth. - Because state never leaves the browser, there's nothing to back up or secure server-side beyond restricting who can load the page at all (see the access-control notes above).
- Clearing browser storage (or using a different browser/device) will reset the sheet to the sample data.
src/
routes/
__root.tsx # document shell, SEO/Open Graph metadata
index.tsx # the single page — renders EnvVarSheet
components/
EnvVarSheet.tsx # the grid: state, persistence, sorting, DnD
ImportVariablesModal.tsx # .env / JSON import
ExportVariablesModal.tsx # .env / JSON / CSV export
Routes are file-based (via TanStack Router) — add a new file under src/routes to add a page.
