Table of contents

Open Table of contents

Introduction

Designing high-performance APIs requires deep understanding of network layers, database pooling, and serialization formats. This guide covers the most impactful patterns.

APIs are the backbone of modern software. A slow API kills user experience faster than a bad UI.

Key Considerations

Here’s a quick overview of the areas we’ll cover:

ConcernSolutionImpact
CachingRedis / CDNVery High
DB QueriesIndexes + BatchingHigh
PayloadGzip / BrotliMedium
AuthJWT + Rate limitingHigh
ProtocolHTTP/2, gRPCMedium

Caching Strategy

Use Cache-Control headers and a Redis layer for frequently-accessed endpoints.

// src/middleware/cache.ts
import { createClient } from 'redis';

const redis = createClient();

export async function cacheMiddleware(req, res, next) {
  const key = `cache:${req.url}`;
  const cached = await redis.get(key);

  if (cached) {
    return res.json(JSON.parse(cached));
  }

  res.sendResponse = res.json.bind(res);
  res.json = async (data) => {
    await redis.setEx(key, 300, JSON.stringify(data)); // TTL 5 min
    res.sendResponse(data);
  };

  next();
}
Note

Always set an appropriate TTL. Stale caches can cause data inconsistencies.

Warning

Never cache responses containing user-specific private data.

Database Optimization

Avoiding N+1 Queries

The classic N+1 problem: fetching users then querying orders for each user separately.

-- ❌ Bad: N+1 pattern
SELECT * FROM users;
-- Then for each user:
SELECT * FROM orders WHERE user_id = ?;

-- ✅ Good: single JOIN
SELECT u.*, o.*
FROM users u
LEFT JOIN orders o ON o.user_id = u.id;

Indexing

Always index columns used in WHERE, JOIN, and ORDER BY:

CREATE INDEX idx_orders_user_id ON orders(user_id);
CREATE INDEX idx_orders_created_at ON orders(created_at DESC);

Payload Compression

Enable compression in your Express server:

import compression from 'compression';
import express from 'express';

const app = express();
app.use(compression({ level: 6 })); // Gzip level 6
Tip

For APIs serving large JSON payloads, Brotli (br) achieves ~20% better compression than Gzip.

Rate Limiting

Protect your API from abuse using express-rate-limit:

import rateLimit from 'express-rate-limit';

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100,                  // 100 requests per window
  standardHeaders: true,
  legacyHeaders: false,
});

app.use('/api/', limiter);

Checklist

  • Enable response caching (Redis)
  • Add database indexes on hot columns
  • Enable Gzip/Brotli compression
  • Add rate limiting middleware
  • Migrate to HTTP/2
  • Benchmark with k6 or Artillery

Conclusion

Performance is a feature, not an afterthought. Start with caching and proper indexing — these give the biggest wins with the least effort.