It used to be fast

When the app launched, every page loaded instantly. That was with a few thousand records and a handful of customers. Now there are millions of rows, customers with years of history, and reports nobody imagined in the first version. The dashboard takes eight seconds. An export times out. The database server sits at high CPU all afternoon and nobody is quite sure which part of the app is doing it.

This is a good problem to have. It means the business worked. Your team built something people use more and more, and the code they wrote was right for the size it was. It just wasn’t written for the size it is now.

The usual response is to buy a bigger server. That helps for a few months, costs more every month, and leaves the real cause in place.

What I do: measure first

I don’t change anything until I know where the time goes. Guessing at performance is how teams spend a month on a cache that saves forty milliseconds while the real problem sits elsewhere.

Every change gets a before and after number. If a change doesn’t move the number, it comes back out.

MeasureAPM, slow-query logFind the causeEXPLAIN ANALYZE,N+1s, indexesChange one thingMeasure againbefore vs afterPerformance notesnumbers written down next slowest
Figure 1. The performance loop. Measure, find the cause, change one thing, measure again, write it down.

Numbers, written down

The point of this work is that your team understands what changed and can keep it fast. So everything goes into the repo:

You own all of it, along with any monitoring I set up.

Why me

For seven years I was a senior engineer on a multi-tenant B2B SaaS that grew from about $4M to $13M in annual revenue. I ran its roughly 1TB Postgres database, and I cut the company’s AWS bill by six figures a year, much of it by making the app do less work rather than buying more hardware. I’ve written about some of that on my writing page, including counting 800 million rows and tracking down 319 N+1 queries across a fleet of apps.

Take a business like this one

The business in this section is a composite of the kind of company I talk to, not a named client. The numbers are the shape of the problem, not a case study.

Picture a property management platform on Rails and Postgres, used by a few hundred management companies. The largest customers have tens of thousands of units and years of payment history. Their owner statements page takes twelve seconds, the monthly export fails for the three biggest accounts, and the database instance has been upsized twice in a year. Smaller customers are fine, so the team has trouble reproducing the problem.

What I’d do for a business shaped like this:

  1. Week one: measure. Turn on detailed tracing for the slow endpoints and the slow-query log, and copy a large customer’s data shape into a safe environment to reproduce it.
  2. Fix the statements page. In a case like this it’s usually an N+1 inside a loop over units, plus a missing composite index on payments. Measure after each change.
  3. Move the monthly export to a background job that emails a link when it’s done, so it can’t time out.
  4. Replace live totals on the payments table with a summary that updates as payments arrive.
  5. Tune Postgres for the real workload, and check whether the second upsize can be undone.
  6. Write it up. Performance notes with every number, runbooks, and AI-assistant instructions, so the team keeps it fast as the next large customer arrives.

The team keeps doing what they’re best at: building the features property managers ask for.

What it costs

It starts with a small fixed-price assessment: a week of measuring and a written report naming the slowest parts of your app, the likely causes, and what fixing each would take. Many teams fix the first few items themselves from the report. The work after that is scoped from what we find. No retainer, and no surprise invoices.

What I need from you

Access to the code, your APM or logs, and read access to production metrics. A copy of production data, or a sanitized one, to test against. A developer on your side to review changes and learn the tools. And your list of the pages customers complain about most, because that’s where we start.