Find the constraint before changing the architecture. Clear data ownership and visible operations are useful at every stage.
Describe the pressure you expect
“It needs to scale” is not yet a requirement. A reporting platform may be limited by expensive queries, while a document service spends most of its time waiting for external processing. Estimate the important workload: concurrent activity, record sizes, request patterns, and acceptable delays for specific tasks.
Use those estimates to choose what to measure first. Keep the initial architecture understandable. Splitting an application into services introduces network failures, deployment coordination, and data consistency questions; it does not automatically remove the original bottleneck.
Follow one request through the system
For a document export, trace authorization, query execution, file generation, and delivery separately. If file generation is slow but can happen later, a background job may be appropriate. The user needs a visible job state and a reliable way to retrieve the result, not a request that hangs indefinitely.
A queue separates the interactive request from longer work, but it adds responsibility. Workers need bounded retries, failure handling, and a way to recognize repeated work. The diagram below is an example architecture, not a requirement for every backend.
- Authorize request
- Record export job
- Worker generates file
- User retrieves result
Investigate before adding capacity
Collect evidence at the point where time is being spent. A larger server will not resolve every slow query or repeated external call.

Swipe the table to compare all columns →
| Symptom | Check first | Possible response |
|---|---|---|
| Slow list pages | Query plan, row counts, pagination | Fix access patterns and assess indexes |
| Request timeouts | External calls and long-running work | Use explicit timeouts or background processing |
| Duplicate actions | Retry behavior and request identity | Design idempotent operations |
| Unpredictable failures | Resource limits and dependency errors | Add bounded concurrency and useful telemetry |
Treat data changes as releases
Changing a data model affects old records, running application versions, and integrations. Plan compatibility before deploying. A staged change can add a new field, migrate existing records, and remove the old dependency only after readers and writers have moved.
In PostgreSQL, EXPLAIN shows the query plan and can help investigate access patterns. Use representative data and understand the difference between inspecting a plan and actually running a statement with EXPLAIN ANALYZE. Production investigation deserves the same care as a release.
Know whether the change helped
Compare latency, errors, and resource use under a representative workload before and after the change. Tail latency matters: a reasonable average can hide a painful experience for some users. Include recovery behavior in the review, not just throughput.
Keep a short record of the constraint, the evidence, and the result. Scaling becomes easier when architectural decisions are tied to observed product needs. The aim is dependable service as demand changes, with enough visibility to know what to improve next.

