← Case Studies

A SaaS Dashboard's API Latency Was 487ms. We Brought It to 28.

A B2B analytics platform with 35K daily active users, a five-person engineering team, and a dashboard that deserved to be faster.

The Waiter of Gold Lapel · Updated Mar 20, 2026 Published Mar 5, 2026 · 6 min read
One does not keep a VP waiting. That is how support tickets are born.
487ms P95 latency (before)
28ms P95 latency (after)
94% Latency reduction
0 Code changes

The challenge

The platform provides analytics dashboards to mid-market B2B companies — the kind of dashboard a VP of Sales opens every morning to review pipeline metrics, deal velocity, and team performance. Each page load triggers 6-8 API endpoints, each running queries that join activity logs, user records, subscription tiers, and billing history.

At launch, with 5K users, the dashboard loaded in under 200ms. Perfectly adequate. At 35K daily actives, the same dashboard had developed a 487ms P95 latency — and the P99 was touching 1.2 seconds. The kind of latency that makes a VP refresh the page, then open a support ticket.

The engineering team — five developers, no dedicated DBA — had correctly identified the database layer as the bottleneck. The Django ORM was generating reasonable queries, but those queries were scanning millions of rows across joins that had grown expensive as the dataset scaled. The team estimated four to six weeks to manually add materialized views, refactor the most expensive aggregations, and implement a cache invalidation strategy.

They had four weeks of product roadmap already committed. Six weeks of optimization work was not available.

The setup

Gold Lapel was deployed as a sidecar container in the existing Docker Compose stack. The only configuration change: the application's DATABASE_URL was pointed at the proxy instead of PostgreSQL directly.

# docker-compose.yml — the only change
goldlapel:
  image: goldlapel/goldlapel:latest
  command: --upstream 'postgresql://app:password@db:5432/saas_prod'
  ports:
    - "7932:7932"

# Point the app at the proxy instead of Postgres directly
environment:
  DATABASE_URL: postgresql://app:password@goldlapel:7932/saas_prod

Total deployment time: twelve minutes. The application was restarted once. No Django code was modified, no migration files were created, and no ORM queries were rewritten.

What happened next

Gold Lapel observed traffic for the first thirty minutes, building a profile of query patterns. Within the first hour, it had identified three query families responsible for 78% of database CPU time:

  • Deal pipeline aggregation — a five-table join grouping deals by stage, owner, and month, executed 2,400 times per hour across all tenants.
  • Activity timeline rollup — a three-table join counting user activities by type and day, with a WHERE clause that scanned 90 days of history on every request.
  • Revenue by segment — a four-table join computing MRR breakdowns by plan tier and cohort, running 800 times per hour.

For each pattern, Gold Lapel created a PostgreSQL materialized view, rewrote incoming queries to read from the view, and established a write-aware refresh schedule. The views refreshed only when the underlying tables received writes — not on a fixed timer — keeping them fresh without wasting cycles.

The results

Query patternBefore (P95)After (P95)Improvement
Deal pipeline aggregation487ms18ms96%
Activity timeline rollup312ms28ms91%
Revenue by segment224ms14ms94%
Overall dashboard P95487ms28ms94%

Database CPU utilization dropped from 72% to 31% during peak hours. The compound effect: queries that Gold Lapel did not directly optimize also became faster, because PostgreSQL had more resources available.

What the team noticed

  • No query changes were required. The team added a Gold Lapel container to their docker-compose.yml and pointed DATABASE_URL at it. The Django ORM continued generating the same queries. The proxy transparently redirected them to materialized views.
  • The views maintained themselves. When the team shipped a new dashboard widget two weeks later, Gold Lapel detected the new query pattern and created a fourth materialized view within the hour. When they deprecated an old widget, the proxy noticed the pattern disappeared and dropped the corresponding view after its TTL expired.
  • Support tickets about dashboard speed stopped. The VP of Sales stopped refreshing the page. The support team stopped escalating performance complaints. The engineering team did not spend six weeks rewriting queries.
  • The cost was $49/month per database. The alternative — six engineer-weeks at fully loaded cost — would have been approximately $45,000 in opportunity cost, plus ongoing maintenance.

Key takeaways

  • Small teams benefit most. A five-person team cannot afford to dedicate an engineer to database optimization for six weeks. Automation closes the gap between what needs to happen and what the team has capacity for.
  • The problem compounds. Dashboard latency was growing every month as the dataset grew. Without intervention, the 487ms would have become 800ms within two quarters. Materialized views arrested the growth because they precompute the aggregation regardless of table size.
  • Transparent proxies are operationally simple. One environment variable change. No ORM modifications, no migration files, no feature flags. The blast radius of deployment was zero — if the proxy had any issue, removing it would restore the original connection path.

Terms referenced in this article

The N+1 detection that drove most of the latency improvement here has been benchmarked independently. The N+1 query detection benchmark measures the exact throughput gain from batching ORM-generated query patterns at the wire protocol level — the numbers behind the 487ms-to-28ms story.