Deploy Backend
This guide covers deploying the FastAPI backend to production.
Quick Deploy to Railway
Railway is the easiest platform for deploying Python applications with a generous free tier.
1. Prerequisites
- GitHub account
- Railway account (railway.app)
- Code pushed to GitHub repository
2. Create New Project
- Go to railway.app
- Click "New Project"
- Select "Deploy from GitHub repo"
- Choose your
acodeadayrepository - Railway auto-detects Python and starts deployment
3. Configure Root Directory
If your backend is in a subdirectory:
- Go to project Settings
- Set Root Directory:
backend - Redeploy
4. Add Environment Variables
Go to project Variables tab and add:
DATABASE_URL=postgresql+asyncpg://postgres:PASSWORD@HOST:5432/postgres
SUPABASE_URL=https://YOUR_PROJECT.supabase.co
SUPABASE_KEY=YOUR_ANON_KEY
JUDGE0_URL=https://your-judge0-instance.com
AUTH_USER_EMAIL=admin
AUTH_PASSWORD=your-secure-password
ENVIRONMENT=production
PYTHONUNBUFFERED=15. Configure Build Command
Railway auto-detects uvicorn, but you can customize:
- Go to Settings > Deploy
- Build Command:
pip install uv && uv sync - Start Command:
uv run uvicorn app.main:app --host 0.0.0.0 --port $PORT
6. Run Migrations
After first deployment:
- Go to project Deployments
- Click on active deployment
- Open "Deploy Logs"
- You'll see the app URL
SSH into Railway (if needed):
railway run uv run alembic upgrade headOr run migrations locally against production DB:
# Set DATABASE_URL to production
uv run alembic upgrade head7. Seed Problems
# Connect to production database
railway run uv run python scripts/seed_problems.py seedOr locally:
# Set DATABASE_URL to production
uv run python scripts/seed_problems.py seed8. Get Deployment URL
Railway provides a URL like:
https://acodeaday-production.up.railway.appTest it:
curl https://your-app.up.railway.app/api/problemsDeploy to Fly.io
Fly.io offers more control and excellent performance.
1. Install Fly CLI
# macOS
brew install flyctl
# Linux
curl -L https://fly.io/install.sh | sh
# Windows
powershell -Command "iwr https://fly.io/install.ps1 -useb | iex"2. Login to Fly.io
flyctl auth login3. Create Dockerfile
Create backend/Dockerfile:
FROM python:3.12-slim
WORKDIR /app
# Install uv
RUN pip install uv
# Copy dependency files
COPY pyproject.toml uv.lock ./
# Install dependencies
RUN uv sync --frozen
# Copy application code
COPY . .
# Run migrations and start server
CMD uv run alembic upgrade head && uv run uvicorn app.main:app --host 0.0.0.0 --port 80804. Create fly.toml
cd backend
flyctl launchThis creates fly.toml. Edit it:
app = "acodeaday"
primary_region = "sjc"
[build]
dockerfile = "Dockerfile"
[env]
ENVIRONMENT = "production"
PORT = "8080"
[[services]]
internal_port = 8080
protocol = "tcp"
[[services.ports]]
port = 80
handlers = ["http"]
[[services.ports]]
port = 443
handlers = ["tls", "http"]
[services.http_checks]
interval = "10s"
timeout = "2s"
grace_period = "5s"
path = "/health"5. Set Secrets
flyctl secrets set DATABASE_URL="postgresql+asyncpg://..."
flyctl secrets set SUPABASE_URL="https://..."
flyctl secrets set SUPABASE_KEY="..."
flyctl secrets set JUDGE0_URL="https://..."
flyctl secrets set AUTH_USER_EMAIL="admin"
flyctl secrets set AUTH_PASSWORD="your-password"6. Deploy
flyctl deploy7. Run Migrations
flyctl ssh console
uv run alembic upgrade head
exit8. Get URL
flyctl infoYour app will be at https://acodeaday.fly.dev
Deploy to Render
Render offers a free tier with automatic deploys from Git.
1. Create Web Service
- Go to render.com
- Click "New +" > "Web Service"
- Connect GitHub repository
- Configure:
- Name: acodeaday-backend
- Region: Choose closest
- Branch: main
- Root Directory: backend
- Runtime: Python 3
- Build Command:
pip install uv && uv sync - Start Command:
uv run uvicorn app.main:app --host 0.0.0.0 --port $PORT
2. Add Environment Variables
In Environment tab:
DATABASE_URL=postgresql+asyncpg://...
SUPABASE_URL=https://...
SUPABASE_KEY=...
JUDGE0_URL=https://...
AUTH_USER_EMAIL=admin
AUTH_PASSWORD=your-password
ENVIRONMENT=production3. Deploy
Click "Create Web Service". Render auto-deploys on every Git push.
4. Run Migrations
After first deploy, open Shell:
uv run alembic upgrade head
uv run python scripts/seed_problems.py seedEnvironment Variables Reference
Required for all deployment platforms:
# Database
DATABASE_URL=postgresql+asyncpg://USER:PASSWORD@HOST:PORT/DATABASE
# Supabase
SUPABASE_URL=https://PROJECT_ID.supabase.co
SUPABASE_KEY=your_anon_key
# Judge0
JUDGE0_URL=https://your-judge0-instance.com
# Optional: JUDGE0_API_KEY=your_key (if using auth)
# Authentication
AUTH_USER_EMAIL=admin
AUTH_PASSWORD=your-secure-password
# Environment
ENVIRONMENT=production
# Optional
LOG_LEVEL=INFO
CORS_ORIGINS=https://your-frontend.comHealth Check Endpoint
Add health check to backend/app/main.py:
@app.get("/health")
async def health_check():
return {"status": "healthy"}Most platforms use this for uptime monitoring.
CORS Configuration
Update CORS for production in backend/app/main.py:
app.add_middleware(
CORSMiddleware,
allow_origins=[
"https://your-frontend.vercel.app",
"https://yourdomain.com"
],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)Logging
Configure structured logging for production:
import structlog
structlog.configure(
processors=[
structlog.stdlib.filter_by_level,
structlog.stdlib.add_logger_name,
structlog.stdlib.add_log_level,
structlog.stdlib.PositionalArgumentsFormatter(),
structlog.processors.TimeStamper(fmt="iso"),
structlog.processors.StackInfoRenderer(),
structlog.processors.format_exc_info,
structlog.processors.UnicodeDecoder(),
structlog.processors.JSONRenderer()
],
context_class=dict,
logger_factory=structlog.stdlib.LoggerFactory(),
cache_logger_on_first_use=True,
)Monitoring
Add Sentry
uv add sentry-sdk[fastapi]import sentry_sdk
sentry_sdk.init(
dsn="your-sentry-dsn",
environment="production",
traces_sample_rate=1.0,
)SSL/TLS
All platforms (Railway, Fly.io, Render) provide automatic HTTPS. No configuration needed!
Database Connection Pooling
For production, use connection pooling:
# backend/app/db.py
engine = create_async_engine(
DATABASE_URL,
pool_size=10,
max_overflow=20,
pool_pre_ping=True,
)Performance Optimization
Enable Gzip Compression
from fastapi.middleware.gzip import GZipMiddleware
app.add_middleware(GZipMiddleware, minimum_size=1000)Add Caching
Use Redis for caching:
uv add redisimport redis.asyncio as redis
cache = redis.from_url("redis://localhost:6379")Troubleshooting
Deployment fails
# Check logs
railway logs # Railway
flyctl logs # Fly.io
# Render: View logs in dashboardDatabase connection errors
- Verify
DATABASE_URLincludes+asyncpg - Check Supabase allows connections from your platform
- Ensure SSL mode is correct
Import errors
# Ensure all deps in pyproject.toml
uv add missing-package
git commit && git pushNext Steps
- Deploy Frontend
- Environment Variables
- Judge0 Setup for production Judge0