All posts

Plausible vs Umami: events per second on 1 GB

Same-host ingest lab under a 1 GB memory ceiling: Umami 3.4.1 hit 178 events/s with no OOM; Plausible CE v3.2.1 idled ~615 MiB and OOM'd under concurrent POSTs.

Written by NodeRings Inc.

NodeRings Inc. writes these notes. The company runs the marketplace and the agent that stays on the provider’s side of the hypervisor.

Umami 3.4.1 under Docker mem_limit of 768m for the app and 256m for Postgres accepted 2000 parallel pageview POSTs in 11.24 seconds: 178 events per second, zero errors, stack RAM about 200 MiB idle and 268 MiB after the load. Plausible Community Edition v3.2.1 with Postgres 16 and ClickHouse 24.12, limits split to 520m + 200m + 280m (1 GB total), idled near 615 MiB. One worker pushed about 46.5 events/s across 2000 sequential /api/event calls. Five or twenty workers under the same 520m app cgroup got the BEAM process killed by the memory controller (dmesg: CONSTRAINT_MEMCG on beam.smp).

StackIdle (docker stats sum)Load shapeEvents/sErrorsOOM
Umami 3.4.1 + PG15~200 MiB2000 POST, 20 workers1780no
Plausible CE v3.2.1 + PG16 + CH~615 MiB2000 POST, 1 worker46.50no
Plausible CE (same limits)~615 MiB2000 POST, 20 workerscrash~1997yes (memcg)
Bar chart comparing Umami and Plausible idle RAM and events per second under a 1 GB memory ceiling.
Idle floor and ingest under pinned mem_limits totaling about 1 GB.

Umami on a VPS already covers install hygiene (loopback, secrets, Caddy). The search that sits next to that post is this one: which privacy analytics stack still accepts events when the SKU is 1 GB.

Two containers vs three

Umami is the app plus Postgres. Plausible CE adds ClickHouse for events. Official Plausible self-host docs lean on roughly 2 GB of RAM for a comfortable CE box. Fitting CE into a 1 GB mem_limit budget means starving something. With the app at 384m beside ClickHouse and Postgres, the container never finished boot (Restarting (137)). Redistributing to 520 / 200 / 280 let /api/health return {"sessions":"ok","postgres":"ok","clickhouse":"ok",...} and left roughly 385 MiB unused at idle, which concurrent ingest then spent.

# Umami lab (compose excerpt)
services:
  db:
    image: postgres:15-alpine
    mem_limit: 256m
  umami:
    image: ghcr.io/umami-software/umami:3.4.1
    mem_limit: 768m
    ports: ["127.0.0.1:3010:3000"]
# Plausible CE override on top of the official clone
services:
  plausible:
    ports: ["127.0.0.1:8011:80"]
    mem_limit: 520m
  plausible_db:
    mem_limit: 200m
  plausible_events_db:
    mem_limit: 280m
# Plausible .env (lab)
BASE_URL=http://127.0.0.1:8011
SECRET_KEY_BASE=$(openssl rand -hex 64)
Terminal freeze of the lab method: mem_limits, endpoints, and worker counts.
Same host, one stack at a time, loopback JSON POSTs.

How the ingest was measured

Both stacks got a site first. Umami: create a website via the API, then POST /api/send with that websiteId. Plausible: register a user and Plausible.Sites.create for bench.example.com, then POST /api/event with "d":"bench.example.com". Success codes were 200 (Umami) and 202 (Plausible).

# Plausible smoke (after a site exists)
curl -s -o /dev/null -w '%{http_code}\n' -X POST http://127.0.0.1:8011/api/event \
  -H 'Content-Type: application/json' \
  -H 'User-Agent: Mozilla/5.0' \
  -d '{"n":"pageview","u":"https://bench.example.com/","d":"bench.example.com","r":null}'
# 202
# Shape used for both benches (Python ThreadPoolExecutor)
N, WORKERS = 2000, 20   # Plausible also run at WORKERS=1 and WORKERS=5
# POST JSON body to /api/send or /api/event
# count HTTP 200/202 vs errors; elapsed = wall time; eps = ok / elapsed

These are synthetic clients on loopback. Real browsers send fewer concurrent beacons and keep connections differently. The comparison still holds for what happens when a burst hits a memory-capped box.

Umami under the 1 GB ceiling

Idle stack about 200 MiB. After 2000 events at 20 workers: about 268 MiB, oom: false, 178 events/s.

FieldValue
VersionUmami 3.4.1 + Postgres 15
mem_limit768m + 256m
Idle stack~200 MiB
After load~268 MiB
Events OK / err2000 / 0
Wall time11.24 s
Events/s178
Umami bench JSON: 178 events per second, 0 errors, idle about 200 MiB.
Umami absorbed the parallel burst inside the 1 GB split.

Plausible CE under the same ceiling

Health was green. Idle hovered around 615 MiB with the app near 400 MiB of its 520m limit. Sequential ingest stayed healthy at 46.5 events/s for 2000 calls. Raising concurrency to five workers was enough to trip the cgroup killer on beam.smp. Twenty workers matched the Umami method and left almost every request as connection refused while the container restarted.

FieldValue
VersionCE ghcr.io/plausible/community-edition:v3.2.1
mem_limit520m + 200m + 280m
Idle stack~615 MiB
Seq 2000 / 1 worker46.5 events/s, 0 errors
Parallel 20 workersOOM on beam.smp, ~3 OK then refuse
App at 384m (earlier try)Exit 137 before listen
# dmesg excerpt during the parallel run
Memory cgroup out of memory: Killed process … (beam.smp)
constraint=CONSTRAINT_MEMCG
anon-rss ≈ 457 MiB  (under the 520m app limit)
docker stats for Plausible CE under 520m/200m/280m limits and sequential 46.5 events/s.
Boots and takes sequential events. Concurrent ingest spends the leftover headroom.
Parallel Plausible bench failing with connection refused and memcg OOM on beam.smp.
Same 20-worker shape that Umami finished cleanly.

Which one to run on 1 GB

You haveLean this way
A 1 GB VPS and you need analytics that survives burstsUmami
You want Plausible’s product and ClickHouse queriesPlan a 2 GB box (or follow CE’s own guidance)
You already know Umami’s UI and want install stepsUmami on a VPS
You are comparing idle RSS across appsWhat fits on a 2 GB VPS
Decision notes: Umami on 1 GB, Plausible CE when you can buy 2 GB headroom.
1 GB buys Umami headroom. Plausible CE wants ClickHouse room.
Skip thisWhat this lab did
Running both stacks at once on 1 GBOne stack at a time
Treating vendor “2 GB” as idle usageMeasured idle and load under mem_limit
Publishing app ports on 0.0.0.0Loopback binds only
Equating browser traffic with synthetic POSTsCaveat in the method section
Leaving Plausible on 384m app + CH + PGRecorded the boot OOM, then redistributed

Why Plausible’s floor sits above Umami’s

Umami’s self-hosted shape is the app plus PostgreSQL (Node 22+ since 3.1.0, Postgres 12.14+). Independent 2026 idle checks land roughly 170–400 MiB depending on version and whether Caddy shares the guest. Plausible Community Edition adds ClickHouse beside Postgres and the Elixir app; the CE README recommends at least 2 GB of RAM and a CPU with SSE 4.2 or NEON. ClickHouse’s own small-RAM tips admit 2 GB is possible only with lowered caches, single query threads, and trimmed log tables, and even then ingestion stays low. That is the mechanism behind Plausible feeling heavy on a 1 GB VPS: three engines, one of them columnar. Licence differs too (Umami MIT, Plausible CE AGPLv3 with an MIT tracker script). Feature splits in current CE vs Umami Cloud/CE guides still matter for Search Console (Plausible) versus funnels/replays (Umami self-hosted), but the RAM decision on a small VPS is mostly ClickHouse yes/no.

FAQ

Does Plausible CE ever fit 1 GB? It can listen if you give the Elixir app most of the budget and keep ClickHouse thin. Concurrent ingest still hit the cgroup wall here. Treat 1 GB as a lab squeeze for CE; buy more RAM before production traffic.

Is 178 events/s enough? For a personal site or a small product, yes. Marketing spikes and multi-site ingest are a different sizing problem; raise workers and watch Postgres and the app RSS.

Umami Cloud or Plausible Cloud instead? Fine if you want someone else to run ClickHouse. This post is about self-host RAM and ingest on a small VPS.

Postgres vs ClickHouse? Umami keeps events in Postgres. Plausible CE uses ClickHouse for the event path, which is why the third container shows up in every RAM discussion.

What to run on the VPS

On a 1 GB Compute Instance, pin Umami + Postgres with loopback ports and Caddy in front, and you still have RAM left after a 178 events/s burst on this lab. If you want Plausible CE, start at 2 GB so ClickHouse and the BEAM VM share less of a knife-edge cgroup, then repeat an ingest check before you point production traffic at /api/event. Compose layout notes live in Docker Compose on a VPS.