01.Finding the Bottleneck First
Never optimize blind. Before touching code, instrument your API with APM tooling (Datadog, New Relic, or even simple response time middleware). Profile your database queries. 80% of performance issues come from 20% of your endpoints — usually the ones hitting the database without indexes or caching.
02.Database Query Optimization
The most impactful optimization is almost always at the database layer. Add composite indexes for common query patterns. Use EXPLAIN ANALYZE to find sequential scans. Avoid N+1 queries by eager-loading relations. Paginate large result sets. Select only the columns you need — don't SELECT *.
-- Before: sequential scan, 340ms
SELECT * FROM documents WHERE user_id = $1 ORDER BY created_at DESC;
-- After: composite index, 4ms
CREATE INDEX idx_documents_user_created
ON documents(user_id, created_at DESC);03.Redis Caching Strategy
Cache aggressively for read-heavy data that changes infrequently — user profiles, configuration, feature flags, aggregated stats. Use cache-aside pattern: check Redis first, fall back to DB on miss, populate cache. Set TTLs based on acceptable staleness, not arbitrary values.
async getUserProfile(userId: string) {
const cacheKey = `user:profile:${userId}`;
const cached = await this.redis.get(cacheKey);
if (cached) return JSON.parse(cached);
const user = await this.userRepo.findOne({ where: { id: userId } });
await this.redis.setex(cacheKey, 300, JSON.stringify(user));
return user;
}04.Connection Pooling
Creating a new database connection per request is expensive — each connection takes 5–50ms to establish. Use connection pooling (pg-pool for PostgreSQL, Mongoose connection pool for MongoDB). Configure pool size based on your RDS instance limits. Redis connections should also be pooled via ioredis cluster mode for high-throughput workloads.
05.Results After Optimization
After implementing composite indexes, Redis caching for hot paths, and connection pooling: average API response time dropped from 280ms to 45ms. P99 latency went from 1.2s to 12ms. Database CPU utilization dropped by 60%. These weren't exotic optimizations — they were fundamentals applied correctly.