Module 1: Architecture Foundations
Understanding architecture decisions before writing code saves months of refactoring later.
System Architecture Layers
Every SaaS application has these layers:
┌─────────────────────────────────────────────────┐
│ CLIENT │
│ Browser / Mobile App / CLI │
└─────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ EDGE │
│ CDN, Edge Functions, Static Assets │
└─────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ API LAYER │
│ REST / GraphQL / tRPC / Server Actions │
└─────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ SERVICE LAYER │
│ Business Logic, Auth, Payments │
└─────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ DATA LAYER │
│ PostgreSQL, Redis, S3, Vector DB │
└─────────────────────────────────────────────────┘Monolith vs Microservices
Monolith (Recommended for 0-1 Stage)
What it is: Single deployable unit containing all code.
my-saas/
├── src/
│ ├── app/ # All routes
│ ├── lib/
│ │ ├── auth/ # Auth module
│ │ ├── billing/ # Billing module
│ │ ├── users/ # Users module
│ │ └── ...
│ └── ...
└── package.json # Single packagePros:
- Simple deployment (one build, one deploy)
- Easy debugging (single codebase)
- No network latency between services
- Faster development velocity
Cons:
- Harder to scale individual components
- One bug can crash everything
- Large codebases become unwieldy
Microservices (Only When Needed)
What it is: Multiple independent services communicating over network.
organization/
├── api-gateway/ # Routes requests
├── auth-service/ # Handles auth
├── billing-service/ # Handles payments
├── user-service/ # User management
└── notification-service/When to use microservices:
- Team size > 20 developers
- Different scaling needs per service
- Polyglot requirements (different languages)
- Regulatory isolation requirements
Don't Start with Microservices
Most startups that fail with microservices fail because they started with them too early. Start with a modular monolith.
Serverless Architecture
What it is: Functions that run on-demand, scale automatically, pay per execution.
When Serverless Works Well
javascript
// API Route (Serverless Function)
// pages/api/hello.js or app/api/hello/route.ts
export async function GET(request) {
// This function:
// - Starts when called
// - Runs your code
// - Shuts down after response
// - Scales automatically
return Response.json({ message: 'Hello World' })
}Good for:
- API endpoints
- Webhooks
- Scheduled jobs (cron)
- Image processing
- Form submissions
Bad for:
- WebSockets (needs persistent connections)
- Long-running processes (>30s typically)
- High-frequency, low-latency needs
Cold Starts
Serverless functions have "cold starts" - initial delay when a function hasn't run recently.
First request: [~500ms cold start] + [execution time]
Next request: [execution time only]
After idle: [cold start again]Mitigation strategies:
- Keep functions warm with scheduled pings
- Use edge functions for latency-critical paths
- Use provisioned concurrency (AWS Lambda)
Edge Computing
What it is: Code running at CDN locations close to users.
javascript
// Edge Function Example (Vercel Edge)
// middleware.ts
import { NextResponse } from 'next/server'
export const config = {
runtime: 'edge', // Runs at edge locations
}
export function middleware(request) {
// This runs at 30+ global locations
// <50ms response time worldwide
// Use cases:
// - A/B testing
// - Geolocation redirects
// - Auth token validation
// - Request rewriting
return NextResponse.next()
}Edge vs Serverless:
| Feature | Edge Functions | Serverless Functions |
|---|---|---|
| Location | CDN edge (30+ locations) | Regions (1-3 locations) |
| Cold start | ~0ms | 100-500ms |
| Runtime | Limited (V8 isolates) | Full Node.js |
| Max duration | 30s | 5-15 minutes |
| Database | Limited access | Full access |
Practical Architecture Decision Tree
Starting a new project?
│
├─ Team size < 10?
│ └─ YES → Modular Monolith
│
├─ Need real-time features?
│ └─ YES → Consider Supabase Realtime or Pusher
│
├─ Heavy image/video processing?
│ └─ YES → Offload to queue + workers
│
├─ Global low-latency needs?
│ └─ YES → Edge functions for hot paths
│
└─ Everything else → Start simple, optimize laterRecommended Architecture for SaaS
┌──────────────────────────────────────────────────────────┐
│ VERCEL (Edge) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Static │ │ Edge │ │ Serverless │ │
│ │ Assets │ │ Middleware │ │ Functions │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└──────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ SUPABASE │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ PostgreSQL │ │ Auth │ │ Storage │ │
│ │ + pgvector │ │ │ │ (S3) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Realtime │ │ Edge │ │
│ │ (WebSocket)│ │ Functions │ │
│ └─────────────┘ └─────────────┘ │
└──────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ EXTERNAL SERVICES │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Stripe │ │ Resend │ │ Inngest │ │
│ │ (Payments) │ │ (Email) │ │ (Jobs) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└──────────────────────────────────────────────────────────┘Summary
- Start with a modular monolith - Separate concerns with folders, not services
- Use serverless for API routes - Let the platform handle scaling
- Use edge for latency-critical paths - Auth checks, redirects, A/B tests
- Extract services only when needed - When a clear bottleneck emerges