Migrated from split-stack architecture (Vercel Frontend + Render Backend) to unified Vercel deployment with serverless functions.
Vercel (Frontend) → CORS → Render (Backend) → Supabase (Database)
- Cold starts (30-60s on Render free tier)
- Cross-domain authentication complexity
- CORS configuration required
- Token management in localStorage
Vercel (Frontend + API Functions) → Supabase (Database)
- No cold starts (instant serverless functions)
- Same-origin requests (no CORS)
- Simplified authentication
- Better performance
Created /api directory with serverless functions:
/api/_lib/auth.ts- Shared authentication utilities/api/_lib/db.ts- Database connection with postgres-js/api/auth/user.ts- GET user profile/api/auth/logout.ts- POST logout/api/auth/sync-user.ts- POST sync user to database/api/properties/index.ts- GET/POST properties/api/properties/[id].ts- GET/PUT/DELETE specific property/api/units/index.ts- GET/POST units/api/units/[id].ts- GET/PUT/DELETE specific unit/api/tenants/index.ts- GET/POST tenants/api/tenants/[id].ts- PUT specific tenant/api/payments/index.ts- GET/POST payments/api/leases/index.ts- GET/POST leases/api/dashboard/stats.ts- GET dashboard statistics
Updated client/src/lib/config.ts:
- Changed
API_BASE_URLto empty string for production (same-origin) - Removed Render backend references
- Simplified configuration
Updated vercel.json:
- Added
/api/*rewrites for serverless functions - Configured Node.js runtime for TypeScript functions
- Set environment variables for Supabase and database
Added:
@vercel/node- TypeScript types for Vercel functionspostgres- PostgreSQL client for serverless (already installed)
Go to Project Settings → Environment Variables and add:
DATABASE_URL- Your Supabase PostgreSQL connection stringSUPABASE_URL- Your Supabase project URLSUPABASE_ANON_KEY- Your Supabase anon keySUPABASE_SERVICE_ROLE_KEY- Your Supabase service role key (for admin operations)
git add .
git commit -m "Migrate to Vercel serverless functions"
git push origin mainVercel will automatically:
- Build the frontend (React/Vite)
- Deploy serverless functions from
/apidirectory - Configure routing
The authentication flow now works as follows:
- User visits
/api/login(will need to create login function or use Supabase Auth UI) - After login, Supabase returns JWT token
- Frontend stores token in localStorage
- All API requests include
Authorization: Bearer <token>header - Serverless functions verify token with Supabase
You'll need to update the login flow since we're using serverless functions:
Option A: Use Supabase Auth directly in frontend
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY)
// Sign in
const { data, error } = await supabase.auth.signInWithPassword({
email: 'user@example.com',
password: 'password'
})
// Store token
if (data.session) {
localStorage.setItem('supabase-auth-token', data.session.access_token)
}Option B: Create login serverless function
Create /api/auth/login.ts to handle email/password login
- ✅ Reduced cold starts - Vercel functions use Fluid compute to minimize cold starts, though they can still occur on first invocation or after periods of inactivity (especially on Hobby plan). Significantly better than Render's 30-60s cold starts.
- ✅ Global CDN - Functions deployed to edge locations
- ✅ Same-origin - Faster requests, no pre-flight CORS checks
- ✅ Single deployment - One git push deploys everything
- ✅ No CORS config - Same-origin requests
- ✅ Better debugging - Vercel logs integrated with frontend
- ✅ Free tier - Vercel Hobby plan includes:
- 100GB bandwidth
- 150,000 Function Invocations per month
- 100 hours function execution time
- Far exceeds typical usage for this app
- ✅ Automatic scaling - Vercel handles traffic spikes
- ✅ Serverless - No server management
- ✅ PostgreSQL - Keep relational database benefits
You can now remove:
server/directory (Express backend no longer needed)- Render deployment configuration
- CORS configuration in routes
- Cross-domain authentication logic (simplified)
- ✅ Deploy to Vercel
- ✅ Set environment variables
- ⏳ Test all API endpoints
- ⏳ Update authentication flow (if using custom login)
- ⏳ Remove old Render deployment
- ⏳ Update documentation
Solution: Check vercel.json rewrites are correct and functions are in /api directory
Solution: Verify DATABASE_URL environment variable is set in Vercel
Solution: Check SUPABASE_SERVICE_ROLE_KEY is set and valid
Solution: Optimize database queries or increase maxDuration in vercel.json (max 60s on Hobby plan)
If needed, revert by:
- Change
API_BASE_URLback to Render URL inconfig.ts - Revert
vercel.jsonto previous version - Keep using Render backend
December 5, 2025
Automated migration with guidance