Skip to content

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

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 package

Pros:

  • 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:

  1. Keep functions warm with scheduled pings
  2. Use edge functions for latency-critical paths
  3. 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:

FeatureEdge FunctionsServerless Functions
LocationCDN edge (30+ locations)Regions (1-3 locations)
Cold start~0ms100-500ms
RuntimeLimited (V8 isolates)Full Node.js
Max duration30s5-15 minutes
DatabaseLimited accessFull 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 later
┌──────────────────────────────────────────────────────────┐
│                     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

  1. Start with a modular monolith - Separate concerns with folders, not services
  2. Use serverless for API routes - Let the platform handle scaling
  3. Use edge for latency-critical paths - Auth checks, redirects, A/B tests
  4. Extract services only when needed - When a clear bottleneck emerges

Next: Module 2: Frontend with Next.js →