Guides
Environment variables and secrets
What Launchpad injects, how to add your own, and how the three environments differ.
Your app reads its database URL, API keys and settings from environment variables. Launchpad fills in the ones that come from services it created, and you add the rest.
What Launchpad injects
Each service contributes variables under the names frameworks expect, for example DATABASE_URL
from the database and RESEND_API_KEY from email. The full list is in
Providers and credentials, and every deploy prints the names it injected.
You never paste these yourself, and they're updated when something changes, such as a rotated key.
Adding your own
In the console, open a project and use Environment variables. From the terminal:
launchpad secrets set STRIPE_SECRET_KEY=sk_live_… --env production
printf %s "$TOKEN" | launchpad secrets set GITHUB_TOKEN # piped: never in shell history
launchpad secrets generate SESSION_SECRET # random, 32 bytes
launchpad secrets list # names only, values hidden
A value you set wins over a service's value of the same name, so you can override EMAIL_FROM, for
example, and keep the rest.
The three environments
| Environment | Used by |
|---|---|
production | Your live app, and every process (workers, cron, APIs) |
preview | Vercel's preview deployments, one per pull request, listed on the project's page |
development | Local work, through launchpad env --dotenv |
A secret set with no environment goes to all three. In the console, a project's Environment variables section shows which variables differ between them (names only, never values).
Previews get their own database
Every pull request's preview is a real copy of your app, and people click around in it: signing up, adding items, deleting things. If it ran against your production database, all of that would land in your live data.
So on Neon, previews and local development get their own copy of the database: a Neon branch
called launchpad-preview, made from production's data at the moment it's created. Production's
DATABASE_URL points at your real database; preview and development get the copy's. Nothing done
in a preview reaches production, and branches are copy-on-write, so the copy costs almost nothing
until it changes.
- The copy is made once, on the first deploy, and doesn't follow production after that. To start it again from production's current data, reset the branch from its parent in the Neon console.
- It holds a copy of production's data, including your users' details. Keep previews private (Vercel asks visitors to sign in by default) and don't share preview links outside your team.
- To give previews production's database instead, use the switch in the console's Environment
variables section, or set
"previews": "shared"underservices.database. The copy is deleted. - On Supabase, previews use the production database: Supabase's branching is a paid add-on that Launchpad doesn't set up. The console says so on the project's page.
Payment keys in previews
Previews also get production's payment keys unless you set others for them. With live Razorpay or Stripe keys, a test checkout in a preview charges a real card, and the console warns you. Add your test-mode keys under the same names, ticking only preview and development: they replace the live ones there and production keeps the live keys.
Looking at one environment
To see what one environment holds:
launchpad env --env preview # names and values for that environment
launchpad env --dotenv > .env.local # development values, for running locally
Limiting what a part can see
By default every part of the app sees every variable. To narrow that, list what a part needs under
its secrets in launchpad.json:
"hosting": {
"secrets": ["NEXT_PUBLIC_SUPABASE_URL", "NEXT_PUBLIC_SUPABASE_ANON_KEY"]
}
A worker that only writes to the database then never receives your Stripe key.
Values that refer to other values
Inside launchpad.json, env entries can refer to a secret or to another part of the app:
"hosting": { "env": { "NEXT_PUBLIC_API_URL": "${processes.api.url}" } },
"processes": [{ "name": "api", "env": { "SECRET_KEY": "${env.APP_SECRET}" } }]
That's how the web app learns its API's address without you copying it after each deploy.
Removing one
Remove a secret, or take a name out of a part's secrets list, and the next deploy deletes it from
Vercel and Render. Launchpad only ever deletes variables it set itself: anything you added by hand
in a provider's dashboard is left alone.
Rules of thumb
- Anything starting
NEXT_PUBLIC_,VITE_orPUBLIC_is visible in the browser. Never put a secret key behind those prefixes. - Use test keys while you build, and switch to live keys in
productiononly. Previews get your test keys as long as you set them for preview and development. - After adding or changing a variable, deploy again: a running app keeps the values it started with.
Something missing or wrong? Edit this page on GitHub or email hello@axonscape.com.