Running it

Common SaaS Scaling Mistakes and How to Spot Them

Eight scaling mistakes we see in SaaS products, from buying a bigger database to tenant filters that rely on habit, with the early signal and the fix for each.

Illustration: four rising columns with an upward arrow, the third column cracked

Most scaling problems are decided long before the traffic arrives

A SaaS product rarely falls over because it became popular. It falls over because of a choice made when it had ten customers, which was reasonable then and is wrong now. Scaling is mostly the work of finding those choices before the load does.

This page lists eight mistakes, ordered roughly by how early they show up. For each one it gives the signal that you are in it, and the smaller fix that usually works before anything dramatic is needed. Where a point comes from a system we run ourselves, it says so. Where it is a rule of thumb, it says that too. None of this replaces measuring your own product, and several items depend on your database, your traffic shape and your team.

If your product is already straining and you want a second pair of eyes, our SaaS modernization and SaaS architecture review services exist for exactly that. Read the list first: it may save you the call.

Request path from browser to app servers, a queue and one shared database
App servers can be copied. The database is shared state, so every copy of the app ends up leaning on the same place. Most of the mistakes below are about that place.

1. Buying a bigger server before reading the queries

Scaling a database up is a legitimate first move and a poor only move. If every slow page is answered with more memory, the cause is usually underneath: a missing index, a query that loads a whole table to show ten rows, or a list endpoint with no limit.

The signal: the slowest pages get slower in proportion to the data, not the traffic. A page that took a moment with a thousand rows takes noticeably longer with a million, on the same server.

The fix: read the plan before you spend. PostgreSQL's EXPLAIN documentation shows how to see whether a query scans a whole table. Add the index that matches the filter and the sort, page every list on the server, and never return an unbounded result. Our own convention in the products we build is the same: only the requested page leaves the database.

2. Treating tenant separation as a habit

In a multi-tenant product, "every query remembers to filter by customer" is a convention. Conventions fail on the one route somebody forgot, usually an export or a background report, and the failure is a customer seeing another customer's data.

The signal: nobody can say where the tenant check happens. It is in the handlers, in the repository layer, in a helper, depending on who wrote the route.

The fix: make it structural. In the HR platform we are building in house, the tenant is part of the signed token and not the request, and relationships between records are composite with the tenant, so the database refuses a link from one employer's record to another's. That is cheap at the schema stage and close to unfixable once there is data, which is why it belongs on the list of things to settle before the first paying customer.

Two panels comparing tenant filters by convention with tenant rules built into the structure
The left side works until the day a new route skips the filter. The right side makes that mistake impossible to ship quietly.

3. Doing slow work inside the request

Sending an email, generating a PDF, importing a file or calling a third party inside the web request makes every user wait for the slowest step, and ties up a server process while they do. At low traffic nobody notices. At higher traffic the processes run out and unrelated pages stall.

The signal: response times spike when one feature is busy, and timeouts appear on pages that have nothing to do with it.

The fix: accept the request, record the job, answer quickly, and let a worker do the slow part. Two details decide whether this works. Jobs must be safe to run twice, because queues retry. And the user needs a visible state (queued, running, done), or the support inbox becomes the progress bar.

4. No idempotency on payments and webhooks

Networks retry, and so do payment providers. A webhook delivered twice, or a client that resubmits a payment on a timeout, must not charge or fulfil twice. Stripe documents the pattern in its guide to idempotent requests: the caller sends a unique key and the server returns the first result for a repeat.

The signal: a support ticket that says "charged twice" or "got two emails", even once.

The fix: store the event or request key with a unique constraint, check it inside the same transaction as the effect, and make the second arrival a harmless no-op. This is boring work that pays for itself the first time a provider has a bad hour.

5. Letting reports share a database with live traffic

A dashboard that scans a year of orders is a perfectly good query. Run on the same database that serves sign-ins, it is also a way for one customer's export to slow everyone else down.

The signal: the product is slowest when somebody runs a large report, typically in the morning or at month end.

The fix, in order of effort: limit and page exports, run heavy reads against a replica, and only then consider a separate analytics store. Most products need the first two for a long time.

6. Adding app servers without counting connections

Each app server holds a pool of database connections. Doubling the servers doubles the connections, and PostgreSQL limits them: the connection settings list max_connections with a default of 100. Past the limit, new requests fail, and more servers make it worse.

The signal: errors about too many connections appear right after a scale-out, when traffic was supposed to be easier to carry.

The fix: size the pools deliberately, keep transactions short so connections return quickly, and put a pooler in front of the database when the arithmetic stops working. This is the clearest example of the picture above: the part that does not copy is the part that sets the limit.

7. Splitting into services, or rewriting, too early

When something strains, the tempting move is a larger structure: microservices, or a rewrite from zero. Martin Fowler's MonolithFirst argues that you should usually start with a monolith and split when real seams appear, because services multiply deployment, monitoring and failure modes before they remove any.

The signal: the proposal arrives before anyone can name the specific limit it removes.

The fix: move in stages. Find the one component that genuinely needs independent scaling, give it a clean boundary inside the codebase first, and extract it only when the boundary has held. A rewrite stops feature work and has to rediscover every edge case the old system already handled. We say so on our modernization page, and we recommend a rewrite only when an assessment shows staged change would cost more.

8. Scaling without measuring, and without limits

Two gaps travel together. The first is no visibility: you learn about slowness from customers. Google's SRE book names four signals worth watching for any service, latency, traffic, errors and saturation. The second is no limits: one tenant, one script or one bug can consume everything. OWASP lists unrestricted resource consumption among its API security risks.

The signal: you cannot say what normal looks like, and nothing stops a single caller from asking for everything.

The fix: record the four signals before the next launch, and set per-tenant and per-key limits on expensive routes, uploads and exports. Our own tool platform shows the other side of the idea. Of its 132 tools, 114 do their work entirely in the visitor's browser and the other 18 call our server, and none of those takes a file. Keeping heavy work away from the shared server is a design decision, and it is the cheapest scaling there is.

A one-page check before you scale

You can answer most of this in an afternoon, without a vendor:

  • Slowest five queries: do you know them, and have you read their plans?
  • Connections: servers times pool size, against the database limit.
  • Slow work: which requests send email, build files or call another service while the user waits?
  • Retries: what happens if your payment webhook arrives twice?
  • Tenant rule: where, exactly, is it enforced, and what would a forgotten filter do?
  • Reports: what runs on the live database that does not need to?
  • Signals: can you see latency, traffic, errors and saturation without logging in to a server?

If three or more of these draw a blank, an independent look is likely to repay its cost. Signs your SaaS architecture needs an audit goes deeper on what a review should hand back, and SaaS development cost in India explains how that kind of work is sized and quoted.

How we approach it

We build and run our own products: KeyNesta, where the server stores ciphertext it cannot read, and MenuFly, a QR menu platform that renders a real mobile page instead of a PDF. They shaped the points above, as did the HR platform and the tool platform described earlier. They are not claims about your system, and we make no promise about the numbers you will reach. What we can say is how we work: assess first, change in stages, and give a written scope and a fixed quote for each phase. SaaS maintenance and support covers the ongoing care after a change, and cloud and DevOps covers deployment, monitoring and backups.

BitsSolved holds no SOC 2, ISO 27001 or HIPAA certification. Where a customer requires one, that is a separate programme with an accredited auditor.

Frequently asked questions

When should a SaaS start thinking about scaling?

Earlier than the traffic suggests, but lightly. Settle the structural choices that are expensive to change later (tenant separation, identity, payment idempotency) before the first paying customers, and leave the rest until a measurement says it matters.

What is the most common SaaS scaling bottleneck?

In our experience the database, and usually the queries and connections around it, not the raw size of the server. That is a rule of thumb from the systems we have seen, not a measurement of yours.

Should we move to microservices to scale?

Rarely as a first step. Splitting adds deployment and monitoring work before it removes any limit. Name the specific constraint first, and extract only the component that needs to scale independently.

Do we need to rewrite our SaaS to scale it?

Usually not. A staged migration that leaves a working system after each step is safer than a rewrite, which pauses feature work and rediscovers old edge cases.

How do I scale a multi-tenant SaaS safely?

Put the tenant in the signed identity, in every table and in every relationship, so a missing filter cannot expose another customer. Add per-tenant limits so one customer cannot slow the rest.

Can you review a SaaS we did not build?

Yes. Reviewing systems built by someone else is ordinary work for us. The first call is free, and nothing is chargeable until you approve a written quote for a scoped phase.

Start here

  1. Write down your five slowest queries and read their plans.
  2. Multiply servers by pool size and compare with the database limit.
  3. Move one slow task out of the request path.
  4. Prove that a repeated webhook does nothing the second time.
  5. Find where tenant separation is enforced, and test it by asking for another tenant's record.

If you want an independent read, start with a SaaS architecture review, or talk to us about SaaS modernization when the findings turn into build work.

Want this built properly?

The first call is free and is mostly us asking questions. After it you get the scope in writing and a fixed quote for the first phase.

What happens next

  1. You send the formTell us the problem.
  2. We reply by emailWith any questions.
  3. A free first callThen the scope in writing.
Based inTamil Nadu, India
First callFree, and mostly us asking questions