Set, unset, list, encryption
Env vars are encrypted at rest (AES-256-GCM) and injected at container startup. Changes take effect on the next deploy — run percher publish to apply immediately.
bunx percher env set STRIPE_KEY=sk_live_... bunx percher env list # values are masked bunx percher env unset STRIPE_KEY
Build-time exposure: by default env vars are only available at runtime, which is correct for secrets but breaks frameworks like Vite/Next/Astro/Expo that bake *_PUBLIC_* values into the static bundle at build time. Opt in per-key via [build] pass_env in percher.toml:
# percher.toml [build] pass_env = [ "NEXT_PUBLIC_API_URL", "VITE_POCKETBASE_URL", "EXPO_PUBLIC_API_URL", ] # values still come from the env store, not the TOML bunx percher env set NEXT_PUBLIC_API_URL=https://api.example.com
For Dockerfile-based projects (runtime = "docker") the listed keys are forwarded as --build-arg; declare ARG NEXT_PUBLIC_API_URL in your Dockerfile to read them.
Outbound HTTPS (calling external APIs from your app): Apps run on an internal Docker network and reach the public internet through a forward HTTP proxy that Percher injects automatically:
HTTP_PROXY=http://egress-proxy:8888 HTTPS_PROXY=http://egress-proxy:8888 NO_PROXY=localhost,127.0.0.1,.local NODE_USE_ENV_PROXY=1
Bun and Node 24+ use the proxy automatically — fetch("https://api.exa.ai/...") just works. Python (requests/httpx/urllib) and Go (http.DefaultTransport) also honor HTTPS_PROXY natively. For Node 22 and earlier wire up undici manually at app startup:
import { ProxyAgent, setGlobalDispatcher } from "undici";
if (process.env.HTTPS_PROXY) {
setGlobalDispatcher(new ProxyAgent(process.env.HTTPS_PROXY));
}Direct outbound is blocked by design — apps can't scan internal hosts or hit cloud metadata. If a smoke probe sees ENETUNREACH on 1.1.1.1:443, that's the symptom of the runtime not using the proxy, not a missing-egress problem.