Your first real deploy: Supabase + Vercel from scratch
Concrete walkthrough, exporting from no-code, setting up Postgres, deploying frontend, custom domain. Ends with a working URL.
Most "deploy your app" tutorials end at localhost:3000 with a wave and a "now deploy it." That last step is the one that keeps people stuck for a week. This guide takes you from an empty project to a public URL with a real database behind it, and you'll never have to think about provisioning anything.
The stack is Supabase plus Vercel. Postgres, auth, storage, and a CDN-backed Next.js host. Both have free tiers that you will not outgrow before you have real users, and they're "real" enough that you won't have to migrate when you do.
Why this stack
Supabase gives you a managed Postgres database with a dashboard, row-level security, an auth system, and a file storage bucket. The free tier is generous: 500MB database, 1GB file storage, 50k monthly active users on auth. Most side projects live there for a year before paying a cent.
Vercel hosts Next.js the way Heroku used to host Rails: you push to GitHub, it builds and deploys. Custom domains are two clicks. Preview URLs for every branch. The free hobby tier is fine until you start getting real traffic.
Railway is the credible alternative on the hosting side. Same idea, single platform, but it's better when you also need a long-running backend container, a Python worker, or a cron job. We'll come back to it at the end.
Prerequisites
You need a GitHub account, Node 20 or newer, and a project. If you don't have a project yet:
npx create-next-app@latest my-app
cd my-app
Take the defaults. App router, TypeScript, Tailwind. You'll have something running on localhost:3000 in under a minute.
Step 1: Create a Supabase project
Go to supabase.com, sign in with GitHub. Click "New Project." You'll pick:
- An organization (it makes one for you on signup, just use that)
- A project name (anything, you can rename it)
- A database password (save this in your password manager, you'll need it)
- A region (pick the one closest to where most of your users are, or where your Vercel functions will run)
Click create. It takes about a minute to provision.
Once it's up, go to Settings > Database > Connection string > URI. You'll see something like:
postgresql://postgres:[YOUR-PASSWORD]@db.xxxx.supabase.co:5432/postgres
Replace [YOUR-PASSWORD] with the password you set. That's your DATABASE_URL.
Step 2: Connect locally
In your project root, create .env.local:
DATABASE_URL=postgresql://postgres:yourpassword@db.xxxx.supabase.co:5432/postgres
Install the Postgres client:
npm install pg
npm install -D @types/pg
Now a tiny route handler at app/api/books/route.ts:
import { Pool } from "pg";
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
ssl: { rejectUnauthorized: false },
});
export async function GET() {
const { rows } = await pool.query("select * from books order by id desc");
return Response.json(rows);
}
Run npm run dev and hit http://localhost:3000/api/books. You'll get an error because the table doesn't exist yet. That's fine, that's step 3.
Step 3: Run the schema
Open the Supabase dashboard, click SQL Editor, paste:
create table books (
id bigserial primary key,
title text not null,
author text,
created_at timestamptz default now()
);
insert into books (title, author) values ('Dune', 'Frank Herbert');
Click Run. Refresh http://localhost:3000/api/books. You should see Dune.
If you'd rather track schema in your repo, drop those statements into supabase/migrations/0001_init.sql and run them with the Supabase CLI later. For a first deploy, the SQL editor is fine.
Step 4: Push to GitHub
Make a new repo on github.com, don't initialize it with anything. Then:
git init
git add .
git commit -m "initial"
git branch -M main
git remote add origin git@github.com:yourname/my-app.git
git push -u origin main
Make sure .env.local is in .gitignore. create-next-app adds it for you. Don't commit your DATABASE_URL.
Step 5: Deploy on Vercel
Go to vercel.com, sign in with GitHub. Click "Add New Project." Vercel will list your repos. Pick the one you just pushed.
Before you click Deploy, expand "Environment Variables" and add:
- Name:
DATABASE_URL - Value: your full Postgres connection string
Click Deploy. It builds for about 60 seconds and gives you a URL like my-app-xxxx.vercel.app. Open it. The site is live. Hit /api/books. Your database is live too.
Step 6: Custom domain
You already have a working URL on *.vercel.app. If that's enough, you're done.
If you own a domain, go to your project's Settings > Domains in Vercel. Type the domain. Vercel tells you what DNS records to set: usually an A record pointing to 76.76.21.21 for the apex, and a CNAME pointing to cname.vercel-dns.com for www. Add those at your registrar (Cloudflare, Namecheap, wherever). Propagation is usually under five minutes. SSL gets issued automatically.
Common gotchas
Connection pooling. The default Supabase connection string is a direct connection, fine for local dev but bad for serverless. Vercel functions can spin up dozens of instances and exhaust your connection limit fast. In Supabase, go to Settings > Database > Connection pooling and copy the pooler URL (port 6543, "transaction" mode). Use that as your production DATABASE_URL.
Env vars not picked up. Vercel only reads environment variables at build time. If you add a variable after deploying, you have to redeploy. Click the latest deployment, hit the three-dot menu, "Redeploy."
Postgres SSL. Supabase requires SSL. The ssl: { rejectUnauthorized: false } option above handles it. If you forget, you'll see an SSL required error in your function logs.
When Railway is the better call
If your app is Next.js plus a database, Vercel and Supabase is the cleaner answer. If you also have a Python script, a long-running worker, a Discord bot, or a cron job, Railway lets you run all of that on one platform with one bill. You get Postgres, a service for your Next.js app, a service for your Python worker, and cron triggers, all in the same project. The DX isn't quite as polished as Vercel for pure frontend work, but the surface area is larger.
Next up
You have a real URL, a real database, and a real deploy pipeline. The last guide in this pillar is "Claude Code & CLI workflows: shipping from your terminal," where you stop touching the dashboard and start pushing changes the way professional teams actually do it.
Next in this pillar
Claude Code & CLI workflows: shipping from your terminal