← Blog

Building Scalable Web Applications

2024-03-15
architecture
performance
typescript
scalability

Building Scalable Web Applications

Every engineer eventually faces the same challenge: an application that worked fine at launch starts creaking under real-world load. This post is about the patterns I’ve found effective for building systems that scale gracefully.

The Foundation: Define Your Constraints First

Before writing a single line of architecture, answer these questions:

  • What is the expected peak concurrent users?
  • What is your acceptable p99 latency?
  • What is your data growth rate per month?

Skipping this step leads to over-engineering in the wrong places.

Horizontal vs Vertical Scaling

Vertical scaling (bigger machines) is fast and simple — until you hit the hardware ceiling. It’s a fine starting point but not a strategy.

Horizontal scaling (more instances) requires your application to be stateless. If state lives in memory or local disk, you’ve built a monolith that can’t scale out.

The rule: no session state on the application server. Use Redis, a distributed cache, or your database.

The Twelve-Factor Principles That Actually Matter

Out of the twelve-factor methodology, these four have the highest ROI:

  1. Config in environment — never hardcode URLs, secrets, or feature flags
  2. Stateless processes — see above
  3. Disposability — fast startup, graceful shutdown
  4. Dev/prod parity — if it runs differently locally, it will bite you in production

Observability First

You can’t optimize what you can’t measure. Before performance work:

// Instrument from the start
const span = tracer.startSpan('process-order');
try {
  await processOrder(orderId);
  span.setStatus({ code: SpanStatusCode.OK });
} catch (err) {
  span.recordException(err);
  throw err;
} finally {
  span.end();
}

Add distributed tracing, structured logging, and RED metrics (Rate, Errors, Duration) on every external call.

Database Patterns That Save You

The database is almost always the bottleneck. These patterns help:

  • Read replicas for analytics and reporting queries
  • Connection pooling — PgBouncer or your ORM’s built-in pool
  • Query analysisEXPLAIN ANALYZE before every new query type
  • Soft deletes with timestamps — you’ll thank yourself at 2am

Caching Strategy

A simple three-layer cache strategy:

  1. Browser cache — static assets with far-future expires
  2. CDN cache — API responses that are user-agnostic
  3. Application cache — expensive computations or DB results

Be explicit about cache invalidation. The classic “two hard problems” joke exists because people aren’t explicit.

Conclusion

Scalability is less about clever technology and more about discipline: stateless services, measured everything, and clear cache strategies. Start simple, measure first, optimize second.