Running Chatwoot in Production: Sizing, Tuning and Costs
Self-hosting Chatwoot is free, but production is not the install. Official sizing numbers, Puma and Sidekiq tuning, upgrade discipline, backups that restore, and real costs versus Chatwoot Cloud.

Chatwoot is free to self-host, but the install is the easy part. What decides whether your instance is still healthy in a year is sizing, Puma and Sidekiq tuning, upgrade discipline, and backups that actually restore. This guide covers all four, with the official numbers, measured data from real installations, and a cost model against Chatwoot Cloud.
It assumes you have already installed Chatwoot with Docker or the Linux script. If you have not, the official Docker deployment guide is the right starting point. Come back here when the login screen works.
What a production Chatwoot install actually runs
Chatwoot looks like one application. In production it is at least four processes, and each fails differently. The official architecture page lists the required services:
- Rails web server (Puma). Serves the agent dashboard, the widget API, and the websocket channel that pushes new messages into open dashboards.
- Sidekiq worker. Sends email, polls connected channels, fires automation rules and webhooks, builds reports. If this dies, the dashboard looks fine but nothing happens in the background.
- PostgreSQL. The only supported database. Holds conversations, contacts, agents, and every setting.
- Redis. Holds the Sidekiq job queue and the ActionCable pub/sub channel. It is not a throwaway cache: lose Redis and you lose queued jobs.
- An email service. SMTP, SendGrid, Mailgun, or Amazon SES. Agent invitations and reply notifications depend on it. If you already run SES for outbound mail, the same verified domain works here; our Listmonk and Amazon SES setup guide walks through the SES side, including moving out of the sandbox.
- Object storage. Optional at first, but attachments have to live somewhere, and local disk fills up.
The most common early failure mode is running the Rails container without the Sidekiq container and wondering why notifications stopped. The second is treating Redis as ephemeral and discovering the queue was the only copy of an outbound email.
One more detail that trips people on 4.x installs: the Postgres image must ship the pgvector extension. Chatwoot's migrations create the vector and pg_trgm extensions, and the stock postgres image fails with ERROR: extension "vector" is not available. Use pgvector/pgvector:pg16 like the upstream compose file does.
Sizing: official numbers and what real installs measure
The official requirements page gives clear guidance:
- 4 CPU cores and 4 GB RAM is the recommended minimum, rated at up to 10,000 conversations a day.
- 8 cores supports up to 20,000 conversations a day.
- Beyond that, scale horizontally by adding application servers.
- PostgreSQL needs at least 5 to 10 GB of storage before you count attachments.
- Redis 7.0 or higher, starting around 100 MB.
Two measured data points make this concrete. A Docker Compose stack of Chatwoot 4.x idles at about 810 MB of RAM: roughly 373 MB for Rails, 381 MB for Sidekiq, 44 MB for Postgres, 12 MB for Redis. That is before a single conversation. Sidekiq alone can pass 1 GB on a busy server, because it boots the entire Rails stack and grows over time.
The practical translation:
- 1 to 5 agents, quiet inbox: 4 GB RAM, 2 vCPU is workable. Do not go below 4 GB.
- 5 to 20 agents with real volume: 8 GB RAM, 4 vCPU. This keeps Sidekiq from competing with Rails for memory.
- 40+ agents or heavy WhatsApp volume: 16 GB, 8 vCPU, or split the worker onto its own host, which is what Chatwoot officially recommends for scalability.
A 2 GB VPS will boot Chatwoot and will look fine with two agents. It falls over in two places: Sidekiq memory under load, and upgrades, because db:chatwoot_prepare boots a second Rails process to run migrations. The kernel's OOM killer then SIGKILLs the largest process and Docker shows the container cycling through Exited (137). If you must run small, add at least 1 to 2 GB of swap and set per-service memory limits so the worker cannot take the database down with it. Upstream recommends at least 1 GB of swap for exactly this reason.
Tuning Puma and Sidekiq
Default Chatwoot is tuned to boot everywhere, not to run fast. The official optimization guide documents the knobs:
WEB_CONCURRENCY: number of Puma worker processes. Default is 0, meaning a single worker, so the app runs on low-spec machines. On any real server, raise it.RAILS_MAX_THREADS: threads per worker. Each thread handles one request at a time.SIDEKIQ_CONCURRENCY: Sidekiq job threads, default 10.- The database connection pool is sized automatically from
RAILS_MAX_THREADSandSIDEKIQ_CONCURRENCY, so these numbers have a database cost.
Chatwoot's own advice is to set workers at or slightly below the number of CPU cores. The reason is the MRI Ruby GVL: threads inside one Ruby process cannot run CPU-bound work in parallel, and a lot of Chatwoot's request cost is CPU-bound JSON serialization, not SQL.
A real example makes this vivid. In GitHub discussion 14838, a team running about 101,000 conversations, 40 agents, and 1.4 million messages on 8 vCPU and 32 GB saw 15 to 28 second response times on the conversation list. Their logs showed roughly 900 ms of view serialization against 330 ms of database time per request, with Postgres nearly idle and Rails CPU pinned. The fix that worked: more Puma workers, fewer threads. They settled on WEB_CONCURRENCY=5, RAILS_MAX_THREADS=5, SIDEKIQ_CONCURRENCY=15, and the stalls disappeared.
Two rules to take from that:
- CPU-bound slowness means more workers, not more threads. If logs show high view time and low ActiveRecord time, raise
WEB_CONCURRENCYtoward your core count. - Watch the connection math.
WEB_CONCURRENCY * RAILS_MAX_THREADS + SIDEKIQ_CONCURRENCY, plus headroom for consoles and one-off jobs, must fit inside Postgresmax_connections. With 5 workers, 5 threads, and Sidekiq at 15, you are at 40 application connections. Comfortable against the default 100, but a 6x10 configuration plus Sidekiq at 25 would be 85, and one Rails console away from trouble.
The same discussion surfaces a quieter scaling lever: conversation hygiene. That team had left 99.8 percent of conversations open, which inflates the list and meta queries every agent loads. Auto-resolving stale conversations, and training agents to work from the Open view rather than All, reduces load more cheaply than hardware.
Storage, uploads, and the database growth nobody budgets for
Postgres itself grows predictably. Attachments do not. Every screenshot, PDF, and voice note a customer sends lands in local storage by default and stays there.
Move to S3-compatible storage before it is urgent, not after. Chatwoot supports S3, GCS, Azure, and S3-compatible services like Minio, Cloudflare R2, and DigitalOcean Spaces through environment variables. R2 is attractive here because it charges no egress fees, and support attachments get downloaded constantly.
Operational habits that prevent the 2 a.m. disk-full page:
- Watch
docker system df -v, not just the database size. The storage volume is what grows without a limit you set. - Set retention expectations early. Decide how long you keep attachments and automate cleanup, or accept the growth curve.
- Keep 20 percent free disk headroom on the Postgres volume. Migrations and vacuum operations need working room.
Upgrades without regret
Chatwoot releases a new version around the first Monday of every month, with hotfix releases between. Falling months behind is how a routine upgrade turns into a scary one, because the official guidance for old installs is to step through intermediate tags one at a time, running migrations after each.
The safe sequence for a Docker deployment:
- Read the release notes for every version between your tag and the target.
- Take a fresh database dump and a storage volume archive, and verify the file sizes look sane.
- Pull the new image first. Migrations must run from the new image; the old one does not contain the new migration files.
- Stop the stack. Old code running against a new schema writes rows the new schema may reject.
- Run
docker compose run --rm rails bundle exec rails db:chatwoot_prepare. - Start the stack and watch the logs.
If Rails boots before migrations run, it refuses to serve with ActiveRecord::PendingMigrationError and the container restart-loops. Run the prepare step and it clears.
The part most guides skip: there is no reliable reverse migration path. Rollback means restoring the old tag plus the database dump, which is why step 2 is not optional. Budget 30 to 60 minutes a month for this, and do it monthly.
Backups: the four things you must capture
A database-only backup of Chatwoot is a partial backup. To fully restore you need four things:
- The Postgres database.
docker compose exec -T postgres pg_dump -U postgres -Fc chatwoot > db-$(date +%F).dump - The storage volume. Without it, a restore gives you conversations full of broken attachment links.
- The
.envfile. A differentSECRET_KEY_BASEsigns every user out. More importantly, theACTIVE_RECORD_ENCRYPTION_*keys encrypt columns at rest: lose them and those columns are unreadable even with a perfect database dump. - The compose files. Small, but you want the exact configuration back.
Then prove the restore works. Restore testing is the step everyone skips: once a quarter, restore the dump and the volume onto a scratch VM and open a conversation with an attachment. A backup you have never restored is a hypothesis.
What it costs: server versus Chatwoot Cloud
Here is the honest arithmetic for a 12-agent support team, using Chatwoot's published cloud prices and DigitalOcean droplet pricing.
Chatwoot Cloud, 12 agents:
- Startups plan at $19 per agent per month: $228 a month, $2,736 a year. No automation rules at this tier.
- Business plan at $39 per agent per month: $468 a month, $5,616 a year. Adds voice and automation rules.
- The free Hacker plan caps at 2 agents and 500 conversations a month, and since July 2026 it no longer includes API and webhook access, which removes most integration use cases.
Self-hosted, any number of agents:
- 8 GB / 4 vCPU droplet: $48 a month.
- Object storage for attachments and backup copies: roughly $5 to $10 a month.
- Transactional email via SES or similar: a few dollars at support volumes.
- Total: about $60 a month, $720 a year, flat, whether you have 5 agents or 50.
That is roughly $4,900 a year less than the Business plan for 12 agents. The gap buys a lot of maintenance time. We ran the same build-versus-subscribe arithmetic for self-hosting Cal.com, and the pattern holds across the stack: the software is free, the server is cheap, and the real cost is the maintenance hours. So price the maintenance honestly: expect 2 to 4 hours a month for upgrades, monitoring, and the occasional incident, and more in the first month. If your team's fully loaded engineering time is expensive, the first year of savings is smaller than the sticker math suggests.
Note also what self-hosted Community Edition does not include. SSO/SAML and audit logs are Enterprise features on the pricing page, and the Enterprise Edition of the self-hosted software requires a paid license key. If your compliance team requires SAML, factor that license into the comparison.
Common mistakes
- Running without the Sidekiq container. Dashboard works, nothing else does.
- Staying on
latest. Pin a version tag (or a-cetag for Community Edition) so upgrades are deliberate. - Skipping swap on a 4 GB box. Upgrades boot a second Rails process and the OOM killer picks your database.
- Using the stock Postgres image. You need pgvector, or the first migration fails.
- Backing up only the database. The storage volume,
.env, and encryption keys are equally load-bearing. - Leaving
WEB_CONCURRENCYat the default. One Puma worker on an 8-core box wastes the box. - Never resolving conversations. A six-figure pile of open conversations slows the views agents use all day.
When self-hosting Chatwoot is the wrong choice
Self-hosting is a poor fit when nobody on the team owns it. Chatwoot Cloud exists precisely for teams that cannot commit 2 to 4 hours a month and an on-call path. Pay the per-agent fee and move on.
It is also the wrong choice when you need SSO/SAML and audit logs but cannot justify the Enterprise license, since you would be self-hosting and still paying per agent. And if your support volume is tiny, two agents and a few dozen conversations a week, the free Hacker plan or a shared inbox in your existing email is simpler than running four services.
Finally, if your real requirement is WhatsApp at scale in Kenya or East Africa, the hard part is the Business API setup and Meta's per-conversation pricing, not where Chatwoot runs. We cover that in Chatwoot WhatsApp Business API setup and costs in Kenya.
Frequently asked questions
How much RAM does self-hosted Chatwoot need? Officially, 4 GB with 4 cores is the minimum, rated at up to 10,000 conversations a day. A measured 4.x stack idles around 810 MB, but Sidekiq alone can exceed 1 GB on a busy server, so treat 4 GB as the floor and 8 GB as the comfortable production size.
Can I run Chatwoot on a 2 GB VPS? It will boot and work for two or three agents on a quiet inbox. It will OOM-kill containers under Sidekiq load and during upgrades. If budget forces 2 GB, add 2 GB of swap and set container memory limits.
Do I need the pgvector Postgres image?
Yes. Chatwoot 4.x migrations create the vector and pg_trgm extensions, and the stock postgres image fails with ERROR: extension "vector" is not available. Use pgvector/pgvector:pg16 or another image that ships pgvector.
How do I upgrade Chatwoot in Docker safely?
Pin a version tag, back up the database and storage volume, pull the new image, stop the stack, run db:chatwoot_prepare, then start. Old installs should step through intermediate tags one at a time. There is no reliable reverse migration, so rollback means restoring your dump.
Is self-hosted Chatwoot really free? The Community Edition is free and open source, with no per-agent fee. You pay for the server, storage, and email, typically $25 to $60 a month. Enterprise Edition features like SSO/SAML and audit logs require a paid license even when self-hosted.
What breaks most often in production?
Memory pressure, in two forms: Sidekiq growing past 1 GB on busy servers, and upgrades booting a second Rails process on a box with no swap. After that, disk filling with attachments and missed backups of the .env encryption keys.
Where to go from here
If you want Chatwoot running without owning the pager, our managed open-source stack service deploys and runs Chatwoot alongside Twenty, Listmonk, and the rest of the stack, with upgrades, backups, and restore testing handled for you. If you are already self-hosting and want the conversations flowing into the rest of your operations, our business automation work connects Chatwoot to your CRM, billing, and alerting through n8n. And if you are building the wider self-hosted stack piece by piece, our guides on self-hosting Twenty CRM and running a newsletter on Listmonk with Amazon SES follow the same production-first approach as this one.
About AI Agents Plus Editorial
AI automation expert and thought leader in business transformation through artificial intelligence.



