Choosing the right hardware for a Mastodon instance is a balancing act. The three main resources — CPU, RAM, and disk — each handle different parts of the workload, and their importance shifts as your user base grows. Many administrators start with a small virtual server only to find that one resource becomes a bottleneck while others sit idle. This article explains how CPU, RAM, and disk interact in the Mastodon stack, what each component does, and how to prioritize spending on the right resource for your expected user count and activity level.
Key Takeaways: Mastodon Instance Resource Sizing Tradeoffs
- CPU cores for Sidekiq workers: Each background worker thread needs one CPU core to process federation, media, and push notifications without delay.
- RAM for PostgreSQL and Puma: Mastodon relies on in-memory caching and database connections — 4 GB is the minimum for 10 concurrent users, 16 GB for 100.
- Disk IOPS for media storage: NVMe SSDs reduce database write latency and media upload times, while HDDs cause timeouts under moderate load.
How Mastodon Uses CPU, RAM, and Disk Differently
Mastodon is a Ruby on Rails application that uses a web server (Puma), a background job processor (Sidekiq), a database (PostgreSQL), a cache (Redis), and a media proxy. Each component has a distinct resource profile.
CPU Workload: Sidekiq and Federation
Sidekiq runs background jobs. These jobs include fetching remote timelines, processing incoming activities from other instances, sending push notifications, generating media thumbnails, and deleting old data. Each Sidekiq process runs multiple threads, but threads share the same CPU core. For heavy federation, you need more Sidekiq processes, which means more CPU cores. A single-core server can handle 5 to 10 active users if federation is light. For 50 active users, plan for 4 CPU cores. Puma also uses CPU for rendering web pages and API responses, but its load is typically lower than Sidekiq’s.
RAM Workload: PostgreSQL and Redis
PostgreSQL stores all toots, accounts, follows, and metadata. Mastodon generates complex queries for timelines and search. PostgreSQL uses shared buffers to cache data in RAM. If the working set of active data — recent toots from followed accounts — fits in RAM, queries are fast. If it does not, the database reads from disk, which is orders of magnitude slower. Redis caches timeline data and session information. Redis is an in-memory store; it holds frequently accessed data to reduce database load. A Redis instance with 1 GB of RAM is enough for 100 active users. PostgreSQL typically needs 2 GB to 8 GB depending on the size of the active dataset.
Disk Workload: Media Storage and Database Writes
Disk performance matters for two reasons: media files and database write-ahead logs. Mastodon stores uploaded images and videos in the public/system directory. Each toot with an image writes a file to disk. When a user scrolls their home feed, Mastodon serves these files directly. If you use S3-compatible object storage, disk performance on the server becomes less critical for media. The database still writes to disk for every transaction. A slow disk increases the time PostgreSQL takes to commit writes, which can cause request timeouts. NVMe SSDs provide the lowest latency. SATA SSDs are acceptable. HDDs are not recommended for production instances with more than 10 users.
How to Sizing Your Mastodon Instance Based on User Count
The table below provides starting resource allocations for different user scales. These numbers assume moderate federation — about 200 remote instances — and typical media usage of 1 to 2 images per toot.
- Estimate your peak concurrent users
Concurrent users are those active on the instance at the same time, not total registered accounts. A typical ratio is 10 percent of registered users active at peak. For example, 100 registered accounts means roughly 10 concurrent users. - Choose the CPU core count
For up to 10 concurrent users: 2 CPU cores. For 10 to 50 concurrent users: 4 CPU cores. For 50 to 200 concurrent users: 8 CPU cores. Beyond 200, scale horizontally by running multiple Sidekiq and Puma processes on separate servers. - Choose the RAM amount
For up to 10 concurrent users: 4 GB total RAM (2 GB for PostgreSQL, 1 GB for Redis, 1 GB for system and Puma). For 10 to 50 concurrent users: 8 GB total. For 50 to 200 concurrent users: 16 GB total. For 200 to 500 concurrent users: 32 GB total. - Choose the disk type and size
Use NVMe SSDs for any instance with more than 10 concurrent users. SATA SSDs are acceptable for smaller instances. Allocate 30 GB for the operating system and Mastodon application. Add 100 MB per registered user for media storage. For 100 registered users, that is 10 GB of media, plus 30 GB system = 40 GB total. Use object storage like S3 or Wasabi for media above 50 GB to keep server disk costs low. - Configure Sidekiq concurrency
Set the Sidekiq concurrency in the .env.production file. A good starting point is 10 threads per Sidekiq process. Run one Sidekiq process per CPU core. For a 4-core server, run 4 Sidekiq processes. This ensures background jobs do not queue up.
Common Sizing Mistakes and Tradeoffs to Avoid
Buying More CPU When the Bottleneck Is Disk IOPS
If your instance feels slow but CPU usage is below 50 percent, check disk I/O wait time using the iostat command. A high I/O wait percentage means the disk cannot keep up with read and write requests. Adding more CPU cores will not help. Upgrade to a faster disk — NVMe SSD — or move media to object storage.
Allocating Too Much RAM to Redis and Not Enough to PostgreSQL
Redis uses RAM efficiently for its cache, but PostgreSQL needs RAM to avoid disk reads. If PostgreSQL’s cache hit ratio falls below 99 percent, increase the shared_buffers setting. A common mistake is giving Redis 4 GB while PostgreSQL has only 1 GB. Redis rarely needs more than 2 GB for a small to medium instance. Reallocate that RAM to PostgreSQL.
Using an HDD for the Database Volume
A hard disk drive causes database write latency spikes whenever a write-ahead log flush occurs. This results in 500 errors for users posting toots. Even a 7200 RPM HDD cannot match the random I/O performance of a SATA SSD. Never use an HDD for the database or the Mastodon application directory. Use an HDD only for cold media storage that is rarely accessed, and even then, prefer object storage.
Ignoring Memory for Sidekiq Workers
Each Sidekiq thread consumes about 100 MB of RAM. If you run 4 Sidekiq processes with 10 threads each, that is 40 threads and approximately 4 GB of RAM just for Sidekiq. If your server has only 4 GB total RAM, the system will swap memory to disk, causing severe slowdowns. Always account for Sidekiq memory when sizing RAM. A safe formula is: total RAM = 2 GB for system + 2 GB for PostgreSQL + 1 GB for Redis + (number of Sidekiq threads 100 MB).
| Resource | Small Instance (10 concurrent users) | Medium Instance (50 concurrent users) |
|---|---|---|
| CPU cores | 2 | 4 |
| RAM | 4 GB | 8 GB |
| Disk type | SATA SSD or NVMe | NVMe SSD |
| Disk size | 40 GB (30 GB system + 10 GB media) | 80 GB (30 GB system + 50 GB media) |
| Sidekiq processes | 2 | 4 |
| PostgreSQL shared_buffers | 512 MB | 2 GB |
| Redis maxmemory | 256 MB | 1 GB |
You can now size a Mastodon instance by matching CPU, RAM, and disk to your expected concurrent user count. Start with the smallest recommended allocation and monitor Sidekiq queue length and PostgreSQL cache hit ratio after launch. If you see queue growth above 100 jobs or a cache hit ratio below 99 percent, add the bottlenecked resource first. For a quick check, run htop for CPU and RAM usage and iostat -x 1 for disk I/O wait. The most cost-effective upgrade for a slow instance is almost always adding RAM or switching to an NVMe SSD rather than adding CPU cores.