$ cd ../blog
$ cat ./fast-prototyping-stack-2024.md

the fast prototyping stack that actually ships

Next.js, Supabase, Vercel, Railway, Tailwind, and shadcn. Zero to production in hours, not weeks.

date: March 28, 2024

read: 10 min

tags: next.js, supabase, prototyping, stack

Most prototypes die in development. Not because the idea sucks, but because the stack is too slow. Here's what actually works.

The Stack

  • Next.js 14 - Framework
  • Supabase - Database + Auth + Storage
  • Vercel - Hosting
  • Railway - Backend services when needed
  • Tailwind + shadcn - UI

This isn't theory. This is what I use to ship.

Why This Stack

Speed to First Deploy: < 1 Hour

From npx create-next-app to live URL with auth and database.

# Minute 0: Create app
npx create-next-app@latest my-app --typescript --tailwind --app

# Minute 5: Add Supabase
npm install @supabase/supabase-js @supabase/auth-helpers-nextjs

# Minute 15: Add shadcn components
npx shadcn-ui@latest init

# Minute 30: Deploy
git push  # Vercel auto-deploys

Minute 60: You have auth, database, and a live app.

Try doing that with a custom backend.

Next.js 14: The Foundation

Why Next.js

Server Components by default:

// This runs on the server. Zero client JS.
export default async function Page() {
  const data = await db.query('SELECT * FROM posts')
  return <PostList posts={data} />
}

API routes that don't suck:

// app/api/users/route.ts
export async function GET() {
  const users = await getUsers()
  return Response.json(users)
}

Image optimization included:

import Image from 'next/image'

<Image src="/hero.jpg" width={1200} height={600} alt="Hero" />
// Automatically optimized, lazy loaded, responsive

What You Get Free

  • TypeScript configured
  • Hot reload that works
  • Built-in routing
  • API routes
  • Middleware
  • Edge functions

Zero config. Just code.

Supabase: Backend in a Box

Why Supabase

It's Postgres with superpowers. Open source. Self-hostable. Fast.

Auth in 5 lines:

import { createClient } from '@supabase/supabase-js'

const supabase = createClient(url, key)

// Sign up
await supabase.auth.signUp({ email, password })

// That's it. Email verification, password reset, all included.

Database that feels like an API:

// No SQL needed (but you can use it)
const { data } = await supabase
  .from('posts')
  .select('*')
  .eq('published', true)
  .order('created_at', { ascending: false })
  .limit(10)

Real-time for free:

supabase
  .channel('posts')
  .on('postgres_changes', {
    event: 'INSERT',
    schema: 'public',
    table: 'posts'
  }, (payload) => {
    console.log('New post!', payload)
  })
  .subscribe()

Storage Included

// Upload file
await supabase.storage
  .from('avatars')
  .upload('user-1.png', file)

// Get public URL
const { data } = supabase.storage
  .from('avatars')
  .getPublicUrl('user-1.png')

No S3 config. No IAM policies. Just works.

Row Level Security

-- Only users can see their own data
CREATE POLICY "Users can view own data"
ON profiles FOR SELECT
USING (auth.uid() = user_id);

Security at the database level. Not middleware. Not API checks. Database.

Vercel: Deploy in Seconds

Why Vercel

Made by the Next.js team. Zero config deployment.

git push
# That's the deployment command

Preview Deploys: The Killer Feature

Every branch gets its own URL. Automatically.

git checkout -b feature/new-ui
git push

# Vercel instantly creates:
# https://my-app-git-feature-new-ui-username.vercel.app

No config. No CI/CD setup. Just works.

Share the link with your team. Get feedback. Merge when ready. The feature branch URL disappears.

Perfect for:

  • Client previews
  • Design reviews
  • QA testing
  • Showing work-in-progress

This alone is worth using Vercel.

What You Get

  • Automatic SSL - HTTPS by default
  • Global CDN - Edge network included
  • Preview deploys - Every branch, every commit
  • Analytics - Built in
  • Edge functions - When you need them
  • Instant rollbacks - One click to previous deploy

Cost Reality

Free tier is generous:

  • 100GB bandwidth
  • Unlimited projects
  • Unlimited team members
  • Unlimited preview deploys

Paid starts at $20/month. Worth it if you're shipping.

Railway: When Vercel Isn't Enough

Why Railway

Vercel is great for Next.js. Not great for everything else.

Sometimes you need:

  • WebSockets that stay alive
  • Background workers
  • Cron jobs
  • Python/Go/Rust services
  • Long-running processes

Railway handles it. Vercel doesn't.

Real Example: Python Parser Microservice

The Problem:

We needed to parse Cisco Catalyst router configuration files. Files up to 50,000 lines. Complex YAML processing. Heavy parsing with CiscoConfParse2.

Tried Vercel Functions first. Hit walls:

Vercel can't run FastAPI properly.

The issue:

// Always use local Python service for now
// Vercel Python functions have issues with FastAPI/ASGI

Vercel Functions don't support ASGI servers (what FastAPI needs). They're built for small, short-lived functions. Not for:

  • Full FastAPI applications
  • Heavy libraries (CiscoConfParse2)
  • Large file processing (50k+ lines)
  • Persistent Python services

We needed a real server. Not serverless.

The Solution:

Move to Railway. Deploy the Python service as a container.

# parser_service.py
from fastapi import FastAPI, UploadFile
from ciscoconfparse2 import CiscoConfParse
import uvicorn
import yaml

app = FastAPI()

@app.post("/parse/catalyst")
async def parse_catalyst_config(file: UploadFile):
    # Read config file (can be 50,000+ lines)
    content = await file.read()

    # Parse with CiscoConfParse2
    parse = CiscoConfParse(content.decode().splitlines())

    # Extract interfaces, VLANs, routing, etc
    interfaces = parse.find_objects(r'^interface')
    vlans = parse.find_objects(r'^vlan')

    # Process YAML configs
    result = {
        "interfaces": [i.text for i in interfaces],
        "vlans": [v.text for v in vlans],
        "total_lines": len(parse.objs)
    }

    return result

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

requirements.txt:

fastapi
uvicorn[standard]
ciscoconfparse2
pyyaml
python-multipart

Dockerfile:

FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["uvicorn", "parser_service:app", "--host", "0.0.0.0", "--port", "8000"]

Deploy:

railway up

That's it.

No config files. No YAML mess. No Kubernetes. Railway reads your Dockerfile and deploys.

Note: We tried Render first, then switched to Railway for simpler configuration and better DX.

It Was a Breeze

Railway gave us:

  • Persistent containers (no cold starts)
  • Real memory limits we could control
  • Proper CPU allocation
  • Built-in monitoring
  • Simple environment variables
  • Auto HTTPS

Everything just worked.

Dead Simple Deploy

# Install CLI
npm i -g @railway/cli

# Deploy anything
railway up

Works with:

  • Docker containers
  • Node.js apps
  • Python workers
  • Go services
  • Redis, Postgres, MongoDB
  • Whatever runs in a container

When to Use Railway

Use Railway for:

  • Background workers
  • Python/Go/Rust services
  • Long-running processes
  • WebSocket servers
  • Database hosting
  • Anything that doesn't fit serverless

Keep Vercel for:

  • Your Next.js frontend
  • API routes that are fast
  • Edge functions
  • Static assets

Use both. They complement each other.

Cost

Pay for what you use. Starts at $5/month.

Our Catalyst parser service:

  • 1GB RAM (needed for 50k+ line files)
  • 1 CPU
  • ~$10/month

Way cheaper than managing our own infrastructure. And way more reliable than trying to force-fit this into serverless.

Tailwind + shadcn: UI That Ships

Why Tailwind

No context switching:

<button className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
  Click me
</button>

Style where you code. No separate CSS files. No naming conventions.

Responsive by default:

<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3">

Mobile first. Works everywhere.

Why shadcn

It's not a component library. It's components you own.

npx shadcn-ui@latest add button

This copies the Button component to your project. You can modify it. It's yours.

No dependency hell. No version conflicts. Full control.

The Components That Matter

# Add what you need
npx shadcn-ui@latest add button
npx shadcn-ui@latest add dialog
npx shadcn-ui@latest add form
npx shadcn-ui@latest add table

Beautiful, accessible, and you own the code.

Real World: 0 to Production

Day 1: MVP

# Hour 1: Setup
create-next-app + supabase + shadcn

# Hour 2-4: Auth
Supabase auth + protected routes

# Hour 5-8: Core feature
Database schema + CRUD + UI

End of Day 1: Working prototype deployed.

Week 1: Polish

  • Add more features
  • Improve UI
  • Add analytics
  • SEO optimization

Week 2: Launch

  • Custom domain
  • Error tracking
  • User feedback
  • Iterate

The Cost Breakdown

Month 1 (Testing):

  • Vercel: $0 (free tier)
  • Supabase: $0 (free tier)
  • Railway: $0 (not needed yet)
  • Domain: $12

Total: $12

Month 2 (Growing):

  • Vercel: $20 (pro plan)
  • Supabase: $25 (pro plan)
  • Railway: $5 (small worker)
  • Domain: $0 (already paid)

Total: $50

Compare that to managing your own infrastructure.

What This Stack Can't Do

Not good for:

  • Heavy compute (use dedicated servers)
  • Complex microservices (use Kubernetes)
  • Legacy integration (use whatever works)

Perfect for:

  • SaaS MVPs
  • Internal tools
  • Client projects
  • Side projects that might scale

The Trade-offs

Pros

  • Ship in hours, not weeks
  • Scales to thousands of users
  • Low maintenance
  • Great DX

Cons

  • Vendor lock-in (Vercel + Supabase)
  • Cost scales with usage
  • Less control than self-hosted

For prototypes, pros win. Ship first, optimize later.

Getting Started

1. Clone the Template

npx create-next-app@latest --example with-supabase

2. Add Supabase Project

# Create project at supabase.com
# Copy credentials to .env.local

3. Add shadcn

npx shadcn-ui@latest init
npx shadcn-ui@latest add button form input

4. Deploy

git init
git add .
git commit -m "Initial commit"
git push

# Connect to Vercel
# Deploy happens automatically

Time: 20 minutes

The Reality Check

This stack isn't perfect. It's practical.

It won't win architecture beauty contests. It will ship your idea before your competitors finish their Kubernetes config.

Speed matters. This stack is fast.

Useful Resources

Start building. The stack is ready.

$