deploy · tutorial

From localhost to a $5 VPS in one command

Prefilled .env.local for dev, .env.prod for the server. No dashboard spelunking.

Boring Team

Boring Team

September 13, 2026 · 1 min read

Deployment usually means an afternoon of clicking through dashboards, pasting secrets into text boxes, and discovering that staging and prod disagree about everything.

Boring keeps two files:

.env.local   # prefilled, gitignored, loads automatically
.env.prod    # prod values, gitignored, scp'd to the server once

Local: just run it

.env.local ships prefilled — SQLite, test-mode billing, localhost URLs. The only empty lines are OAuth and provider keys, which you don't need until you do:

npm run dev
# → http://localhost:3000, database in ./db/app.db

Prod: source and start

Next.js doesn't auto-load .env.prod, so the scripts do it for you:

npm run build:prod   # loads .env.prod, then next build
npm run start:prod   # loads .env.prod, then next start

Shell variables beat .env.local every time, so prod values always win — even if both files exist on the box.

The checklist that remains

  1. Point DNS at the box, set NEXTAUTH_URL to the real domain.
  2. Generate a real NEXTAUTH_SECRET (openssl rand -base64 32).
  3. Create the billing product (Stripe price, Dodo product, or LS variant) and paste the ID.
  4. Paste the provider webhook secret, point the webhook URL at /api/webhook/<rail>.
  5. Run schema.sql once if you chose Supabase.

That's the whole list. The boring kind of list — short, complete, and the same every time.

deploytutorial