How many users can a 2 vCPU / 4 GB VPS handle?

Anyone who gives you a number without seeing your app is guessing. The same small server can serve a cached page to a big crowd, or fall over on a slow query with a handful of people. Here is what decides it, and how to find the number for your app.

Why there is no single answer

A "user" is not a unit of load. One visitor reading a cached blog post costs the server almost nothing. Another one opening a dashboard that runs several database queries and renders a chart on the server costs a lot more. Both count as one user.

So the question that has an answer is narrower: how many users, doing what, on which pages, before p95 latency or the error rate gets worse than you accept. On a given server that depends on four things more than on the server size itself.

1. CPU, and how many cores your app can use

Two vCPUs means two threads of work at the same time. On a shared VPS those vCPUs are shared with other customers on the same host, so the speed you get can change during the day.

The bigger catch is whether your app uses both cores at all. Node.js runs your JavaScript on one thread per process. A Python app with a single worker behaves the same way. If one process does all the work, one core sits at 100% while the other idles, and the server looks half busy while requests queue up.

So look at CPU per core, not the total. A total of 50% on a 2 vCPU box can mean plenty of room, or it can mean one core is completely full. Running one worker per core (cluster mode, more gunicorn or puma workers, more container replicas) is often the cheapest fix there is.

2. Memory

4 GB has to hold the operating system, your app, every worker you start, and often the database too. Each extra worker brings its own memory, so adding workers to use more CPU can run you out of RAM.

When memory runs out, the kernel kills a process or the server starts swapping, and latency goes from fine to terrible very quickly. Watch the memory peak under load, not at idle, and leave room for the database cache.

3. The database

On a small VPS the database often runs on the same box, sharing the two cores and the 4 GB with the app. A query without an index, or one query per item in a list, can use more CPU than the app itself.

The other common limit is connections. If the app has a pool of ten database connections and every request needs one, the eleventh request waits, however idle the CPU is. That shows up as latency climbing while CPU stays low, which is confusing if CPU is the only thing you watch.

4. Caching

The cheapest request is the one your app never has to compute. A page served from a CDN or a reverse proxy cache barely touches the server. A page rendered fresh on every request, with the same output for everyone, burns CPU for nothing.

Before paying for a bigger server, check which of your busy pages could be cached, even for a few seconds. Under a spike, a few seconds of caching turns many identical requests into one.

How to find the number for your own app

Run your app on the same size of server you plan to use, with the same container and settings. Point it at a test database, not production.

Send it traffic that looks like your real traffic: the pages people actually hit, roughly in the mix they hit them. Ramp the number of users up gradually instead of starting at the maximum, so you can see where things change.

Watch three things as the load rises: p95 latency (the time 95% of requests beat), the error rate, and what each resource is doing (CPU per core, memory, database connections). The point where p95 bends upward or errors start is your ceiling on that server. Whatever was full at that moment is what ran out first.

The fix follows from what ran out. One core full: more workers. Every core full: a bigger CPU, or less work per request. Memory full: more RAM or fewer workers. Nothing on the server full but latency climbing anyway: look at the database and the connection pool.

Common mistakes

Testing from your laptop over home internet measures your upload speed and your laptop, not the server. Generate the load from another machine close to the server.

Testing only the health endpoint tells you the framework can return "ok". Include the slow pages.

Reading average latency hides the slow requests. Use p95, and look at how it moves as load goes up rather than at one value.

Try it on your own app

The free Stresix run uses exactly this size of server. Lite starts your repository or Docker image on a 2 vCPU / 4 GB server, ramps up to 500 simulated users in a 4 minute window, and the report tells you what ran out first, the p95, the error rate and a verdict. Your first run is free with a GitHub account at least a week old.

To see what a finished report looks like before you start, the sample reports on the home page show three real runs on different stacks.

Frequently asked questions

Is 2 vCPU / 4 GB enough for a small SaaS?

It can be, depending on what your busiest pages do and whether your app uses both cores. The way to know for yours is to run it on that size and watch p95, errors and CPU per core as the load rises.

Is 2 vCPU twice as fast as 1 vCPU?

Only if your app can do two things at once. A single process Node or Python app uses one core however many you pay for, until you run more workers.

Should the database run on the same server?

It works, but it shares the CPU and memory with the app. Under load, check whether the app or the database is using the CPU before you decide to split them.

Related guides

Stop guessing your specs. Start knowing them.

Point Stresix at a repo or Docker image and get a number you can deploy on, in one run.

Start a load test