Three seconds is an eternity in live TV
Three seconds. That was how long users waited every time they clicked something in the Cuez application. Three seconds to load a show rundown. Three seconds to pull up a guest list. Three seconds to check the live event schedule.
For a SaaS product used during live television broadcasts, where every second of dead air matters, that kind of delay was not an irritation. It was a business problem, and the kind that has a name: API performance optimization. Users were frustrated. The client was worried about churn. The team had already tried the obvious fixes without much success.
I was brought in as a senior engineer to lead the work. What followed was a systematic investigation that took the API from 3 seconds to 300 milliseconds — 10x faster — without rebuilding the application from scratch. Stack: Laravel, Vue.js, TypeScript, AWS, FFMPEG. Outcome: ~40% infrastructure cost reduction on top of the speed win. The full case write-up lives in the Cuez API optimization case study.
This article walks through how I did it, step by step. If your product's backend feels sluggish and you are not sure where to start, treat this as the playbook.
TL;DR
- The problem: A B2B SaaS product (Cuez by Tinkerlist) had API response times averaging 3 seconds, frustrating users and threatening retention.
- The approach: Full codebase audit to find hidden performance drains: unused libraries, outdated dependencies, custom code that duplicated framework features, and unoptimized database queries.
- The result: API response times dropped to 300ms (10x faster), infrastructure costs fell by roughly 40%, and the platform gained capacity to handle far more concurrent users.
- Key insight: The biggest performance gains came from removing things, not adding them. Stripping unused code and replacing hand-built solutions with framework built-ins delivered more impact than any single optimization technique.
Table of contents
- The problem: a 3-second API in a real-time product
- Step 1: the full codebase audit
- Step 2: removing unused and outdated libraries
- Step 3: replacing custom code with framework built-ins
- Step 4: optimizing database queries
- Step 5: reducing the dependency footprint
- Step 6: the framework upgrade
- The results
- What this means for your business
- Reflecting on what compounded the win
- FAQ
- Conclusion and next steps
The problem: a 3-second API in a real-time product
Cuez is a SaaS product built by Tinkerlist, a company based in Belgium. The platform helps television producers manage live shows. Rundowns (the sequence of segments in a broadcast), guest coordination, timing sheets, real-time updates during live events.
The product was built on Laravel (a popular PHP framework) with a Vue.js frontend, running on AWS, with FFMPEG handling media work. Architecturally sound choices. Over time, though, the codebase had accumulated what engineers call technical debt — shortcuts and workarounds that quietly slow things down over the long run.
By the time I joined: average API response time was 3 seconds, some endpoints worse. The frontend felt sluggish waiting on data. (For context, Google's research on user-perceived performance puts the threshold for "feels broken" right around 1 second of waiting.) Previous optimization attempts (a cache here, a query tweak there) had delivered marginal improvements. The team had tried point fixes. What they had not done was look at the full picture.
Step 1: the full codebase audit
Before changing a single line of code, I spent time understanding the entire system. This is the part most teams skip. It is also the most important part.
What a codebase audit actually looks like
A codebase audit is like a health checkup for your software. Instead of blood pressure and cholesterol, you are checking: how many external libraries does the application depend on? Are they still maintained? Is the application using its own framework effectively, or did developers build custom versions of things the framework already provides? How does data flow from the database to the user's screen? What gets loaded on every single request, even when it is not needed?
I mapped the dependency tree — a complete list of every external package the application relied on. I profiled API requests to see where time was being spent. I read through the code to understand why certain architectural decisions had been made.
What I found
The picture that emerged was not a single catastrophic problem. It was death by a thousand cuts. Dozens of small inefficiencies, each adding 50 or 100 milliseconds, compounding into that 3-second response time.
A simplified breakdown of where those 3 seconds were going:
| Time sink | Approximate impact |
|---|---|
| Unused libraries loaded on every request | ~400ms |
| Custom code doing what the framework already handles | ~500ms |
| Unoptimized database queries | ~800ms |
| Outdated dependencies with known performance issues | ~300ms |
| Excessive dependency chain (libraries loading other libraries) | ~600ms |
| Other overhead (serialization, middleware, etc.) | ~400ms |
No single item was "the problem." All of them were. That is exactly why point fixes had not worked. Optimizing one query saves 100ms, but when the whole stack is adding drag, you need a systemic approach.
Step 2: removing unused and outdated libraries
The first thing I did was the simplest. I removed code that was not doing anything.
The library graveyard
Over the life of any software project, developers add libraries to solve specific problems. A charting library for a feature that was later redesigned. A date formatting package that was replaced by a better one but never removed. A debugging tool that was only needed during development but got bundled into production.
In the Cuez codebase, I found over a dozen packages that were either no longer used anywhere, had been replaced by something else but never fully removed, or were only used in one small place and could be replaced with a few lines of native code.
Why unused libraries hurt performance
If a library is not being used, how can it slow things down? In PHP, the language Laravel is built on, there is a mechanism called autoloading that registers every installed package so it is available if needed. More packages means more registration work on every request. And libraries have their own dependencies. Removing one library might also remove three others it was pulling in.
Think of it like a kitchen with counters cluttered by appliances you never use. Clearing the counter does not make your stove hotter, but it makes everything you do in that kitchen faster. (You also stop knocking over the toaster every time you reach for the salt.)
The impact
Removing unused and outdated libraries cut roughly 400 milliseconds from every API request. Not because any single library was that slow, but because the cumulative overhead of loading, registering, and managing dozens of unnecessary packages adds up.
Step 3: replacing custom code with framework built-ins
This was the most impactful single step, and it is a pattern I see in nearly every project I audit.
The problem with reinventing the wheel
Laravel is a mature framework with built-in solutions for most common backend tasks: caching, queue management, data serialization (converting database records into the format your browser expects), authentication, and more. When developers are under deadline pressure, they sometimes build custom solutions for problems the framework already solves. Not bad engineering. Usually just tight timelines and imperfect knowledge.
In the Cuez codebase, I found several areas where custom code was doing jobs that Laravel handles natively:
- Custom data transformation logic where Laravel's built-in API Resources would have been faster and more maintainable.
- Hand-rolled caching that did not use Laravel's cache layer, which integrates directly with Redis (a high-speed in-memory data store).
- Custom middleware (code that runs on every request) duplicating functionality already in the framework.
- Manual query construction where Laravel's query builder would have been more efficient.
Framework maintainers spend years optimizing these tools. A custom solution built under a deadline almost never matches that level of optimization. Framework built-ins are also tested against edge cases across thousands of applications.
The refactoring process
I replaced custom implementations one endpoint at a time, starting with the highest-traffic API routes. For each: document current behavior, rewrite using framework tools, test against the original to verify identical output, measure the improvement. Methodical, endpoint-by-endpoint work over several weeks. The results were consistent.
The impact
Replacing custom code with framework built-ins shaved approximately 500 milliseconds off API response times. It also made the codebase significantly easier to maintain, which matters for the long-term health of the product. If you want a deeper take on which framework choices age well, see my piece on the best backend framework for a scalable startup.
Step 4: optimizing database queries
The database is where most API performance problems live. Cuez was no exception.
N+1 queries: the silent killer
The single biggest database issue was something called an N+1 query problem. Plain language:
Imagine you have a list of 50 TV shows. For each show, you need to load its segments, guests, and timing data. A naive approach:
- Run 1 query to get all 50 shows.
- Run 1 query per show to get its segments (50 queries).
- Run 1 query per show to get its guests (50 queries).
- Run 1 query per show to get its timing data (50 queries).
That is 151 database queries for what should be 4 queries — one per data type, using a technique called eager loading that fetches related data in bulk.
Each individual query might take only 10 to 20 milliseconds. But 151 of them? That is 1.5 to 3 seconds, just in database time.
Missing indexes
A database index is like the index in a book. Without it, the database has to read every single row in a table to find what it is looking for (a full table scan). With an index, it jumps straight to the relevant data.
Several frequently queried columns in the Cuez database were missing indexes. Every time the API needed to look up shows by date, or filter segments by type, the database scanned the entire table. Adding indexes turned queries that took 300 to 400 milliseconds into queries that took 10 to 20 milliseconds.
Google's web.dev guide on backend optimization is blunt about this: most user-perceived latency in a web application sits in two places, the database and the network. Cleaning up the database is usually the highest-impact move.
Over-fetching data
Some endpoints loaded entire records when they only needed a few fields. I rewrote key queries to select only what was needed and added pagination where endpoints were returning entire datasets instead of manageable pages.
The impact
Database optimizations collectively removed approximately 800 milliseconds from API response times. The N+1 fix alone was worth hundreds of milliseconds. The efficiency gains also meant the database server was doing less work overall, which freed capacity for growth.
The same database-first approach was the core of the Imohub real-estate portal case study: 120k+ properties, sub-500ms query response, 70% infrastructure cost reduction.
Step 5: reducing the dependency footprint
After removing unused libraries in Step 2, there was still more to trim.
Direct vs. transitive dependencies
When you install a library, it often brings along its own dependencies, which bring their own. One popular PHP package might pull in 15 others you never directly chose. I mapped the full dependency tree and found many of these transitive dependencies (the ones your dependencies depend on, like friends of friends) were duplicating functionality, locked to outdated versions, or far heavier than necessary.
The fix: replace parent libraries with lighter alternatives, configure packages to share underlying dependencies instead of duplicating them, and inline small functions instead of loading large libraries for 20 lines of code.
The impact
Reducing the dependency footprint removed roughly 600 milliseconds from total overhead and shrank the application's deployment size.
Step 6: the framework upgrade
The final step was upgrading Laravel itself, from an older version to a current major release.
Why framework versions matter
Framework upgrades are not just about new features. Each major version includes performance improvements in the core engine, optimized database layers, better caching mechanisms, and updated language version support — which means access to language-level speed gains. The newer Laravel I moved to specifically improved model serialization and route resolution, both of which directly affect API response times.
The upgrade process
I audited breaking changes, updated all dependencies for compatibility, ran the full test suite, benchmarked performance before and after, and deployed through a staged rollout (test environment first, then production). The upgrade also forced removal of deprecated patterns, further cleaning up the codebase.
The impact
The framework upgrade, combined with the PHP version bump it enabled, contributed to the remaining performance gains and provided a modern, well-supported foundation for future development.
The results
After completing all six steps:
| Metric | Before | After | Improvement |
|---|---|---|---|
| Average API response time | 3,000ms | 300ms | 10x faster |
| Database queries per request (typical) | 100–150+ | 5–15 | ~90% fewer |
| External dependencies | Dozens of unused/redundant packages | Clean, minimal dependency tree | ~40% reduction |
| Infrastructure cost | Baseline | ~40% lower | Server resources freed up |
| Concurrent user capacity | Limited | Significant headroom | Scalability gain |
The 10x improvement was not the result of one clever trick. It was the compound effect of systematically eliminating inefficiencies across the entire stack.
Timeline
The full optimization project took roughly 8 to 10 weeks, working alongside the existing development team. Improvements rolled out incrementally. Users started feeling the difference within the first few weeks as individual endpoints were optimized.
What this means for your business
If you are a founder or business leader reading this, here is what this case illustrates.
Speed is a retention problem
Users do not file bug reports when an application is slow. They use it less, switch to a competitor, or cancel their subscription. Slow software erodes trust in ways that only show up later in your churn numbers. McKinsey's work on customer experience economics consistently finds that consistency of experience matters more than peak moments. Slow loads ruin consistency. The signs are usually visible earlier — see 5 signs your web app has a performance problem.
The fix is usually not a rebuild
The instinct when software is slow is often "we need to rebuild it." That is almost always wrong, and it is the most expensive option. In Cuez's case, the architecture was sound. The problem was accumulated cruft. Cleaning house was faster, cheaper, and less risky than starting over. For the wider take on when to optimize vs. rebuild, see how to fix a slow website without rebuilding it and the website speed optimization guide.
Performance work pays for itself
The ~40% infrastructure cost reduction alone justified the investment. The real value, though, was in user retention and headroom for growth. A product that responds in 300ms feels modern. One that takes 3 seconds feels broken.
You probably have similar problems
If your web application has been in development for more than a year with multiple developers contributing, there are almost certainly unused dependencies, duplicated framework functionality, and unoptimized queries hiding in the codebase. These are not edge cases. They are the norm.
If you want senior engineering oversight without a full-time hire, fractional CTO is usually the most cost-effective way in.
Reflecting on what compounded the win
The single biggest mental shift, looking back, was treating performance as a system property instead of a checklist of tricks. The team had already tried the tricks. None of them moved the needle on their own. What worked was insisting on the full picture before touching anything (the dependency tree, the query patterns, the framework usage, the request lifecycle) and then changing things in a sequence that made each later change easier than it would have been on its own.
There is a discipline lesson tucked inside the engineering one. Most slow systems are slow because nobody owned the speed metric. New features had owners. Outages had owners. Latency was everyone's problem and therefore nobody's. The Cuez fix held because a senior engineer (me, in that case) took a clear position: this number matters, here is what it should be, here is the order I work in.
For founders the takeaway is simple. Pick the metric, name an owner, set a budget, and revisit it on a known cadence. The technical methodology (audit, remove, replace, optimize) is portable. The discipline is the part you actually have to install. My piece on performance budgets for founders covers how to keep it in place after the consultant has left the building.
FAQ
How do I know if my API has a performance problem?
If users mention slowness, that is the most reliable signal. On the technical side, API response times above 500 milliseconds for standard data-fetching endpoints usually indicate room for improvement. Tools like New Relic, Datadog, or Laravel Telescope can show you exactly how long each request takes and where the time is spent. My guide to measuring website performance walks through the tooling.
Can't I just add more servers to fix slow API responses?
Throwing hardware at a software problem is expensive and temporary. If your code runs 151 database queries when it should run 4, doubling your server capacity does not fix the root cause — it just delays the cliff. Optimize the code first, then scale the infrastructure.
How much does API performance optimization cost?
For a typical mid-size SaaS application (10 to 50 API endpoints, one database, standard framework), expect $15K to $40K for a thorough audit and optimization. The return (retained users, reduced infrastructure cost, improved conversion) usually pays back within 3 to 6 months.
Does this approach work for frameworks other than Laravel?
The principles are universal. Every framework (NestJS, Next.js, Express, Vue, React) has built-in tools that teams under-use. Every codebase accumulates unused dependencies. Every database can be queried more efficiently. The methodology applies everywhere: audit, remove, replace, optimize. See API integration for the same pattern in a different context.
How is this different from a full application rewrite?
A rewrite means starting from scratch — months of development before you are back to feature parity. The approach I used at Cuez preserved the existing application, its features, and its data. The product kept running and improving throughout the process, with zero downtime for users.
What role does a fractional CTO play in performance optimization?
A fractional CTO brings the experience to diagnose these problems quickly and the authority to prioritize fixing them. Performance work often gets deprioritized in favor of new features — until users start churning. A senior technical leader who understands both the engineering and the business case makes sure it actually gets done.
How long does it take to see results?
Individual endpoint optimizations show results immediately. A full codebase optimization project like Cuez typically takes 6 to 12 weeks, with incremental improvements visible throughout.
Conclusion and next steps
The Cuez project is a pattern I see repeated across the SaaS products I work on. Applications start fast, accumulate technical debt over time, and gradually slow down as unused libraries pile up, custom code proliferates, and database queries go unexamined. The good news is that these problems are fixable — systematically, methodically, and without rebuilding from scratch.
If your application is slower than it should be:
- Measure first. Get actual numbers on API response times, not just user impressions.
- Look at the full picture. Audit the entire stack — dependencies, custom code, database patterns, framework utilization.
- Prioritize by impact. Start with the highest-traffic endpoints.
- Consider a professional audit. An outside perspective often finds things internal teams have become blind to.
I have optimized backend systems for 250+ projects over 16 years. If your API response times are holding your product back, book a free strategy call and I will tell you what a focused engagement would look like.