Skip to content
STACK IT FAST

Chatwoot

Curated OSSHybridCustomer Support Suite6-20 people

Audited from github.com/chatwoot/chatwoot

Chatwoot is an open-source customer engagement platform providing live chat, email, and omnichannel support desk features, built as a Ruby on Rails application with a Vue dashboard and widget.

Language
Ruby
Database
PostgreSQL
Hosting
Docker
Running for
4 years 6 months
Team
6-20 people

Why this architecture

Keeping the Vue dashboard inside the Rails asset pipeline via vite_rails and running realtime updates over Action Cable lets Chatwoot ship one deployable Rails app instead of coordinating a separate frontend and websocket service, while Sidekiq and OpenSearch handle background work and search.

Tech stack by layer

11 technologies · audited Sep 17, 2026
Frontend & UI
  • VueComponent framework for the agent dashboard and the embeddable website widget.
  • ViteBuild tool and dev server for the Vue frontend, integrated with Rails via vite_rails.
  • Tailwind CSSUtility CSS for the dashboard UI, referenced in the repository topics and asset pipeline.(inferred)
Backend & APIs
  • RailsCore web framework serving the REST API, admin, and server-rendered mailer views.
  • SidekiqBackground job processor for message delivery, integrations, and scheduled tasks via sidekiq-cron.
  • Action CableServes websocket connections for live conversation and presence updates via @rails/actioncable on the frontend.
  • DeviseAuthentication framework for agents and users, extended with two-factor and token auth.
Data & Persistence
  • PostgreSQLPrimary relational database, accessed through the pg gem.
  • RedisBacks Sidekiq queues and Action Cable pub/sub.
  • OpenSearchFull-text search over conversations and contacts via Searchkick and the opensearch-ruby client.
Infrastructure & Deploy
  • DockerMulti-stage Dockerfile builds the production image; a separate docker-compose.yaml runs the full dev stack.
  • PumaApplication server running the Rails process in production containers.

Chatwoot architecture diagram

Open SVG
Chatwoot architecture diagramAgent dashboard → Rails app (REST); Website widget → Rails app (REST); Agent dashboard → Action Cable (live updates); Rails app → PostgreSQL (ActiveRecord); Rails app → Redis (enqueue); Redis → Sidekiq (jobs); Action Cable → Redis (pub/sub); Rails app → OpenSearch (index · query); Rails app → File storage (attachments)CLIENTSSERVICESWORKERS & JOBSDATA & STORAGEEXTERNALAgent dashboardVue · ViteWebsite widgetVueRails appPuma · REST APIAction CablewebsocketsSidekiqdelivery · integrationsPostgreSQLpgRedisqueues · pub/subOpenSearchSearchkickFile storageS3 · Azure · GCSRESTRESTlive updatesjobsActiveRecordenqueuepub/subindex · queryattachments
How the main components of Chatwoot connect, drawn from the audited repository.
Diagram as text
  • Agent dashboard (Vue · Vite) → Rails app (Puma · REST API): REST
  • Website widget (Vue) → Rails app (Puma · REST API): REST
  • Agent dashboard (Vue · Vite) → Action Cable (websockets): live updates
  • Rails app (Puma · REST API) → PostgreSQL (pg): ActiveRecord
  • Rails app (Puma · REST API) → Redis (queues · pub/sub): enqueue
  • Redis (queues · pub/sub) → Sidekiq (delivery · integrations): jobs
  • Action Cable (websockets) → Redis (queues · pub/sub): pub/sub
  • Rails app (Puma · REST API) → OpenSearch (Searchkick): index · query
  • Rails app (Puma · REST API) → File storage (S3 · Azure · GCS): attachments

Key architectural decisions

7 decisions
  1. 01

    Ruby on Rails serves both the JSON API and the Vue frontend from one app

    Gemfile declares rails 7.2.3.1 and vite_rails, integrating the Vite-built Vue dashboard directly into the Rails asset pipeline rather than running it as a fully separate frontend service.

  2. 02

    Sidekiq with Redis handles all asynchronous and scheduled work

    Gemfile includes sidekiq (~> 7.3.10), sidekiq-cron for scheduled jobs, sidekiq_alive for healthchecks, and judoscale-sidekiq for CloudWatch-based autoscaling metrics, making Sidekiq the single background-processing system for message delivery, integrations, and reports.

  3. 03

    Realtime dashboard updates run over Action Cable, not a separate websocket service

    The frontend package.json depends on @rails/actioncable, connecting directly to the Rails process for live conversation updates, typing indicators, and presence, keeping realtime infrastructure inside the same Rails/Redis stack used for background jobs.

  4. 04

    Search runs on OpenSearch through Searchkick rather than Postgres full-text search

    Gemfile pairs searchkick with opensearch-ruby and faraday_middleware-aws-sigv4 (for signed AWS OpenSearch requests), giving conversation and contact search a dedicated search index instead of relying on Postgres.

  5. 05

    Multiple cloud storage backends are supported through one abstraction

    Gemfile depends on aws-sdk-s3, azure-blob, and google-cloud-storage together (all required: false, loaded conditionally), letting self-hosters pick S3, Azure Blob, or Google Cloud Storage for Active Storage attachments without code changes.

  6. 06

    The release pipeline runs a Postgres migration step before the app boots

    The Procfile defines a release phase (POSTGRES_STATEMENT_TIMEOUT=600s bundle exec rails db:chatwoot_prepare) that runs before the web and worker dynos start, ensuring schema migrations complete first on Heroku-style deploys.

  7. 07

    Dev runs Rails, Sidekiq, and Vite as separate Compose services with shared volumes

    docker-compose.yaml defines rails, sidekiq, vite, postgres, redis, and mailhog services that all depend on a common base image built from docker/Dockerfile, with the rails service explicitly depending on postgres, redis, vite, mailhog, and sidekiq before starting.

How Chatwoot is built

How Chatwoot is structured

Chatwoot is a single Ruby on Rails application (Gemfile declares rails 7.2.3.1 on ruby 3.4.4) with an integrated Vue frontend rather than a separately deployed SPA. The root package.json (@chatwoot/chatwoot) defines the JavaScript side of the same repository, built through vite_rails (in Gemfile) so the Vue dashboard, the embeddable website widget, and an SDK bundle (build:sdk script, vite.lib.config.ts) all come out of one asset pipeline alongside the Rails app.

Frontend

The dashboard and widget are built in Vue, bundled with Vite (@vitejs/plugin-vue, vite build --config vite.lib.config.ts for the SDK). Realtime connectivity uses @rails/actioncable directly from the frontend package.json, talking to the Rails backend's Action Cable server. Component development and visual testing use Histoire (story:dev, story:build scripts) rather than Storybook. Bundle size is enforced with size-limit, capping the widget bundle at 300 KB and the SDK at 40 KB. Internationalization is synced with a dedicated sync:i18n script (bin/sync_i18n_file_change). Telephony features integrate @twilio/voice-sdk, and rich text editing uses a Chatwoot-maintained ProseMirror schema (@chatwoot/prosemirror-schema).

Backend & APIs

The Rails app (Gemfile) exposes its API through standard Rails controllers, authenticated with Devise (devise, devise_token_auth, devise-two-factor for 2FA) and authorized with Pundit. Background processing runs on Sidekiq (sidekiq ~> 7.3.10), configured via config/sidekiq.yml per the Procfile's worker process, with sidekiq-cron for scheduled jobs and sidekiq_alive for container healthchecks. Rate limiting and abuse protection use rack-attack, and outbound URL fetches are protected with ssrf_filter. The administrate gem (with administrate-field-active_storage and -belongs_to_search extensions) powers a Rails-native super-admin panel, avoiding a separate admin app.

Data & persistence

PostgreSQL is the primary datastore, accessed via the pg gem, with groupdate for time-series aggregation and activerecord-import for bulk inserts. Redis, via the redis and redis-namespace gems, backs both Sidekiq queues and Action Cable's pub/sub layer, so the same Redis instance supports background jobs and realtime messaging. Search is delegated to OpenSearch through searchkick and opensearch-ruby, with faraday_middleware-aws-sigv4 available for signed requests to AWS-hosted OpenSearch. File attachments use Rails Active Storage with optional aws-sdk-s3, azure-blob, or google-cloud-storage backends, all loaded conditionally (require: false) so only the configured backend is active.

Realtime / collaboration

Live conversation updates, agent presence, and typing indicators are delivered over Action Cable, connected from the frontend through the @rails/actioncable npm package to the Rails backend's built-in websocket server, which uses Redis as its adapter. This keeps realtime infrastructure inside the same Rails/Redis stack used for background jobs rather than introducing a separate Node.js or Go websocket service.

Build, test & deploy

CI runs through GitHub Actions: run_foss_spec.yml and run_mfa_spec.yml run the Ruby test suite, frontend-fe.yml runs frontend tests, test_docker_build.yml validates the Docker image builds, size-limit.yml enforces the frontend bundle budgets, and logging_percentage_check.yml and deploy_check.yml gate additional release checks. Separate workflows publish Community (publish_foss_docker.yml) and Enterprise (publish_ee_docker.yml) Docker images, and nightly_installer.yml builds an installer on a schedule. The production docker/Dockerfile is a multi-stage Alpine build using ruby:3.4.4-alpine3.21 and Node 24 with pnpm for asset compilation.

Self-hosting notes

docker-compose.yaml defines a full local stack: rails, sidekiq, vite, postgres, redis, and mailhog services, all built from a shared base image (./docker/Dockerfile) with the rails service depending on postgres, redis, vite, mailhog, and sidekiq. For platform deploys, the Procfile defines release (runs rails db:chatwoot_prepare with a 600s statement timeout before anything else starts), web, and worker process types, and app.json provides a Heroku-style one-click deploy manifest.

What to copy (and what not to)

Keeping the Vue frontend inside the Rails asset pipeline via vite_rails, instead of running it as an independently deployed SPA, removes a class of deployment and CORS complexity for a self-hostable product — the tradeoff is that frontend and backend release cycles stay coupled to the same Rails deploy. Using Action Cable (backed by the same Redis instance as Sidekiq) for realtime messaging is a good fit for a Rails-centric team that wants to avoid running a second realtime service, though it does mean realtime throughput is bounded by Rails' connection-handling model rather than a purpose-built websocket server. Supporting three interchangeable object-storage backends (S3, Azure Blob, GCS) as optional gems behind one Active Storage configuration is a pattern worth copying for any self-hostable product that expects deployment across different clouds.

Sources & repo audit

Audited
Sep 17, 2026
Commit
39b9d20
License
NOASSERTION

Independent analysis of repository at github.com/chatwoot/chatwoot. Spotted an inaccuracy? Use the claim form to request a correction.

Show this stack on your README or website
Tech stack of Chatwoot
[![Tech stack of Chatwoot on STACK IT FAST](https://stackitfast.com/badge/chatwoot.svg)](https://stackitfast.com/project/chatwoot)

Paste it into your README. It shows your current stack and links to this page.

Use this stack

Scaffold it with your agent

Paste this prompt into Claude Code, Cursor, Windsurf or AGY to start a project with Chatwoot's architecture.

  1. 1Copy the promptThe full markdown spec, with every layer and decision.
  2. 2Open your AI toolClaude Code, Cursor, Windsurf or Copilot, in a new repo.
  3. 3Paste and scaffoldUse it as the first instruction; review before you ship.
use-this-stack.md · 61 lines · 7.6 KB
# MISSION: Scaffold "Chatwoot" Production Architecture
You are an expert Senior Staff Software Architect and Full-Stack Engineer. Your mission is to scaffold and implement a production-grade, highly reliable, and modular codebase following the proven architecture of **Chatwoot**.
---
## 1. PROJECT SPECIFICATIONS & BENCHMARK
- **Reference Architecture**: Chatwoot
- **What It Does**: Chatwoot is an open-source customer engagement platform providing live chat, email, and omnichannel support desk features, built as a Ruby on Rails application with a Vue dashboard and widget.
- **Domain & Category**: Customer Support Suite
- **Production Scale**: 6-20 people
- **Development Mode**: HYBRID
- **Architectural Rationale**: Keeping the Vue dashboard inside the Rails asset pipeline via vite_rails and running realtime updates over Action Cable lets Chatwoot ship one deployable Rails app instead of coordinating a separate frontend and websocket service, while Sidekiq and OpenSearch handle background work and search.
- **Live Website Reference**: https://chatwoot.com
- **Source Repository**: https://github.com/chatwoot/chatwoot
---
## 2. PRODUCTION TECH STACK
- **Full Stack Array**: Ruby, Rails, PostgreSQL, Redis, Sidekiq, Vue, Vite, Tailwind CSS, Devise, OpenSearch, Docker
- **Primary Language(s)**: Ruby, Vue, JavaScript
- **License of the reference repo**: NOASSERTION
- **Frontend**: Vue — Component framework for the agent dashboard and the embeddable website widget.; Vite — Build tool and dev server for the Vue frontend, integrated with Rails via vite_rails.; Tailwind CSS — Utility CSS for the dashboard UI, referenced in the repository topics and asset pipeline.
- **Backend & APIs**: Rails — Core web framework serving the REST API, admin, and server-rendered mailer views.; Sidekiq — Background job processor for message delivery, integrations, and scheduled tasks via sidekiq-cron.; Action Cable — Serves websocket connections for live conversation and presence updates via @rails/actioncable on the frontend.; Devise — Authentication framework for agents and users, extended with two-factor and token auth.
- **Data & persistence**: PostgreSQL — Primary relational database, accessed through the pg gem.; Redis — Backs Sidekiq queues and Action Cable pub/sub.; OpenSearch — Full-text search over conversations and contacts via Searchkick and the opensearch-ruby client.
- **Infrastructure & deploy**: Docker — Multi-stage Dockerfile builds the production image; a separate docker-compose.yaml runs the full dev stack.; Puma — Application server running the Rails process in production containers.
---
## 3. KEY ARCHITECTURAL DECISIONS (audited from https://github.com/chatwoot/chatwoot @ 39b9d20)
1. **Ruby on Rails serves both the JSON API and the Vue frontend from one app**: Gemfile declares rails 7.2.3.1 and vite_rails, integrating the Vite-built Vue dashboard directly into the Rails asset pipeline rather than running it as a fully separate frontend service.
2. **Sidekiq with Redis handles all asynchronous and scheduled work**: Gemfile includes sidekiq (~> 7.3.10), sidekiq-cron for scheduled jobs, sidekiq_alive for healthchecks, and judoscale-sidekiq for CloudWatch-based autoscaling metrics, making Sidekiq the single background-processing system for message delivery, integrations, and reports.
3. **Realtime dashboard updates run over Action Cable, not a separate websocket service**: The frontend package.json depends on @rails/actioncable, connecting directly to the Rails process for live conversation updates, typing indicators, and presence, keeping realtime infrastructure inside the same Rails/Redis stack used for background jobs.
4. **Search runs on OpenSearch through Searchkick rather than Postgres full-text search**: Gemfile pairs searchkick with opensearch-ruby and faraday_middleware-aws-sigv4 (for signed AWS OpenSearch requests), giving conversation and contact search a dedicated search index instead of relying on Postgres.
5. **Multiple cloud storage backends are supported through one abstraction**: Gemfile depends on aws-sdk-s3, azure-blob, and google-cloud-storage together (all required: false, loaded conditionally), letting self-hosters pick S3, Azure Blob, or Google Cloud Storage for Active Storage attachments without code changes.
6. **The release pipeline runs a Postgres migration step before the app boots**: The Procfile defines a release phase (POSTGRES_STATEMENT_TIMEOUT=600s bundle exec rails db:chatwoot_prepare) that runs before the web and worker dynos start, ensuring schema migrations complete first on Heroku-style deploys.
7. **Dev runs Rails, Sidekiq, and Vite as separate Compose services with shared volumes**: docker-compose.yaml defines rails, sidekiq, vite, postgres, redis, and mailhog services that all depend on a common base image built from docker/Dockerfile, with the rails service explicitly depending on postgres, redis, vite, mailhog, and sidekiq before starting.
---
## 4. NON-NEGOTIABLE ARCHITECTURAL GUARDRAILS
1. **Monorepo & Modular Separation**:
   - Structure as a Turborepo monorepo with strict package boundaries:
     - `apps/web`: Application UI, routing, layouts, and server endpoints.
     - `packages/ui`: Shared design tokens, CSS variables, and Radix UI primitive components.
     - `packages/db`: Database schemas, client singleton, declarative migrations, and seed scripts.
     - `packages/config`: Shared TypeScript, ESLint, and build configurations.
2. **Strict Type Safety & Zero `any` Policy**:
   - Enable `strict: true`, `noImplicitAny: true`, and `strictNullChecks: true`.
   - Validate ALL external inputs, API request bodies, and query parameters with **Zod** schemas before execution.
3. **Frontend & Rendering Guidelines**:
   - Utilize Vite 6 with TanStack Router for fully type-safe routing. Manage server state and caching via TanStack Query v5 with optimistic UI updates.
4. **Design System & Aesthetics**:
   - Keep every color, radius, shadow and font in a single token file (CSS variables) and consume tokens everywhere; never hardcode hex values in components.
   - Prefer crisp 1px borders and one subtle shadow scale over blurry default shadows. Pair one sans-serif for body/headings with one monospace for tags, badges, metrics, and code.
5. **Data Layer & Reliability**:
   - Write declarative schema definitions with foreign keys, composite indexes on queried filters, and automated timestamp triggers.
   - Use connection pooling and prepared statements for serverless database execution.
---
## 5. STEP-BY-STEP SCAFFOLDING ROADMAP
- **Phase 1: Workspace & Root Config**: Initialize package manager, monorepo configuration (`turbo.json`, `tsconfig.base.json`, `package.json`).
- **Phase 2: Database Schema & Client**: Set up the data layer (PostgreSQL, Redis, OpenSearch): client, connection pool, models, and migration scripts.
- **Phase 3: Design Tokens & UI Primitives**: Build accessible `Button`, `Input`, `Card`, `Badge`, and layout wrappers inside `packages/ui`.
- **Phase 4: Core Application Routes & Handlers**: Implement primary authentication, user session handling, and application routes.
- **Phase 5: Quality Assurance & Build Verification**: Run `tsc --noEmit`, ESLint, Prettier, and smoke test suites to ensure zero compilation or runtime errors.
---
## 6. EXECUTION INSTRUCTIONS
1. Review all specifications, architectural guardrails, and stack choices above.
2. Present the full monorepo directory tree structure.
3. Systematically generate the complete, production-ready codebase according to the 5-phase roadmap above — starting with the root workspace setup, followed by the database schema, UI design system package, and full-stack application routes until the repository is fully scaffolded and ready to run.
Scaffolded something with this prompt?
Would you pick this stack for a customer support suite project?

Frequently asked about Chatwoot

What is Chatwoot built with?

Chatwoot is a Ruby on Rails application with a Vue frontend built via Vite, using PostgreSQL for data, Redis-backed Sidekiq for background jobs, Action Cable for realtime updates, and OpenSearch (via Searchkick) for search.

Does Chatwoot need a separate realtime or websocket server?

No. Realtime conversation updates run over Action Cable, served from the same Rails process and backed by Redis, so no standalone websocket service is required.

Can I self-host Chatwoot?

Yes. docker/Dockerfile builds a production image, docker-compose.yaml runs a full local stack (Rails, Sidekiq, Vite, Postgres, Redis, Mailhog), and the Procfile supports Heroku-style web/worker/release process deploys.

What does Chatwoot use for search?

Chatwoot indexes conversations and contacts into OpenSearch using the Searchkick gem, with opensearch-ruby and AWS SigV4 signing support for hosted OpenSearch services, rather than relying on Postgres full-text search.

Where can Chatwoot store file attachments?

The Gemfile includes aws-sdk-s3, azure-blob, and google-cloud-storage as optional dependencies, so self-hosters can configure Active Storage to use Amazon S3, Azure Blob Storage, or Google Cloud Storage.

One email a month: new deep dives and stack trends

New source-audited architectures, head-to-head comparisons and the monthly stack report. No spam, unsubscribe anytime.

use-this-stack.md