BetterStarter logoBetterStarter
Getting Started

Go Live

Ship your app to production. BetterStarter works with any hosting platform that supports Node.js.

Important Note:

[!TIP] I highly recommend deploying your project to a production server long before the application is "finished."

You don’t have to market it yet—just get it live. Why? Because you want to shrink the distance between zero and one as quickly as possible.

Deploying a feature-heavy app is exponentially more complex than deploying a skeleton. By going live today, you establish a working baseline. From that point on, every new feature is just an incremental update rather than a massive, high-stakes hurdle.

If you wait for perfection, you’ll likely never ship. And if you do, the technical debt of that "big bang" deployment will be 100x harder to manage.

Service Providers Needed

You need 2 hosting providers:

  1. One for the full-stack app (I use Vercel)
  2. One for the PostgreSQL database (I use Supabase)

Environment Variables

BetterStarter uses T3 Env for environment variable management, which means the app will fail to start if required variables are missing. This forces you to be intentional about your configuration.

Setup Your Production Variables

  1. Copy .env.local to .env.production (won't be committed, but used by your hosting provider)
  2. Update all values to your production configuration
  3. Set DATABASE_URL to your production PostgreSQL database
  4. Update APP_BASE_URL and BETTER_AUTH_URL to your production domain
  5. Run database migrations: pnpm db:migrate

Required Environment Variables

Set all of these in your production environment:

APP_BASE_URL=https://yourdomain.com
DATABASE_URL=postgres://...
BETTER_AUTH_URL=https://yourdomain.com
BETTER_AUTH_SECRET=<random-secret>
PLUNK_SECRET_API_KEY=...
TRANSACTIONAL_EMAIL=noreply@yourdomain.com
GOOGLE_CLIENT_SECRET=...
VITE_GOOGLE_CLIENT_ID=...
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
VITE_STRIPE_PRODUCT_CORE_ID=prod_...
VITE_STRIPE_PRICE_CORE_ONE_TIME_ID=price_...
VITE_STRIPE_PROMOTION_CODE_ID=promo_...

If you're not using Stripe, Google Auth, or other services, use dummy values for now. You can remove unused variables later by updating src/env.ts.

Production Database Change Workflow

Use a migration-first workflow for production changes:

  1. Update your Drizzle schema in src/db/schema/
  2. Generate a migration with pnpm db:generate
  3. Review the generated SQL in drizzle/ before applying it
  4. Apply and verify the migration in a staging environment first
  5. Back up your production database
  6. Run pnpm db:migrate against production
  7. Verify app health and key user flows after deployment

Notes:

  • Avoid using db:push in production except for very early projects or throwaway environments
  • Prefer additive, backward-compatible migrations first, then remove old columns/tables in a follow-up deploy

Vercel

The repo includes a vercel.json that configures the build automatically.

  1. Push your repo to GitHub
  2. Import the project in the Vercel dashboard
  3. Add all environment variables from .env.production in the Vercel project settings
  4. Deploy. Vercel will run pnpm build automatically
// vercel.json (already included)
{
  "installCommand": "pnpm i",
  "buildCommand": "pnpm build",
  "devCommand": "pnpm dev",
  "outputDirectory": ".output"
}

Netlify

A netlify.toml is included in the repo.

  1. Push your repo to GitHub
  2. Import the project in the Netlify dashboard
  3. Add all environment variables in Site settings → Environment variables
  4. Deploy
# netlify.toml (already included)
[build]
command = "pnpm build"
publish = "dist"
functions = "dist/server"

Cloudflare Pages

See guide on Tankstack Start for Cloudflare Deployment


Other Platforms

BetterStarter builds to a standard Node.js server. Any platform that can run Node.js will work.

Railway / Render / Fly.io

On this page