Config vars and secrets
The environment your app runs with, why reading it back needs a scope of its own, and the two lists people confuse.
Config vars are the environment your app’s process starts with: database URLs, API keys, feature flags, anything that differs between your machine and production.
marina env set STRIPE_KEY=sk_live_… LOG_LEVEL=info The app restarts to pick them up, so setting a var is a deploy-sized event, not a live edit.
Build time is not run time
This is the distinction that costs people an afternoon.
| Set with | Available | |
|---|---|---|
| Config vars | marina env set | While your app runs |
[build.env] | marina.toml | While your app builds |
A frontend framework bakes its variables into the bundle during the build, so a VITE_API_URL set with marina env set is not there when npm run build runs and your app ships pointing at nothing. It goes in [build.env].
The reverse holds too: [build.env] lives in a committed file, so a real secret must never go there. Your database password belongs in marina env set, where it is never in your repo and never baked into what gets built.
Reading them back needs its own scope
marina env list
marina env pull Both need env:read, and no preset includes it. Not agent, not developer, not the one marina login gives your terminal by default. You ask for it deliberately:
marina tokens create ops --preset developer --scope env:read That looks awkward until you notice what it protects. Being able to configure an app and being able to read every secret it holds are different powers, and the second one is the whole account if a token leaks. Setting a var does not require reading the others, so an agent can do its job without ever being handed your Stripe key.
marina env set and unset need only env:write, which is why they work on an agent token.
Working from a file
marina env pull
marina env push pull writes the app’s vars to a local .env; push makes the app match that file. Push is the whole picture by default, so a var the app has and the file does not gets removed. When that would happen the command names what it is about to drop and refuses until you say --yes:
marina env push --yes When you only want to add or update, and the file is a fragment rather than the truth:
marina env push --merge --merge never removes anything, which makes it the safe one to reach for and the right one in a script.
In the dashboard, Paste .env on the app’s Settings tab reads the same file out of your clipboard and merges it the same way.
Seeding at create
Config vars can exist before the app’s first boot, which matters for anything that reads them at startup:
marina vessels create api --repo acme/api --env LOG_LEVEL=info --env-file .env.production --env wins over the file where both name the same variable.
What not to put in one
PORT. Marina sets it and routes to it. Overriding it does not move where traffic is sent, it just stops your app receiving any.
Anything you would rather not have in a restart loop. Every change restarts the app, so a var you flip often is better read from a database or a feature-flag service.
