Memory is what most often decides the size of a server. It runs out first, and when it does, the server does not slow down gracefully: it kills processes. This guide gives the sizing rule, what each part of an application actually uses, typical profiles, and how to measure a server that is already running.
available column of free -h, not the free column.A server does not use memory "in general": every running program holds on to its share for as long as it runs. So the calculation starts from the list of processes that will always be there, then adds the peak and some headroom:
RAM to plan for = (OS + always-on services + peak of occasional jobs) × 1.25
The figures below hold for a typical application, measured in production. They are a starting point; measuring your own application, as described further down, always has the final word.
| Component | Typical memory | What makes it vary |
|---|---|---|
| Nginx, Caddy (web server, reverse proxy) | 10 to 50 MB | Almost flat: connection count barely matters. |
| PHP-FPM (WordPress, Laravel, Symfony) | 40 to 80 MB per process | The number of processes, capped by pm.max_children: 10 processes means 400 to 800 MB. |
| Node.js (API, Next.js, NestJS) | 60 to 300 MB per process | The number of processes (cluster mode, PM2) and the heap size, capped by --max-old-space-size. |
| Python (Django, FastAPI, Flask) | 80 to 200 MB per process | The number of Gunicorn or Uvicorn workers, and the libraries loaded: pandas or a machine learning model add hundreds of MB. |
| Java (Spring Boot) | 300 MB to 1 GB per application | The maximum heap size: by default, the JVM takes a quarter of the memory it can see. |
| Go, Rust | 10 to 100 MB | Whatever data the application itself keeps in memory. |
| PostgreSQL | 25% of RAM for shared_buffers, plus a few MB per connection | How much data is read often, the number of connections, work_mem. |
| MySQL, MariaDB | innodb_buffer_pool_size, 128 MB by default | On a dedicated database server, this buffer commonly takes up to 80% of memory. |
| Redis | The size of the data, plus its data structures | While saving to disk, modified pages are duplicated: up to twice the memory in the worst case. |
| Elasticsearch, OpenSearch | At least 2 GB of heap | The heap stays under half of RAM: the rest serves as file cache. |
One peak catches JavaScript projects again and again: the build. npm run build on a Next.js, Nuxt or Angular project commonly needs 1 to 2 GB on its own for a few minutes, on top of everything already running. Building on the server means sizing for that peak; building on your machine or in CI and shipping only the output avoids it.
The same reasoning applies to Docker containers: each container is a set of ordinary processes, and the Docker daemon adds its own share. docker stats shows what each one takes.
These profiles add up the components above, peak and headroom included. They assume an application of ordinary size and launch-day traffic; a large database or sustained traffic pushes the figure up.
| What runs on the server | Memory to plan for |
|---|---|
| Static site, reverse proxy, small bot or scheduled script | 1 to 2 GB |
| One WordPress site with MariaDB and a page cache | 2 GB |
| A WooCommerce shop, or several WordPress sites | 4 GB |
| A Node.js or Python API with PostgreSQL, first users | 4 GB |
| A Next.js app built on the server, with its API and a PostgreSQL database | 6 to 8 GB |
| Several containerized applications, staging and production | 8 GB |
| A database of several tens of GB under heavy read load | 16 GB and up |
| A 7 to 8 billion parameter language model running on the server | 16 GB |
An application that calls an AI model through an API (OpenAI, Anthropic, Mistral) is sized like any web application: the model runs at its provider and your server waits for the answer. Running the model on the server itself is what changes the scale.
On a server in production, measurement replaces estimates. Three commands tell you where you stand:
free -h
ps aux --sort=-rss | head -n 15
vmstat 5 5
free -h: read the available column, the memory actually available to start new programs. The free column is almost always low, and that is normal: Linux fills unused memory with file cache (buff/cache) and hands it back as soon as a program needs it.ps aux --sort=-rss: processes ranked by the memory they hold (the RSS column, in kilobytes). This is where you see what each PHP or Node.js worker weighs.vmstat 5 5: five readings five seconds apart. Non-zero values in the si and so columns, reading after reading, mean the server is swapping: it is short of memory.Measure at the busiest time of day, and during occasional jobs: builds, backups, imports. The peak is what counts.
A server that runs out of memory does not degrade gradually. When there is nothing left to reclaim, the Linux kernel calls the OOM killer (out of memory): it picks a process, usually the one holding the most memory, and kills it outright. On an application server, that is often the database.
The symptoms: intermittent 502 or 503 errors, a service that restarts for no visible reason, a build that dies with Killed. The logs confirm it:
journalctl -k | grep -i "out of memory"
systemctl status your-service
In the output of systemctl status, Failed with result 'oom-kill' marks a service stopped for lack of memory.
Swap, when the server has it, delays that moment by moving the least used memory to disk. It is a safety net, not capacity: a server that leans on swap all the time responds several times slower, even on an NVMe SSD.
The fixes, from quickest to most lasting: fewer application processes (pm.max_children, Gunicorn workers), builds moved off the server, a memory cap on the database, then a larger size.
Memory is not the only resource: CPU matters for anything that computes (builds, image processing, running an AI model) and disk for the database and files. For a web application, though, it is almost always memory that sets the size.
VPS Pro comes in six sizes, on Intel Xeon processors, ECC memory and mirrored NVMe SSDs, and moves up to a larger size at any time without reinstalling. Full-Stack Assistance is included: tell us what your server will run and we recommend the size, then we diagnose every question and tell you what to do, from the operating system down to your application code.
A static site, a reverse proxy or a small script runs in 1 to 2 GB. As soon as a database and an application (PHP, Node.js, Python) share the server, plan for 2 GB for a WordPress site and 4 GB for a custom application with PostgreSQL.
2 GB for one site with MariaDB and a page cache, 4 GB for a WooCommerce shop or several sites. The number of PHP-FPM processes is the first setting to look at: each one holds 40 to 80 MB.
No. Swap prevents an abrupt crash when memory is full, but a server that relies on it all the time responds several times slower, even on an NVMe SSD. It is a safety net; the size is chosen on memory.
Because Linux uses unused memory as file cache. That cache is released as soon as a program needs memory. The column to read is available, which shows the memory really available.
Allow 1 to 2 GB for the build alone, on top of what already runs on the server. Building on your machine or in CI and deploying only the output avoids that peak.
Simafri
Let's talk about your website
Tell us about your project in a few words: we will get back to you quickly.
Thank you! Your request has been sent. We'll get back to you shortly.
Prefer email? Write to us at support@simafri.com.