Skip to content

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 test clean. 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.html and injects {VAR} server-side. The browser only sees placeholders and window.EnvLoaded[NAME]=true.
  • Scan-to-open on a phone — --qr binds every interface and prints a scannable QR of the LAN URL; --qr-format png adds a PNG file for terminals that mangle block characters.
  • Two modes — Local (/proxy + per-process token X-EnvGo-Token, checked with Host + Origin + subtle.ConstantTimeCompare) and Public (/api/<name> fixed routes from envgo.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 — vars allow-set, per-route rate_limit (fixed-window), optional bearer auth, request shaping via query/headers/body, and scrub_response through logger.Redact.
  • DNS-rebinding defence — a closed allowlist of Host values built from the bound address, so a hostile domain resolving to 127.0.0.1 is still refused with 403.
  • Hot-reload — internal/envstore polls .env every 1.5 s with no restart; /__envgo/reload pushes an SSE event so an open page refreshes itself.
  • Dashboard (metadata only) — GET /__envgo_dashboard shows variable names and the last 200 requests, never values.
  • Diagnostics — GET /__env.js typo detection (Levenshtein ≤3) with red banner, PHP echo getenv warning, missing vars warning at startup.
  • PHP — executes .php via the php binary (CLI or -cgi) with .env injected, 30 s timeout, header parsing.
  • TLS — --tls self-signed, and the certificate carries the LAN address so a phone scanning over HTTPS gets a matching name.
  • Scaffolding and deploy files — envgo init writes a project template; envgo deploy generates Caddyfile, nginx.conf and a Dockerfile from your config.
  • Self-update — envgo run update fetches the latest release and refuses to install anything whose SHA256 is not proven against the published SHA256SUMS. A mismatch always aborts, and so does being unable to reach the manifest; --skip-checksum is the explicit opt-out for proxies and air-gapped mirrors, and never covers a real mismatch. The verified binary is startup-tested with -h and swapped in with a same-directory os.Rename.
  • Cross-platform — make release builds darwin/linux/windows amd64+arm64 as six plain binaries.
  • AI-friendly — one copy-paste prompt (/envgo-agent-prompt.txt) that teaches any agent to envgo -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. --tls is self-signed for dev. Production TLS is your reverse proxy (Caddy does Let’s Encrypt).
  • No unlimited abuse protection by default. default_rate_limit is empty → unlimited until you set 30/min etc. Rate limiting is also per-process and needs trust_proxy: true behind 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 .env file. For Vault/AWS Secrets Manager, sync to .env yourself.
  • 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 →

AreaenvGoVite server.proxy / http-proxy-middlewareNext.js / Nuxt API routesCaddy / nginxCloudflare Workers / Vercel Functions
RuntimeNone — single Go binaryNode + node_modulesNode + frameworkCaddy/nginx binaryCloud account + wrangler/vercel
Secret stays server-side?Yes — {VAR} substituted in Go (proxy.inject, gateway.inject)Yes, but you write the handler yourselfYes — process.env on serverYes with header_up/templates, but manualYes — env.MY_SECRET in Worker
Leak via bundle?No — browser gets booleans onlyRisk if you use import.meta.env in clientRisk if you forget NEXT_PUBLIC_ prefixNo (static files)No
Setupenvgo init → envgo run devvite.config.js proxy table + custom handlerpages/api/*.ts per endpointCaddyfile/nginx.conf + sub_filterwrangler.toml + fetch handler
Proxy locked down by defaultYes — off until --allow hostOff unless you add a guardOff unless you add a guardOpen by defaultPer-route, you write it
Open it on your phoneYes — --qr prints a scannable LAN QRNoNoManualNo
Hot-reload .envYes (1.5 s poll)Restart neededRestart neededReload neededRedeploy
Live-reload an open pageYes — SSE at /__envgo/reloadHMR (full Vite)HMRNoNo
Dashboard / historyYes — /__envgo_dashboard names onlyNoNoNoCloud logs only
Typo detectionYes — red banner + Levenshtein suggestion (server/serveEnvJS, server/detectPHPTypo)NoNoNoNo
Fixed public routesYes — /api/<name> with vars + rate_limit + authManual per-route handlerManual per-route handlerManual handle /api/*Manual export default { fetch }
Request shapingDeclarative — query, headers, body per routeWrite a handlerWrite a handlerrewrite/replaceWrite a handler
Rate limitingPer-route fixed-window, per-IP (ratelimit.Limiter)You add express-rate-limitYou add middlewarerate_limit directiveKV / Durable Objects
Auth per routeBearer matching {ENV_VAR}You code itnext-auth etc.forward_authYou code it
PHPYes — php exec with .env envNoNophp_fastcgiNo
TLSSelf-signed (--tls, LAN name included) or proxyDev via mkcertVercel autoCaddy auto Let’s EncryptCloud auto
Generate deploy filesYes — envgo deploy writes Caddyfile, nginx.conf, DockerfileNoNoYou write themwrangler deploy
Update itselfYes — envgo run updatenpm updatenpm updatePackage managerCLI redeploy
Binary / deploy size~8 MB single filenode_modules hundreds MBFramework + build~15–40 MBBundle < few MB
Best forStatic HTML/vanilla JS + one API key, AI-generated sites, internal tools, no-build demos, “just open it on my phone”SPA dev already on ViteFull-stack React/Vue appStatic site behind existing Caddy/nginxEdge, 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 NodeenvGo
Want to open the thing on your phone right now, with no tunnel accountenvGo
Already building a SPA with Vite and comfortable writing a small proxy handlerVite proxy
Building a full app with DB, auth, SSRNext.js / Nuxt
Already running Caddy/nginx in prod and want templates or header_upCaddy/nginx
Need global edge, KV, or pay-per-requestWorkers / 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.