Your project structure should look like this:
spec-driven-todo-ai/ ← Root directory (what Vercel sees)
│
├── vercel.json ← Vercel configuration (REQUIRED)
├── requirements.txt ← Python dependencies (REQUIRED)
│
├── api/ ← Vercel serverless functions folder
│ └── index.py ← Main entry point (REQUIRED)
│
└── backend/ ← Your actual backend code
├── main.py
├── database.py
├── models.py
├── schemas.py
├── requirements.txt
├── routes/
│ ├── tasks.py
│ └── users.py
├── auth/
│ ├── routes.py
│ ├── security.py
│ └── middleware.py
└── services/
├── task_service.py
└── user_service.py
Located at: spec-driven-todo-ai/vercel.json
{
"version": 2,
"builds": [
{
"src": "api/index.py",
"use": "@vercel/python"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "api/index.py"
}
]
}What it does:
- Tells Vercel to use Python runtime
- Routes all requests to
api/index.py - Must be in the root directory
Located at: spec-driven-todo-ai/api/index.py
import sys
import os
# Add backend directory to Python path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from backend.database import create_db_and_tables
# Create FastAPI app
app = FastAPI(
title="Task Management API",
description="API for managing tasks with CRUD operations",
version="1.0.0"
)
# CORS configuration
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Import routes from backend folder
from backend.routes import tasks, users
from backend.auth import routes as auth_routes
# Include routers
app.include_router(tasks.router, prefix="/api/tasks", tags=["Tasks"])
app.include_router(users.router, prefix="/api/users", tags=["Users"])
app.include_router(auth_routes.router, prefix="/api/auth", tags=["Authentication"])
# Startup event
@app.on_event("startup")
def on_startup():
create_db_and_tables()
@app.get("/")
def read_root():
return {
"message": "Task Management API",
"version": "1.0.0",
"docs": "/docs"
}
@app.get("/health")
def health_check():
return {"status": "healthy"}
# IMPORTANT: Export for Vercel
handler = appKey points:
- Must be in
api/folder - Imports code from
backend/folder - Exports
handler = appfor Vercel - Adds backend to Python path
Located at: spec-driven-todo-ai/requirements.txt
fastapi==0.104.1
sqlmodel==0.0.16
python-jose[cryptography]==3.3.0
bcrypt==4.0.1
passlib[bcrypt]==1.7.4
slowapi==0.1.9
python-multipart==0.0.6
python-dotenv==1.0.0
psycopg2-binary==2.9.9
uvicorn[standard]==0.24.0
pydantic==2.5.0
requests==2.31.0
Important:
- Must be in root directory (not backend folder)
- Contains all dependencies from
backend/requirements.txt
-
Create PostgreSQL Database (Choose one):
Option A: Neon (Recommended)
- Visit: https://neon.tech
- Sign up → Create Project
- Copy connection string:
postgresql://user:[email protected]/neondb
Option B: Supabase
- Visit: https://supabase.com
- Create Project → Settings → Database
- Copy URI connection string
Option C: Vercel Postgres
- In Vercel dashboard → Storage → Create Database
- Select Postgres
- Copy connection string
# Add all files
git add .
# Commit
git commit -m "Add Vercel deployment configuration"
# Push to GitHub
git push origin mainVerify these files exist:
- ✅
vercel.json(root) - ✅
requirements.txt(root) - ✅
api/index.py - ✅
backend/folder with all code
-
Go to Vercel Dashboard
- Visit: https://vercel.com/dashboard
- Click "Add New..." → "Project"
-
Import Git Repository
- Select "Import Git Repository"
- Choose GitHub
- Authorize Vercel to access your repositories
- Find and select:
spec-driven-todo-ai
-
Configure Project
Framework Preset:
OtherRoot Directory:
.(leave as root - do NOT select backend/)Build Settings:
- Build Command: (leave empty)
- Output Directory: (leave empty)
- Install Command:
pip install -r requirements.txt
Before deploying, click "Environment Variables" and add:
| Key | Value | Example |
|---|---|---|
DATABASE_URL |
Your PostgreSQL connection string | postgresql://user:pass@host/db |
BETTER_AUTH_SECRET |
Generate with: openssl rand -base64 32 |
abc123xyz... |
BETTER_AUTH_URL |
Your frontend URL | https://zohaibcodez.github.io/spec-driven-todo-ai |
How to add each variable:
- Click "Add New"
- Enter Key (e.g.,
DATABASE_URL) - Enter Value
- Select environment: Production, Preview, Development (select all 3)
- Click "Add"
Repeat for all 3 variables.
- Click "Deploy" button
- Wait for build (usually 1-2 minutes)
- Watch the build logs
Build Process:
▲ Installing dependencies...
▲ Building...
▲ Deploying...
✓ Deployment ready
-
Copy your deployment URL (e.g.,
https://spec-driven-todo-ai.vercel.app) -
Test endpoints:
Health Check:
https://your-app.vercel.app/healthShould return:
{"status": "healthy"}API Docs:
https://your-app.vercel.app/docsShould show Swagger UI
Root:
https://your-app.vercel.app/Should return API info
Cause: Vercel can't find api/index.py
Solution:
- Ensure
api/index.pyexists - Check
vercel.jsonhas correct path:"src": "api/index.py" - Don't set Root Directory to
backend/
Cause: Python can't import from backend folder
Solution:
In api/index.py, add at the top:
import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))Cause: Wrong DATABASE_URL or database not accepting connections
Solutions:
-
Check connection string format:
postgresql://username:password@hostname:port/database -
Test connection locally:
cd backend python -c "import os; from database import engine; print('Connected!')"
-
Neon-specific: Ensure using connection string with
?sslmode=require -
Supabase-specific: Use the URI format, not the connection pooler
Cause: Routes not found
Solution: Ensure file structure:
backend/
routes/
__init__.py ← Must exist (can be empty)
tasks.py
users.py
auth/
__init__.py ← Must exist (can be empty)
routes.py
Cause: Runtime error in code
Solution:
-
Check Vercel logs:
- Dashboard → Your Project → Deployments → Click latest → View Function Logs
-
Common fixes:
- Add
python-dotenvto requirements.txt - Remove local imports that don't exist in Vercel
- Check all environment variables are set
- Add
Just push to GitHub:
git add .
git commit -m "Update backend"
git push origin mainVercel auto-deploys in ~1 minute.
- Go to Vercel Dashboard
- Your Project → Deployments
- Click "Redeploy"
- Vercel Dashboard → Your Project
- Click "Deployments"
- Click on a deployment
- Click "View Function Logs"
- Dashboard → Your Project → Analytics
- Check bandwidth, function invocations, errors
- ✅ DATABASE_URL is in environment variables (not in code)
- ✅ BETTER_AUTH_SECRET is strong (32+ characters)
- ✅
.envfiles are in.gitignore - ✅ CORS origins limited in production
- ✅ Database allows Vercel IPs (usually automatic)
| Resource | Limit |
|---|---|
| Bandwidth | 100 GB/month |
| Function Execution | 100 hours/month |
| Deployments | Unlimited |
| Build Time | 6000 minutes/month |
Your usage: Backend API calls count toward function execution time.
Before going live:
- Database is set up (Neon/Supabase/Vercel Postgres)
- All 3 environment variables added in Vercel
-
vercel.jsonexists in root -
requirements.txtexists in root -
api/index.pyexists and hashandler = app -
backend/folder has all your code - Pushed to GitHub
- Tested
/healthendpoint - Tested
/docsendpoint - CORS updated with your frontend domain
Vercel Issues:
- Docs: https://vercel.com/docs
- Support: https://vercel.com/support
Database Issues:
- Neon: https://neon.tech/docs
- Supabase: https://supabase.com/docs
GitHub Issues:
- Open an issue: https://github.com/ZohaibCodez/spec-driven-todo-ai/issues
Last Updated: December 22, 2025
Deployment Configuration by: GitHub Copilot 🤖