# Sizing

> Server sizes for Grovs Community, the process settings that use them and what to raise as load grows.

Source: https://docs.grovs.io/docs/self-hosting/operate/sizing

The whole stack runs on one server. Every service shares its CPU, memory and disk: the Compose file sets no per-container CPU or memory limits.

## Tiers

| Tier        | Server                                                      | Use it for                                                                                                                      |
| ----------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| Local trial | Any machine with Docker: Linux, macOS, or Windows with WSL2 | Evaluation on `lvh.me`. No real deep links. See [Try locally](https://docs.grovs.io/docs/self-hosting/get-started/try-locally). |
| Community   | **4 vCPU, 8 GB RAM, 80 GB SSD**                             | Production for up to **100,000 users**                                                                                          |
| Enterprise  | Sized with Grovs                                            | More than 100,000 users, or more flexibility and performance. [Talk to sales](https://www.grovs.io/contact).                    |

The Community size is a starting point, not a traffic guarantee. Workload, event volume and retention decide what you need, and disk use grows with your data.

The cloud templates create larger defaults than the Community floor:

| Template                                                           | Default server                                       |
| ------------------------------------------------------------------ | ---------------------------------------------------- |
| [AWS](https://docs.grovs.io/docs/self-hosting/clouds/aws)          | `t3.xlarge`, 100 GiB gp3                             |
| [Google Cloud](https://docs.grovs.io/docs/self-hosting/clouds/gcp) | `e2-standard-4`, 100 GB disk                         |
| [Azure](https://docs.grovs.io/docs/self-hosting/clouds/azure)      | `Standard_D4s_v5` (4 vCPU, 16 GiB RAM), 128 GiB disk |

## Process sizing

These `.env` variables decide how many processes, threads and database connections the stack uses. The shipped values fit the Community server.

| Variable                     | Shipped value | Controls                                             |
| ---------------------------- | ------------- | ---------------------------------------------------- |
| `WEB_CONCURRENCY`            | `2`           | Puma worker processes in `web`                       |
| `RAILS_MAX_THREADS`          | `5`           | Threads per Puma worker                              |
| `RAILS_DB_POOL`              | `10`          | PostgreSQL connections each backend process may open |
| `SIDEKIQ_EVENTS_CONCURRENCY` | `10`          | Threads in the events worker inside `worker-1`       |
| `POSTGRES_MAX_CONNECTIONS`   | `200`         | PostgreSQL server connection ceiling                 |

Apply a change with `docker compose --profile standalone up -d`. Compose recreates only the containers whose settings changed.

### Connection budget

`POSTGRES_MAX_CONNECTIONS` must cover every backend process. Each process can open up to `RAILS_DB_POOL` connections:

| Container  | Backend processes               |
| ---------- | ------------------------------- |
| `web`      | `WEB_CONCURRENCY`               |
| `worker-1` | 3 (scheduler, events, batch)    |
| `worker-2` | 2 (maintenance, device updates) |

With the shipped values that is at most (2 + 3 + 2) × 10 = 70 connections, well under 200. Recompute it whenever you raise `WEB_CONCURRENCY` or `RAILS_DB_POOL`.

## What to raise first

| Symptom                                                                                                                         | Raise                        | Keep in step                                                                              |
| ------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | ----------------------------------------------------------------------------------------- |
| `web` is CPU-bound and API or link responses slow down                                                                          | `WEB_CONCURRENCY`            | The connection budget above                                                               |
| The `events` queue in [health metrics](https://docs.grovs.io/docs/self-hosting/operate/monitoring#health-metrics) keeps growing | `SIDEKIQ_EVENTS_CONCURRENCY` | `RAILS_DB_POOL` at or above the thread count                                              |
| The host runs short of CPU or memory                                                                                            | Server size                  | Then the process settings                                                                 |
| Disk free space keeps falling                                                                                                   | Disk size                    | [Monitoring](https://docs.grovs.io/docs/self-hosting/operate/monitoring#what-to-alert-on) |

Keep `RAILS_DB_POOL` at least as large as `RAILS_MAX_THREADS` and `SIDEKIQ_EVENTS_CONCURRENCY`, as the shipped values do. Never scale `worker-1`: it runs the scheduler and must have exactly one replica.

## Disk

PostgreSQL, ClickHouse, Redis and uploads all live in Docker volumes on the server disk, and they grow with links, events and retention. Plan for growth from the start, watch free space, and leave room for backup files if you write them to the same disk first. See [Backups](https://docs.grovs.io/docs/self-hosting/operate/backups).
