Cloud & DevOps4 min read

Serverless on AWS: lessons from building a SaaS platform from scratch

I designed and deployed a full SaaS platform using serverless architecture on AWS. Here I share the technical decisions, mistakes I made, and what I learned.

UA

Uriel Arana

June 1, 2025

Serverless on AWS: lessons from building a SaaS platform from scratch

When I joined AppWhoop as a senior consultant, the challenge was clear: build a collaborative economy SaaS platform from scratch that could handle high concurrency — without the cost of always-on dedicated servers.

The answer was serverless architecture on AWS. But as you'll learn, "serverless" doesn't mean "problem-free."

Why Serverless?

For an early-stage SaaS, the benefits are clear:

  • Pay per use: you only pay when there's real traffic
  • Auto-scaling: AWS handles spikes without manual configuration
  • Less DevOps: no servers to manage, no patches, no OS updates

But it has important tradeoffs you need to understand before committing.

The Architecture We Chose

React.js (Vite) → CloudFront (CDN)
       ↓
API Gateway → Lambda Functions
       ↓
MariaDB (RDS in private VPC)
S3 (static files and uploads)
CloudWatch (logs and alerts)

Three environments from day one

A mistake I see frequently: starting with only one environment. We configured three from day 1:

  1. Developmentdevelop branch, automatic deploy on every push
  2. QAstaging branch, manual deploy with approval
  3. Pre-productionmain branch, production mirror for final testing

This saved us multiple times from critical bugs that only appear with real data.

Lesson 1: Lambda Cold Starts Are Real

The most underestimated problem with Lambda: cold starts. When a function hasn't been invoked in ~15 minutes, the next request takes an extra 800ms–3s to "wake up" the container.

Solution we implemented:

// Provisioned Concurrency for critical auth routes
// serverless.yml
functions:
  auth:
    handler: src/handlers/auth.handler
    provisionedConcurrency: 2  # Always 2 "warm" instances
    events:
      - http:
          path: /auth/{proxy+}
          method: any

For less critical routes (dashboards, reports), we accepted the cold start and set team expectations accordingly.

Lesson 2: RDS in VPC + Lambda in VPC = Much Worse Cold Starts

This was our most costly mistake. We put RDS (MariaDB) inside a private VPC for security — correct. But Lambda also needs to be in the VPC to connect. And Lambda in a VPC has cold starts of 8–10 seconds.

The solution: RDS Proxy

Lambda (outside VPC) → RDS Proxy (in VPC) → RDS MariaDB

RDS Proxy maintains a persistent connection pool, eliminates the need to put Lambda in the VPC, and dramatically improves cold starts.

Additional cost: ~$35/month. Worth every cent.

Lesson 3: Structure Lambdas as Microservices, Not a Monolith

The most common anti-pattern: one giant Lambda that handles everything.

❌ handler.ts → handles auth, users, products, payments, reports

We organized each Lambda by business domain:

✅
handlers/
  auth/         → login, registration, token refresh
  users/        → user CRUD
  listings/     → service listing CRUD
  payments/     → payment processor integration
  notifications/→ emails and push notifications

Benefit: each function scales independently. If there's a registration spike, only the auth Lambda scales. The rest are unaffected.

The Final Numbers

After 3 months in production:

  • P99 Latency: < 200ms (excluding cold starts on non-critical functions)
  • Uptime: 99.97%
  • Monthly cost: ~$180 (for ~50k requests/day)
  • Equivalent on EC2: ~$450/month for the same performance with auto-scaling

When NOT to Use Serverless

It would be dishonest not to mention this. Serverless is not the right answer for:

  • Apps with persistent WebSocket connections (use EC2 + Socket.io)
  • Video/audio processing (Lambda has 15 min limit and 10GB memory cap)
  • Very early-stage startups that need to iterate fast without thinking about infra (use Railway or Render)
  • Ultra-low, constant latency workloads (gaming, real-time trading)

Conclusion

Serverless on AWS let us launch a robust product with a small team and predictable costs. The key was understanding the tradeoffs from the start and not treating Lambda like a traditional server.

If you're considering this architecture for your next SaaS, the biggest piece of advice I can give: set up your 3 environments from day 1 and add RDS Proxy if you're using a relational database in a VPC.

Have questions about the architecture? Contact me here — I love talking distributed systems.


Uriel Arana is a Senior Full Stack Developer and Technology Consultant with experience in serverless architectures on AWS. Currently available for consulting projects.

Serverless on AWS: lessons from building a SaaS platform from scratch — Uriel Arana