Project Structure
envgo init is the scaffolding command. It writes a runnable project in one step so a new dev can go from mkdir myapp to envgo run dev without reading the source. This page documents exactly what is created, what each file contains and does, and every key that can go in .env according to main.go, envstore and gateway.
What the command does
Source: main.go:doInit — no network, no dependencies, five os.WriteFile calls.
# In the current directoryenvgo init
# In a new subdirectory (fails if directory already exists)envgo init -name myapp# → myapp/.env, myapp/.env.example, myapp/index.html, myapp/.gitignore, myapp/README.mdBehaviour:
- If
-nameis given andmyapp/exists,initexits withdirectory already exists— it never merges. - Otherwise it overwrites
index.html,README.md,.gitignore,.env,.env.examplein the target without asking. Back up first. - No flag is needed for
envgo run devafterwards —.envalready holdsHOST/PORTdefaults.
Folder after init
myapp/├── .env # 0600 — your real secrets (never commit)├── .env.example # 0644 — safe template to commit├── index.html # 0644 — minimal page with presence check├── .gitignore # 0644 — ignores .env + keys└── README.md # 0644 — quick-start notes# optional, you add later:├── envgo.routes.json # public-mode gateway config└── deploy/ # generated by envgo deploy0600 vs 0644: only .env is 0600 (owner read/write) so other users on the same machine cannot read it. Everything else is 0644.
File by file
.env — the only secret store
Default content (main.go:envContent):
# envGo project# Copy to .env and fill in real values. NEVER commit the real .env.
MY_SECRET=change-meHOST=127.0.0.1PORT=8080# MODE_PUBLIC=false # true/public = public mode (needs envgo.routes.json), false/local = local mode# CONFIG=envgo.routes.json # optional: explicit routes file (overrides MODE_PUBLIC)| Line | Kind | What it does |
|---|---|---|
MY_SECRET | placeholder secret | Example. Replace with your real key. Any name matching [A-Za-z_][A-Za-z0-9_]* can be used as {MY_SECRET} in JS or <div id="MY_SECRET">. |
HOST | infra, not secret | Where envgo run binds. 127.0.0.1 = local only. 0.0.0.0 = LAN. Only read by envgo run / run dev when --host is default. Not redacted in logs. |
PORT | infra, not secret | Port envgo run listens on. 8080 → http://127.0.0.1:8080/. PORT=:3000 also works. Not redacted. |
# MODE_PUBLIC | infra, not secret | Commented false by default = local mode. Uncomment true/public/1 to enable public mode without --config flag. Aliases: MODE, PUBLIC_MODE, ENVGO_MODE. Values true/1/yes/public = public, false/0/no/local = local. Flag --config always wins. See CLI Commands. |
# CONFIG | infra, not secret | Commented by default. Explicit routes path (envgo.routes.json, custom/myroutes.json). Aliases: ENVGO_CONFIG, ROUTES, ROUTES_PATH, CONFIG_PATH. Wins over MODE_PUBLIC. Relative paths resolved against .env dir and --dir. |
HOST/PORT/MODE_PUBLIC/CONFIGare never treated as secrets — they appear in logs and are ignored in.env.examplesync and logger redaction (envstore.go:filtered).
What else can you put in .env? Anything you want — every other key is a secret:
MY_SECRET=change-meOPENAI_API_KEY=sk-live-abc123GEMINI_API_KEY=secret2STRIPE_KEY=sk_test_...DATABASE_URL=postgres://...# any non-empty key is accepted, but only [A-Za-z_][A-Za-z0-9_]* can be used as {PLACEHOLDER}Rules (envconfig):
- Blank lines and whole-line
#comments ignored. export KEY=valaccepted (prefix stripped).- Missing
=or empty key (=val) → load fails with line number. - Quotes: matching
"or'around the value is stripped. ${VAR}expansion:BASE=https://${HOST}/v1resolvesHOSTfrom earlier lines, then OS env.- Spaces inside value are preserved.
Hot reload: edit .env while running — envstore.Watch polls mtime/size every 1.5s and reloads without restart (main.go:store.Watch). Removing a key really removes it.
.env.example — safe to commit
Same content as .env (0644), but values are placeholders. Commit this so teammates know which keys to fill. main.go:checkEnvExampleSync warns if names diverge, never values.
MY_SECRET=change-meHOST=127.0.0.1PORT=8080# MODE_PUBLIC=false# CONFIG=envgo.routes.jsonindex.html — presence check, not the secret
Default (main.go:htmlContent):
<!DOCTYPE html><html><head><title>myapp — envGo</title></head><body><h1>Hello from envGo!</h1><div id="MY_SECRET"></div><script src="/__env.js"></script></body></html><div id="MY_SECRET">is not the value./__env.jsfetchesGET /__envgo_dashboard/data(names only) and replaces it with✓ MY_SECRET — Success (value hidden)or✗ ID not match Key+ red banner (Levenshtein suggestion ≤3). Works for any<div id="YOUR_KEY">.- Skipped ids:
out,chatBtn,btn,prompt,askBtn— avoididon non-variable elements. HOST/PORT/MODE_PUBLICdo not need an element — they are not secrets.
.gitignore — prevents accidental commit
.env*.key*.secret.env is always ignored. Add envgo.routes.json there if it holds internal URLs you prefer not to commit (optional).
README.md — local quick-start
Generated README.md repeats envgo run dev, envgo -h, --tls, --config, and deploy. It is a stub — not a source of truth, the docs at envgo.dev are.
Complete .env reference (from Go source)
| Key | Type | Used by | Flag that overrides | Secrets? |
|---|---|---|---|---|
MY_SECRET, OPENAI_API_KEY, … | any secret | {NAME} in proxy/gateway HOST check, dashboard | — | yes — redacted in logs (logger.Redact) |
HOST / host | infra | envgo run only, when --host is default 127.0.0.1 | --host | no |
PORT / port | infra | envgo run only, when --port is default 8080 | --port / -p | no |
MODE_PUBLIC / PUBLIC_MODE / ENVGO_MODE / MODE | infra boolean | startup mode switch when --config absent | --config/-c | no |
CONFIG / ENVGO_CONFIG / ROUTES / ROUTES_PATH / CONFIG_PATH | infra path | explicit gateway file when --config absent | --config/-c | no |
Precedence: flag --config > CONFIG keys > MODE_PUBLIC keys > default local. HOST/PORT only apply to envgo run; plain envgo --port ignores them intentionally (common systemd pitfall).
Typical edits for a new dev
MY_SECRET=real-value-from-teammateOPENAI_API_KEY=sk-...HOST=127.0.0.1PORT=3000# keep local for dev, flip to true when testing public gateway:# MODE_PUBLIC=trueenvgo run dev -a api.openai.com # local with allowlist# orMODE_PUBLIC=true envgo run dev # public via .env, no flagenvgo --config envgo.routes.json --allow api.openai.com # explicitWhat to commit
git add .env.example index.html .gitignore README.md# never: git add .envSee also: Environment Variables, CLI Commands, How It Works.