Where the Time Was Actually Going
The instinct when an API feels slow is to blame the framework and start planning a rewrite. Before we let a client commit to that, we profile — and almost every time, the real cost is a handful of N+1 queries, missing indexes, and payloads shipping fields nobody on the frontend was using.
On this particular project, three endpoints accounted for 80% of total response time across the whole API. That’s where we spent the sprint.
The Changes That Actually Moved the Number
- Eager-loading relations that were previously triggering a query per row in a loop.
- Adding composite indexes matched to the actual query patterns in production, not the ones we assumed.
- Trimming response payloads to only the fields the frontend actually consumed, verified against real traffic.
No Framework Change, No Rewrite
None of this required touching the framework or rewriting a single service. The 60% improvement came entirely from understanding where the actual bottlenecks were instead of guessing. A rewrite would have taken a quarter and carried real risk; this took a sprint and shipped with zero downtime.