Comparison
envGo is intentionally narrow. This page makes the trade-offs explicit so you can decide in 2 minutes whether it fits your project.
What envGo has
- Zero-dependency single binary —
CGO_ENABLED=0, standard library only,go vet/go testclean. No Node, no Python, no runtime to install. ~8 MB (7.7–8.5 MB across the six released targets; not UPX-packed). - Static server + secure proxy — serves your
index.htmland injects{VAR}server-side. The browser only sees placeholders andwindow.EnvLoaded[NAME]=true. - Scan-to-open on a phone —
--qrbinds every interface and prints a scannable QR of the LAN URL;--qr-format pngadds a PNG file for terminals that mangle block characters. - Two modes — Local (
/proxy+ per-process tokenX-EnvGo-Token, checked withHost+Origin+subtle.ConstantTimeCompare) and Public (/api/<name>fixed routes fromenvgo.routes.json). - Outbound allowlist — proxying is off until you pass
--allow host1,host2, so a misconfigured route cannot become an open relay. - Per-route gateway —
varsallow-set, per-routerate_limit(fixed-window), optional bearerauth, request shaping viaquery/headers/body, andscrub_responsethroughlogger.Redact. - DNS-rebinding defence — a closed allowlist of
Hostvalues built from the bound address, so a hostile domain resolving to127.0.0.1is still refused with 403. - Hot-reload —
internal/envstorepolls.envevery 1.5 s with no restart;/__envgo/reloadpushes an SSE event so an open page refreshes itself. - Dashboard (metadata only) —
GET /__envgo_dashboardshows variable names and the last 200 requests, never values. - Diagnostics —
GET /__env.jstypo detection (Levenshtein ≤3) with red banner, PHPecho getenvwarning, missingvarswarning at startup. - PHP — executes
.phpvia thephpbinary (CLI or-cgi) with.envinjected, 30 s timeout, header parsing. - TLS —
--tlsself-signed, and the certificate carries the LAN address so a phone scanning over HTTPS gets a matching name. - Scaffolding and deploy files —
envgo initwrites a project template;envgo deploygeneratesCaddyfile,nginx.confand aDockerfilefrom your config. - Self-update —
envgo run updatefetches the latest release and refuses to install anything whose SHA256 is not proven against the publishedSHA256SUMS. A mismatch always aborts, and so does being unable to reach the manifest;--skip-checksumis the explicit opt-out for proxies and air-gapped mirrors, and never covers a real mismatch. The verified binary is startup-tested with-hand swapped in with a same-directoryos.Rename. - Cross-platform —
make releasebuilds darwin/linux/windowsamd64+arm64as six plain binaries. - AI-friendly — one copy-paste prompt (
/envgo-agent-prompt.txt) that teaches any agent toenvgo -v→ auto-install →envgo init→envgo run dev.
What envGo does not have
Be explicit about this before you commit:
- No database, no sessions, no user auth. The token is per-process, not per-user. Any page on your own origin can fetch it.
- No auto-HTTPS.
--tlsis self-signed for dev. Production TLS is your reverse proxy (Caddy does Let’s Encrypt). - No unlimited abuse protection by default.
default_rate_limitis empty → unlimited until you set30/minetc. Rate limiting is also per-process and needstrust_proxy: truebehind a proxy. - No streaming scrub. SSE passthrough skips redaction to avoid buffering — an upstream that echoes a secret in a stream leaks it.
- No build step. envGo serves files as-is. It does not bundle, minify, or transpile JS.
- No secret rotation / vault. It reads a flat
.envfile. For Vault/AWS Secrets Manager, sync to.envyourself. - No multi-tenant isolation. One
.env, one gateway config per process. For per-user keys, you need a real backend. - No shared concurrency story. Rate limits and request history are per-process, so scaling out means scaling those out too.
If you need any of the above, envGo is the wrong tool — use Next.js/Nuxt API routes or a Worker.
Head-to-head
Scroll horizontally to see all columns →
| Area | envGo | Vite server.proxy / http-proxy-middleware | Next.js / Nuxt API routes | Caddy / nginx | Cloudflare Workers / Vercel Functions |
|---|---|---|---|---|---|
| Runtime | None — single Go binary | Node + node_modules | Node + framework | Caddy/nginx binary | Cloud account + wrangler/vercel |
| Secret stays server-side? | Yes — {VAR} substituted in Go (proxy.inject, gateway.inject) | Yes, but you write the handler yourself | Yes — process.env on server | Yes with header_up/templates, but manual | Yes — env.MY_SECRET in Worker |
| Leak via bundle? | No — browser gets booleans only | Risk if you use import.meta.env in client | Risk if you forget NEXT_PUBLIC_ prefix | No (static files) | No |
| Setup | envgo init → envgo run dev | vite.config.js proxy table + custom handler | pages/api/*.ts per endpoint | Caddyfile/nginx.conf + sub_filter | wrangler.toml + fetch handler |
| Proxy locked down by default | Yes — off until --allow host | Off unless you add a guard | Off unless you add a guard | Open by default | Per-route, you write it |
| Open it on your phone | Yes — --qr prints a scannable LAN QR | No | No | Manual | No |
Hot-reload .env | Yes (1.5 s poll) | Restart needed | Restart needed | Reload needed | Redeploy |
| Live-reload an open page | Yes — SSE at /__envgo/reload | HMR (full Vite) | HMR | No | No |
| Dashboard / history | Yes — /__envgo_dashboard names only | No | No | No | Cloud logs only |
| Typo detection | Yes — red banner + Levenshtein suggestion (server/serveEnvJS, server/detectPHPTypo) | No | No | No | No |
| Fixed public routes | Yes — /api/<name> with vars + rate_limit + auth | Manual per-route handler | Manual per-route handler | Manual handle /api/* | Manual export default { fetch } |
| Request shaping | Declarative — query, headers, body per route | Write a handler | Write a handler | rewrite/replace | Write a handler |
| Rate limiting | Per-route fixed-window, per-IP (ratelimit.Limiter) | You add express-rate-limit | You add middleware | rate_limit directive | KV / Durable Objects |
| Auth per route | Bearer matching {ENV_VAR} | You code it | next-auth etc. | forward_auth | You code it |
| PHP | Yes — php exec with .env env | No | No | php_fastcgi | No |
| TLS | Self-signed (--tls, LAN name included) or proxy | Dev via mkcert | Vercel auto | Caddy auto Let’s Encrypt | Cloud auto |
| Generate deploy files | Yes — envgo deploy writes Caddyfile, nginx.conf, Dockerfile | No | No | You write them | wrangler deploy |
| Update itself | Yes — envgo run update | npm update | npm update | Package manager | CLI redeploy |
| Binary / deploy size | ~8 MB single file | node_modules hundreds MB | Framework + build | ~15–40 MB | Bundle < few MB |
| Best for | Static HTML/vanilla JS + one API key, AI-generated sites, internal tools, no-build demos, “just open it on my phone” | SPA dev already on Vite | Full-stack React/Vue app | Static site behind existing Caddy/nginx | Edge, multi-region, KV/DB |
When to choose what
| You are… | Pick |
|---|---|
Beginner, designer, AI agent that just generated index.html and needs to call OpenAI without learning Node | envGo |
| Want to open the thing on your phone right now, with no tunnel account | envGo |
| Already building a SPA with Vite and comfortable writing a small proxy handler | Vite proxy |
| Building a full app with DB, auth, SSR | Next.js / Nuxt |
Already running Caddy/nginx in prod and want templates or header_up | Caddy/nginx |
| Need global edge, KV, or pay-per-request | Workers / Functions |
Bottom line
envGo is not a replacement for a backend. It is a bridge for the gap between “I have a static HTML file” and “I need one secret without learning a framework.” If that gap is your project, envGo is the shortest path. If you have already crossed that gap, stick with what you have.
Further reading: Threat Model, Configuration, How It Works, Sharing with your phone.