Environment variables
Set a variable on an App and every Function in that App reads it. Variables belong to the App rather than to any one Function, so a key you set today is there for the Function you add next week.
We read them when a Function runs, not when you deploy. Set a value now and the next request has it. No build runs and no version is made. That is also why rolling a Function back to last week’s code does not take last week’s API key with it.
Set one
Section titled “Set one”npx wawesome env set GREETING hello
[wawesome] ✅ Set variable 'GREETING' on app 'demo'.
The App comes from wawesome-function.json in the current directory. None of these commands take
--app, so you run them from the project, or you use the dashboard.
Your handler reads the value off process.env:
export default {
async fetch(): Promise<Response> {
return Response.json({ message: process.env.GREETING });
},
};
Your Function does not run on Node, and the engine underneath has no process at all. We install
process.env before your module is evaluated, so the line above works even though the rest of
process is still missing. A key nobody set reads as undefined rather than throwing.
List them
Section titled “List them”npx wawesome env list
📋 Environment variables for 'demo'
KEY | VALUE | SECRET
------------------|- ---------------- |-------
GREETING | hello | false
STRIPE_SECRET_KEY | ****4242 | true
SUPPORT_EMAIL | support@hello.co | false
A readable variable prints in full. A secret prints as a mask of its last four characters, and only
when the value is longer than eight. Anything shorter comes back as **** and nothing else, because
four characters of a six-character value is most of it. Those four characters let you tell a live
Stripe key from a test one without reading either.
An App with nothing on it prints one line instead of a table:
[wawesome] No environment variables set for app 'demo'.
Delete one
Section titled “Delete one”npx wawesome env rm GREETING
[wawesome] ✅ Deleted variable 'GREETING' from app 'demo'.
The next invocation reads undefined. A key that was not there to begin with is an error, so a typo
does not report success:
[wawesome] Error: Variable 'GREETNIG' not found on app 'demo'.
Secrets nothing reads back
Section titled “Secrets nothing reads back”--secret stores the value write-only:
npx wawesome env set STRIPE_SECRET_KEY sk_live_51NxAbCdEfGh4242 --secret
[wawesome] ✅ Set secret variable 'STRIPE_SECRET_KEY' on app 'demo'.
🔒 Secret Notice:
• Encrypted at rest using AES-256
• This value can't be viewed again after you save it — only updated or deleted
• Only decrypted at the moment your function runs — never returned by the CLI, dashboard, or API after creation.
That notice comes from the gateway, not from the CLI, so it says what we do rather than what a client believes. The value is encrypted under a key belonging to that one App. A running Function is the only thing we ever hand it back to. The response to the write above is already masked, and so are the listing, the dashboard and the API. No flag reveals it.
--secret describes the write rather than the key. Setting the same key again without the flag
stores the new value readable, so keep the flag on every write of a value that should stay
write-only.
When you have lost one
Section titled “When you have lost one”Your Function has not lost it. The copy we hold still runs, and goes on running until you replace it. What you lost is your own copy, and that is the one to replace.
Go back to whoever issued the value and have them issue another. Then set it again under the same
key. env set on a key that already exists overwrites it, and the request after that carries the new
value. There is no step where we hand the old one back.
Where a value is visible
Section titled “Where a value is visible”env list shows every readable value in full to anyone who can run it against the App. The dashboard
shows the same thing under the Secrets tab on the App’s page, split into Secrets and
Environment Variables.
An agent holding write:env can set a variable over MCP. The value travels through the
conversation, and through whatever the chat product keeps of it. That is fine for a feature flag and
wrong for an API key. Type a real secret in at the dashboard yourself.
An agent holding read:env can list an App’s variables over MCP. It sees every key and when it was
set, and the value of each plain variable. It never sees any part of a secret’s value, not even the last
characters the dashboard shows.
A template asks for what it needs
Section titled “A template asks for what it needs”A template declares the variables its code reads. It ships no .env.example and no placeholder to
find and replace. npx wawesome init --template <name> asks you for each one before it deploys,
rather than after the first request fails:
[wawesome] This template needs a few values before it can run.
STRIPE_WEBHOOK_SECRET (required, stored write-only)
Signing secret for this webhook endpoint. Every request is rejected unless it carries a signature made with it.
Where to find it: Stripe Dashboard → Developers → Webhooks → your endpoint → "Signing secret" → Reveal. It starts with whsec_.
STRIPE_WEBHOOK_SECRET?:
The description and the Where to find it line are the template’s own words. That is how the CLI
can point you at a screen in somebody else’s dashboard.
Press enter and it moves on. Blank is the right answer more often than it sounds. A Stripe webhook secret does not exist until the endpoint does, and you create that endpoint with the URL this command is about to print. You get the command to run once the value exists:
[wawesome] STRIPE_WEBHOOK_SECRET left blank. Set it with: wawesome env set STRIPE_WEBHOOK_SECRET <value> --secret
A value you did type is stored before the deploy, under the flag the template declared for it:
[wawesome] ✅ Stored OPENAI_API_KEY (secret).
[wawesome] ✅ Enabled outbound calls to 'openai'.
Outbound calls
Section titled “Outbound calls”A variable holding somebody’s API address does not make the call to it allowed. An App reaches the
providers it subscribes to and the hosts on its allowlist. Both live under Egress on the App’s page
in the dashboard. init --template subscribes the App to the
providers a template declared, which is the Enabled outbound calls line above. For a variable the
template marks as naming a host, it also adds that host to the allowlist, and so does a later
env set on that variable. Outbound
calls is the page for the rest of it.