On this page
How to Choose a VPS Size for an AI-Built App
Start small, measure the right three numbers, and resize on evidence. A practical sizing procedure for the machine that runs your AI-generated app.
Quick answer
- Start at 1 to 2 vCPU with 2 GB of memory for a typical small web application, then resize when measurements say so — not before.
- Memory is usually the first constraint, disk performance the second, and CPU last for request-driven applications.
- Watch three numbers under real load: available memory, steal time, and disk wait. Everything else is secondary.
- Prefer resizing upward as evidence accumulates over buying headroom you never use; providers let you change size in minutes.
- The cheapest way to avoid a big instance is to move the database to a managed service and let the app server stay small.
Start from the shape of the workload
Sizing begins with a question about the code, not the provider’s price list. Is the application request-driven and waiting on a database most of the time? Then it is I/O-bound, memory matters more than CPU, and a small instance will handle far more traffic than people expect. Does it do real computation — image processing, video encoding, model inference, large report generation? Then CPU and memory both matter, and the number of concurrent jobs sets the requirement. Does it hold state in memory, such as a cache or an in-process session store? Then memory is the constraint and it must be sized for the working set, not the average.
This classification removes most of the guesswork. A CRUD application with a database on the same box is a memory question. A web scraper running many parallel fetches is a network and file-descriptor question. A background queue worker is a concurrency question. Writing down which one you have takes a minute and makes the specification follow from the code rather than from the marketing tiers.
Step 1 — Start deliberately small
For a typical small application — a web framework, a handful of routes, a database elsewhere — 1 to 2 vCPU and 2 GB of memory is a genuinely reasonable start, and many production sites run comfortably there. If the database lives on the same machine, add memory for it: 4 GB is a sensible floor for Postgres or MySQL holding any real data, because the database will use as much memory as you give it to cache indexes and rows. Add a small margin for the operating system and for peak traffic.
Avoid two habits at this stage. Do not buy the largest instance you can afford to ‘grow into’ — you will pay for it every hour while it sits idle, and resizing later takes minutes. And do not confuse a cheap burstable instance with a small dedicated one; both may be called 2 vCPU and they behave very differently under sustained load. Note which you are buying before you interpret any benchmark.
# The three numbers to watch, sampled every second under real load
free -h # 'available' memory: the first thing to run out
vmstat 1 # st (steal time) = host contention, si/so = swapping
iostat -x 1 # %util and await on the busiest diskStep 2 — Measure under real load
An instance that is comfortable at idle tells you nothing. Generate representative traffic — ideally with a tool that replays realistic requests, or simply by watching the same three numbers during your actual busiest hour — and record the peaks. Available memory should stay comfortably above zero, which is to say the machine should never swap; steal time should stay in the low single digits; and disk wait should be near zero for a request-driven app that is not doing bulk I/O.
One clarification that prevents a lot of misdiagnosis: memory used by the operating system’s page cache is not wasted memory. Linux deliberately fills spare RAM with cached file data and releases it on demand, which is why the ‘free’ column looks alarmingly small on a healthy machine while ‘available’ remains generous. Watch available, not free. The other classic misreading is disk space — a full disk makes databases and logs fail loudly, and it has nothing to do with memory pressure.
Step 3 — Resize on evidence, in the right direction
Three symptoms and their appropriate responses. If available memory trends toward zero under load, first look for what is holding memory — a leak, an unbounded cache, or a query loading too many rows — and fix that; it is usually cheaper than an upgrade and often the actual bug. If the code is clean and memory still runs out, move up a size. If steal time is high, the problem is the host, not the size, so change instance type or provider rather than paying for more shared contention. If disk wait is high, the fix is a faster volume or fewer disk operations, not more CPU.
Scale out rather than up when the application is stateless. Two small instances behind a load balancer usually cost less than one instance twice the size, and they give you a deploy without downtime and a machine that can fail without taking the site down. The moment you have more than one machine, though, you need somewhere shared for state — sessions, uploads, caches — which is the point at which a managed database and object storage start earning their cost. The usual efficient endpoint for a small AI-built app is a small app server, a managed database, and object storage for files.
Step 4 — Know when the machine is the wrong fix
Before upgrading, check for the five things that look like a sizing problem and are not. An unindexed database query that scans every row will exhaust any instance you can rent. Missing caching means each request does work three times for no reason. N+1 queries turn one page load into a hundred round trips. Loading whole tables into memory makes memory the symptom of a code problem. And a synchronous call to a slow third-party API will make even a large instance appear saturated while it is really just waiting.
Sizing is the last step, not the first. Work through the performance checklist on the application side, fix what is obviously wrong, and then measure what the machine actually needs. The reason this order matters is economic: hardware is a recurring cost, and every hour spent finding the inefficient query is repaid every month the smaller instance runs — while the reverse trade, upgrading first and never investigating, is how projects end up paying for capacity they do not need.
Where this bites vibecoders
Ask an assistant to make your app production-ready and it will often specify a comfortable three-node cluster with a large instance type, because that is the shape of the examples it learned from. Nothing about your actual traffic entered the recommendation. The counter-move is to describe the workload concretely — request-driven, database-backed, a few thousand requests a day — and start on the smallest thing that runs, then let measurements argue for more. It is far easier to justify an upgrade you can point at a graph for than to explain a bill nobody is using.
Where AI coding assistants get this wrong
- Recommending a large multi-node setup for a low-traffic application.
- Choosing a burstable instance for a steady workload and hitting the baseline.
- Sizing by peak the application never reaches rather than measured demand.
- Upgrading the machine instead of fixing an unindexed query or a memory leak.
- Putting the database on the smallest instance and expecting good query latency.
- Ignoring disk space until logs fill the volume and the database stops writing.
Checklist
- Classify the workload as CPU-bound, memory-bound, or I/O-bound.
- Start at 1 to 2 vCPU and 2 GB, or 4 GB if a database shares the machine.
- Confirm whether the instance is burstable or fixed-capacity.
- Measure available memory, steal time, and disk wait under real load.
- Fix obvious application inefficiency before upgrading hardware.
- Prefer several small stateless instances over one large one once that is affordable.
- Move state to managed services before scaling the app server further.
- Alarm on memory, disk space, and downtime so sizing is driven by data.
FAQ
How much RAM does a web app need?
For a small request-driven application on its own, 1 to 2 GB is usually enough, and the operating system’s page cache will use the rest. Add 2 GB or more if a database shares the machine, since databases consume memory deliberately to cache data. Size for peak usage with headroom rather than for the average.
Should I scale up or scale out?
Scale out with several small instances if the application is stateless, because it is usually cheaper per unit of capacity and gives you zero-downtime deploys and failure tolerance. Scale up if the workload is genuinely single-machine — a large database, a long-running compute job — or if you have no shared place to put session state yet.
Why is my server slow when CPU usage looks low?
Usually because the bottleneck is somewhere else: memory pressure causing swapping, disk wait on an unindexed query, high steal time from an oversubscribed host, or time spent waiting on an external API. Low CPU with slow responses is the signature of an I/O-bound problem, and adding CPU will not help.
Related topics
- What Is a vCPU (and Why Isn’t It a Real Core)?
- Hardware for AI Builders: How the Machine Your Code Runs On Actually Works
- How to Choose a Cloud Provider for Your AI-Generated App
- PC vs Data Center Server: Why a Server Looks Slower and Costs More
- How to Reduce Your Cloud Bill Without Breaking Production
- What Is RAM (and Why Does Your App Run Out of Memory)?