Environment variables
.env vs .env.example, what to commit, managed platform keys, and using Deploy → Env vars without losing secrets.
Your app needs settings — API keys, database addresses, public URLs — that change between your laptop and production. Environment variables (often shortened to env vars) are how modern apps read those settings without hard-coding secrets into source files.
This guide is for founders who are new to the idea. You do not need to become a DevOps engineer; you need to know where values live and what LaunchWithCursor handles for you.
What is an environment variable?
An environment variable is a named value your app looks up at runtime, for example:
DATABASE_URL=postgres://...
JWT_SECRET=long-random-string
NEXT_PUBLIC_APP_URL=https://app.example.com
Your code (or framework) reads process.env.DATABASE_URL instead of embedding the password in a file that gets committed to GitHub.
Why this matters: Secrets in Git history are very hard to remove. Env vars keep passwords and API keys out of the codebase your collaborators and deploy system clone.
.env.example vs .env
Most LaunchWithCursor projects use two related files at the repo root (or app root in a monorepo):
| File | Committed to GitHub? | What goes inside |
|---|---|---|
.env.example | Yes | Every variable name your app expects, usually with empty or placeholder values. Documents the checklist for you and your AI assistant. |
.env | No (never commit) | Your real values for local development — Stripe test keys, JWT secrets, localhost URLs, etc. |
Think of .env.example as the table of contents and .env as your private notebook.
Why commit .env.example but not .env?
.env.examplehelps anyone (including future you) know which keys must be set — without exposing actual passwords..envoften contains production-like secrets even on a laptop. If it were pushed to GitHub, those secrets could be scraped within minutes.
Your .gitignore should list .env. Your AI assistant can add that line if it is missing.
Keep real values on your machine
Store working secrets in .env on your computer so you do not lose them between sessions. That file stays private on your laptop.
When you deploy:
- Open your local
.envin your editor (or ask your AI assistant to list the keys — not the values — if you prefer). - Go to Deploy → Env vars on LaunchWithCursor for your project.
- Use Copy name next to each suggested key from
.env.example, paste the matching value from your local.env, and click Add.
You are copying your own values from a file you already trust — not inventing them from scratch on the website.
Why this matters: Founders often forget a Stripe or SendGrid key after weeks away from a project. Local
.envis your backup; the dashboard is where production gets the same keys safely encrypted.
The Env vars page on LaunchWithCursor
On Deploy → Env vars you will see:
- Suggested from .env.example — keys detected in your GitHub repo (the card stays visible while loading, on errors, and when there is nothing left to add). Copy each name, then enter the value in the add form below.
- Current variables — what is stored for the next deploy. Values start masked; use the eye icon on a row to reveal a value, and the copy icon to copy it, so you can confirm a key holds the right value without retyping it. Revealing or copying a stored value is recorded in the audit log.
- Saved For Later — a variable you keep but are not using yet. It shows with a purple bookmark, and the value is not sent to your app on deploy. Turn the toggle off when your app is ready for it.
- Search — helpful once you have many keys.
After you change env vars, re-deploy the affected services so running containers pick up new values. Build-time keys (names starting with NEXT_PUBLIC_, VITE_, or REACT_APP_) require re-deploying front-end services after changes.
Need GitHub connected first? See Git & GitHub.
Platform-managed vs your own services
LaunchWithCursor injects some variables automatically when you turn on add-ons. They appear on the Env vars tab marked managed and cannot be edited.
You do not have to use platform Database, Redis, Storage, Email, or LaunchPay. If you already have Neon, your own R2 bucket, Resend, Stripe, etc.:
- Leave the matching flag in
launchwithcursor.deploy.jsonasfalse(needsDatabase,needsRedis,needsStorage,needsEmail,needsLaunchPay). - On Deploy → Env vars, add the same names your app already uses (
DATABASE_URL,R2_*, provider-specific keys, …). Those stay editable until you provision the platform add-on. - If you later want the platform service: ask your coding assistant to set the flag to
true, commit, Sync from repo, then provision. The dashboard will warn you if you click Provision while the manifest still says no.
Provisioning a platform add-on replaces any value you had under that canonical name.
| Variable(s) | Added when you… | Until then |
|---|---|---|
DATABASE_URL | Provision Postgres or MySQL on Deploy → Database | You may set this yourself (e.g. Neon) |
REDIS_URL, REDIS_KEY_PREFIX | Provision Redis on Deploy → Redis | You may set these yourself (e.g. Upstash) |
R2_ACCOUNT_ID, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_BUCKET_NAME, R2_ENDPOINT, R2_PUBLIC_URL | Provision R2 storage on Deploy → Storage | You may set these yourself |
EMAIL_API_URL, EMAIL_API_KEY, EMAIL_FROM_DOMAIN, EMAIL_FROM_NAME | Set up platform email on Deploy → Email | Use your own email provider keys instead |
LAUNCHPAY_* | Enable LaunchPay | Use Stripe/Paystack/etc. keys as normal env vars |
APP_ENV | Always managed for hosted apps | Do not set |
NODE_ENV=production | Injected on every deploy | Do not set |
Redis Pub/Sub: provisioned Redis lets your app publish and subscribe on any channel — no extra permission is needed. Keys are already scoped to your app by
REDIS_KEY_PREFIX, but pub/sub channel names are not, so use the prefix in channel names too (e.g.ck:my-app-a1b2:calls:room-1) to avoid messages crossing between hosted apps.
PORT is set automatically from each service’s internal port on Deploy → Overview. App listen-port vars like API_PORT / WEB_PORT are ignored on the platform — delete them if they show up in suggestions. This does not apply to third-party service ports such as SMTP_PORT, REDIS_PORT, or DATABASE_PORT — those are normal settings and are used as-is.
Why this matters: Copy-pasting a platform
DATABASE_URLinto Neon (or the reverse after you already provisioned) is the most common “works on my machine” failure. Pick one source per add-on.
What the LaunchWithCursor extension already does
When you install the extension and open your project, it copies a starter pack into .launchwithcursor/pack/LAUNCHWITHCURSOR/ with the canonical variable names and deploy rules your AI assistant should follow (SKILLS/Infrastructure.md, deploy checklists, etc.).
That means:
- Your assistant should create or update
.env.examplewith the right keys as features are built. - You should not need to memorize every infrastructure variable from this web page.
- After provisioning add-ons on the dashboard, redeploy and let managed vars appear — your assistant reads them at runtime like any other env var.
Run LaunchWithCursor: Run Full Scan after changing .env.example so the dashboard suggestions stay in sync with your repo.
Quick checklist
.env.examplein Git — names only, placeholders OK..envon your laptop — real values, never committed.- Deploy → Env vars — copy names, paste values from local
.env. Skip keys that already show as managed. Until you provision an add-on, you may setDATABASE_URL/R2_*/ etc. yourself. - Re-deploy after changes.
- Ask your AI assistant for anything confusing — that is what it is for.
Next steps
- Deploy & hosting — full deploy flow, domains, and add-ons
- Git & GitHub — push code so env suggestions stay current
- Install & sign in — extension and starter pack setup