The System Design Newsletter

The System Design Newsletter

What You Need to Master (And Avoid) to Build Fast, Reliable, and Scalable APIs

#165: Nine Tips for High-Performance APIs

Neo Kim's avatar
Neo Kim
Jul 29, 2026
∙ Paid

Get my system design playbook for FREE on newsletter signup:

  • Share this letter & I’ll send you some rewards for the referrals.


How do you speed up your API?

Every request requires work…Parse the payload, query the database, package the response, then send it back. i.e., each step takes time…

As traffic increases, these tiny delays add up:

  • Servers struggle under load,

  • Users wait longer for responses,

  • Costs increase as you add more machines.

The solution is NOT to write faster code.

Instead, build smarter systems that do less work, handle more traffic, and stay fast under pressure.

Let’s dive into proven ways to build high-performance APIs…

§

Turn your ideas into interactive prototypes in mins (Partner)

Everybody has product ideas…

But the HARD part is turning them into something people can click, test, and give feedback on before you spend weeks building it.

This is where Figma Make comes in…

With Figma Make, you can turn ideas or existing Figma designs into realistic, interactive prototypes to explore user flows, validate concepts, and iterate faster.

Here’s what you can do:

  • Turn ideas into clickable prototypes in minutes.

  • Explore different user flows before development.

  • Create realistic interactions for usability testing.

  • Iterate quickly inside Figma using prompts.

Whether you’re a designer, PM, founder, or engineer, Figma Make helps you move from concept to a testable prototype much faster.

Try Figma Make Today

(Thanks to Figma for partnering with this newsletter.)

§

Here’s what’s inside this newsletter:

  • Why latency grows even when your code is efficient. The real bottlenecks hiding in databases, networks, and downstream services, and why scaling an API is mostly about reducing unnecessary work.

  • The architecture patterns behind high-performance APIs. What caching, asynchronous processing, connection pooling, load balancing, rate limiting, and circuit breakers each solve, and why production systems combine them instead of relying on one optimization.

  • Every optimization has a failure mode. Why stale caches, pool exhaustion, retry storms, payload bloat, and poorly tuned autoscaling can reduce reliability while trying to improve performance.

  • Your API is only as fast as its slowest dependency. Why databases, external services, network round trips, and inefficient payloads usually dominate end-to-end request latency, long before your application code becomes the bottleneck.

  • Nine prompts to review your API architecture. Audit latency bottlenecks, database access, caching strategy, scaling readiness, observability, and resilience to identify high-impact performance improvements before traffic exposes weak points.

Golden members get all letters like these!…

§

1. Caching and compression

If responses didn’t change, you should STOP recomputing them.

This is the core idea behind caching: store responses so you can reuse them later. This skips expensive operations such as database queries, data manipulation, and/or API calls.

Here’s how it works:

  1. Your API receives a request X for the first time

    • It does the usual steps: parse, query the database, package it into a response Y, and send the response

    • Right before/after sending, it stores Y somewhere in-memory; Y is now a cached response to request X

  2. Your API receives a request X for the second time

    • It checks the cache first and sees that the response Y is already there, so it returns it; this is a cache hit

    • It’s a lot faster because there were NO database queries, API calls, or data manipulation

  3. But what happens when the response to X is no longer Y?

    • If the cache serves outdated data, your users see stale results (this is bad)

    • Your API needs to remove the stale data and update it with a fresh copy; this is called cache invalidation

    • There are different techniques for invalidation: time-to-live (TTL), manual removal, cache-control headers

Read through cache

Caching is useful for data that does NOT change often.

Think of requests like profile lookups or product catalog searches. Popular implementations are in-memory caches (Redis, Memcached) and edge caches (Fastly, Cloudflare).

Downsides of caching

  • Stale data: cache can serve outdated responses if invalidation is not managed well

  • Complexity: invalidation logic adds extra logic when to remove/refresh entries

  • Hard to debug: behavior depends on timing, not just code logic

“There are only two hard things in computer science: cache invalidation & naming things.” -- Phil Karlton

Compression explained

If the responses are too BIG, then make them smaller.

This is the core idea behind compression: shrink the payload before sending it over the network. It removes redundancy, such as repeated characters or formatting. A smaller, but equal result travels faster & uses less bandwidth.

Here is how it works:

  1. Your API and the client agree on which compression format to use

    • This process often happens through the Accept-Encoding and Content-Encoding HTTP headers

    • For example, a client requests Accept-Encoding: gzip, and the API replies with Content-Encoding: gzip

  2. Your API prepares the response data Y

    • Before sending, it runs Y through a compression algorithm

    • This makes Y smaller, so it uses less network bandwidth & gets sent faster

  3. The smaller, compressed version of Y gets sent over the network

  4. Client receives this compressed version of Y

    • Before using it, the client runs the response through a decompression algorithm

    • This makes it grow to its original size again

Compression works well for large JSON/binary responses.

Some popular compression formats are Gzip and Brotli. Other options are using Protobuf or Avro formats that reduce payload size by design.

Downsides of compression

  • CPU cost: each encode/decode cycle consumes processing power

  • Only helpful for large payloads: best used when responses exceed 1KB

  • Diminishing returns: for small responses, CPU cost could outweigh network savings

Takeaway

  • Caching avoids recomputation and saves processing time, but adds memory cost and invalidation complexity.

  • Compression reduces payload size and network latency, but increases CPU usage.

Both speed your API when used selectively & measured against their tradeoffs.

§

2. Load balancing and autoscaling

How do you keep your API fast as demand grows?

Every request your API gets is a “job”.

As traffic grows, one machine can’t do it all. The system slows down, queues form, and users wait. Adding more servers helps, but only if you can share the work and manage them properly.

This is what load balancing & autoscaling do.

Share

Load balancing explained

If one server is busy, you should route new requests to other servers.

That’s the key idea behind load balancing. It spreads incoming traffic across many servers so NO single one gets stuck doing all the work. It’s like a traffic cop directing cars to open lanes.

Here’s how it works:

  1. Your API receives a request

  2. The load balancer sits in front of all servers and decides where it goes

  3. It checks which servers are healthy & how busy they are

  4. Load balancer sends the request to the best option

  5. That server handles it and returns the response

Load balancing makes your system faster and more reliable.

If one server fails or gets overwhelmed, others take over. Load balancing is great for web APIs, microservices, and high-traffic systems. You rarely build one yourself, but use existing solutions.

Some popular implementations are AWS ELB, HAProxy, and Nginx.

Downsides of load balancing

  • Setup overhead: adds configuration & management work

  • Single point of failure: can become one without “redundancy”

  • Session problems: stateful sessions break when requests go to different servers

  • Extra complexity: sticky sessions/shared storage fix sessions, but add complexity

Autoscaling explained

If servers can’t keep up, you shouldn’t add more manually; let the system do it for you.

This is the idea behind autoscaling. It adds/removes servers automatically when the load changes. It’s like calling in extra chefs when a restaurant gets a rush of orders, then sending them home when it quiets down.

Here’s how it works:

  1. System tracks metrics such as CPU, memory, and/or request rate

  2. When traffic gets high, it adds more servers based on pre-defined rules

  3. New servers join & start taking requests

  4. When traffic drops, extra servers get shut down

  5. The system stays stable & doesn’t waste money

Autoscaling is common in systems with unpredictable workloads & traffic spikes.

Popular tools are Kubernetes HPA & AWS Auto Scaling Groups.

Downsides of autoscaling

  • Rule sensitivity: triggering too early wastes resources, while triggering too late hurts performance

  • Startup delays: slow server startup affects performance during scaling

  • Configuration work: requires tuning trigger rules & thresholds

Takeaway

Load balancing spreads work across servers & prevents overloading.

Autoscaling adds/removes servers in the system and manages system capacity. Together, they make APIs faster, stable, and ready for traffic changes.

§

3. Asynchronous processing

How do you keep your API responsive when some tasks take a long time?

Tasks like sending emails, reading files, or calling services spend a lot of time waiting for input/output (IO).

During the wait, the server isn’t using the CPU efficiently. If your API waits for these long tasks to finish, users experience slow response time. Asynchronous processing solves this problem. It lets the API respond immediately while heavy tasks run in the background.

Here’s how it works:

  1. API receives a request that triggers an IO-bound task

  2. Instead of processing it right away, it puts a message in a queue

  3. The API responds to the client immediately with a job ID/status

  4. Background workers read from the queue and process tasks independently

  5. Workers notify the client when the job is done (OPTIONAL)

It’s like placing an order at a restaurant and receiving a buzzer:

You can keep doing other things while the kitchen finishes your meal, and the restaurant keeps serving new customers.

Asynchronous processing is ideal for high-traffic systems, unpredictable workloads, or slow IO tasks. It decouples request handling from heavy work, keeping APIs fast and responsive.

Popular tools are RabbitMQ, Kafka & Celery.

Downsides of asynchronous processing

  • Increased complexity: must manage queues, workers, retries, and error tracking

  • Harder debugging: execution happens outside the main request flow

  • Failure handling: workers that fail need to retry/re-queue tasks

  • Limited CPU benefit: offers little help for CPU-bound work where waiting isn’t the problem

Takeaway

Asynchronous processing keeps APIs responsive by offloading slow IO tasks to background workers.

It trades simplicity for scalability, making systems faster under load but harder to monitor and debug.

§

Reminder: this is a teaser of the subscriber-only newsletter, exclusive to my golden members.

When you upgrade, you’ll get:

  • High-level architecture of real-world systems.

  • Deep dive into how popular real-world systems work.

  • How real-world systems handle scale, reliability, and performance.

Unlock Full Access

Ready for the best part?

Keep reading with a 7-day free trial

Subscribe to The System Design Newsletter to keep reading this post and get 7 days of free access to the full post archives.

Already a paid subscriber? Sign in
© 2026 Neo Kim · Publisher Privacy
Substack · Privacy ∙ Terms ∙ Collection notice
Start your SubstackGet the app
Substack is the home for great culture