Chartbrew sits in a practical place between spreadsheet exports, hand-built admin dashboards, and heavier BI platforms.
You connect it to APIs, SQL databases, NoSQL databases, and SaaS systems, build reusable datasets, then turn those results into dashboards, charts, public reports, and embeds.
What is Chartbrew?
Chartbrew is a self-hostable reporting application for building live charts and dashboards from databases and APIs.
The project is useful when you want a dashboard builder that can sit next to operational systems without pushing every question into a data warehouse first.
It supports classic database sources like MySQL, PostgreSQL, MongoDB, TimescaleDB, Supabase DB, RDS variants, and ClickHouse. It also has API and service-oriented sources such as REST APIs, Google Analytics, Firebase/Firestore, Customer.io, Jira, Strapi, and Stripe.
Why Self-Host Chartbrew?
- Keep dashboards close to your systems: Connect directly to internal databases and APIs.
- Control the deployment: Run the UI, API, database, and Redis in your own infrastructure.
- Share selectively: Use public dashboards, reports, embeds, and team roles instead of handing out database access.
- Extend through sources: The backend has a source plugin registry, and the frontend has matching source builders/forms.
Tech Overview of Chartbrew
Chartbrew is a JavaScript monorepo split into client/ and server/.
The frontend is a React 19 application built with Vite, HeroUI, Redux Toolkit, Tailwind, Monaco Editor, and Chart.js. It contains the dashboard builder, dataset screens, source connection forms, public dashboard views, reports, embeds, login/signup, and team settings.
The backend is an Express 5 API using Sequelize migrations/models, Redis, BullMQ, Socket.IO, JWT auth, encrypted secrets, and route-level authorization. It owns connections, data requests, datasets, chart preparation, team/project permissions, integrations, templates, queues, and AI-assisted workflows.
Architecture & Components
Chartbrew’s data model is organized around a few important objects:
- Connection: How Chartbrew reaches a database, API, or SaaS source.
- DataRequest: One query/request against a connection.
- Dataset: Reusable data built from one or more data requests, including joins.
- ChartDatasetConfig: The binding layer between reusable datasets and individual charts.
- Chart visualization: The semantic chart configuration used by the newer visualization runtime.
This split is useful. The dataset can stay focused on source data, joins, and scope, while the chart decides how that data should be presented.
The backend docs describe the runtime flow as connection -> data request -> dataset -> chart dataset config -> visualization engine -> Chart.js/table/metric/export output.
Key Technologies
- Frontend: React, Vite, HeroUI, Redux Toolkit, Tailwind, Chart.js, Monaco Editor.
- Backend: Node.js, Express, Sequelize, Socket.IO, BullMQ, Redis.
- Databases: MySQL or PostgreSQL for Chartbrew itself.
- Sources: REST APIs, MongoDB, PostgreSQL, MySQL, ClickHouse, Firebase, Google Analytics, Jira, Stripe, Customer.io, Strapi, and more.
- Testing: Vitest backend test suite with unit and integration coverage for auth, routes, visualization, migrations, source plugins, and security rules.
Self-Hosting Chartbrew with Docker
Chartbrew publishes a Docker image as razvanilin/chartbrew and includes both MySQL and PostgreSQL compose examples in the repository.
The app defaults to:
- Frontend:
4018 - API:
4019 - Redis:
6379 - MySQL:
3306if using the MySQL compose path
Pre-Requisites - Docker! 🐋
Install Docker on your system before proceeding:
- Linux: Official Docker Engine install guide
- Windows / Mac: Docker Desktop
Verify installation: docker --version && docker compose version
Docker Compose Configuration
The public Home-Lab snippets repository expected by my usual workflow was not available on this machine at /home/jalcocert/Desktop/Home-Lab, so this post includes the tested compose pattern directly.
This version avoids weak secret defaults and keeps Redis/MySQL non-public except for the host mappings you choose. For a normal single-host deployment, you can remove the Redis host port entirely if no external process needs it.
services:
db:
image: mysql:8.4
restart: unless-stopped
environment:
MYSQL_DATABASE: ${CB_DB_NAME:?Set CB_DB_NAME in .env}
MYSQL_USER: ${CB_DB_USERNAME:?Set CB_DB_USERNAME in .env}
MYSQL_PASSWORD: ${CB_DB_PASSWORD:?Set CB_DB_PASSWORD in .env}
MYSQL_RANDOM_ROOT_PASSWORD: "true"
MYSQL_DEFAULT_AUTH: caching_sha2_password
volumes:
- chartbrew-db:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 10
redis:
image: redis:alpine
restart: unless-stopped
chartbrew:
image: razvanilin/chartbrew:latest
restart: unless-stopped
environment:
CB_BULLMQ_USERNAME: ${CB_BULLMQ_USERNAME:?Set CB_BULLMQ_USERNAME in .env}
CB_BULLMQ_PASSWORD: ${CB_BULLMQ_PASSWORD:?Set CB_BULLMQ_PASSWORD in .env}
CB_DB_NAME: ${CB_DB_NAME:?Set CB_DB_NAME in .env}
CB_DB_USERNAME: ${CB_DB_USERNAME:?Set CB_DB_USERNAME in .env}
CB_DB_PASSWORD: ${CB_DB_PASSWORD:?Set CB_DB_PASSWORD in .env}
CB_DB_HOST: db
CB_DB_PORT: 3306
CB_DB_DIALECT: mysql
CB_REDIS_HOST: redis
CB_REDIS_PORT: 6379
CB_REDIS_PASSWORD: ""
CB_SECRET: ${CB_SECRET:?Set CB_SECRET in .env}
CB_ENCRYPTION_KEY: ${CB_ENCRYPTION_KEY:?Set CB_ENCRYPTION_KEY in .env}
CB_API_HOST: 0.0.0.0
CB_API_PORT: 4019
VITE_APP_CLIENT_HOST: ${VITE_APP_CLIENT_HOST:-http://localhost:4018}
VITE_APP_CLIENT_PORT: 4018
VITE_APP_API_HOST: ${VITE_APP_API_HOST:-http://localhost:4019}
CB_ADMIN_MAIL: ${CB_ADMIN_MAIL:[email protected]}
CB_RESTRICT_TEAMS: ${CB_RESTRICT_TEAMS:-0}
CB_RESTRICT_SIGNUP: ${CB_RESTRICT_SIGNUP:-0}
CB_ALLOW_PRIVATE_NETWORK_CALLS: "false"
ports:
- "4018:4018"
- "4019:4019"
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
volumes:
chartbrew-db:
Create a .env next to the compose file:
CB_BULLMQ_USERNAME=chartbrew
CB_BULLMQ_PASSWORD=<long-random-password>
CB_DB_NAME=chartbrew
CB_DB_USERNAME=chartbrew
CB_DB_PASSWORD=<long-random-password>
CB_SECRET=<long-random-string>
CB_ENCRYPTION_KEY=<64-hex-character-key>
VITE_APP_CLIENT_HOST=http://localhost:4018
VITE_APP_API_HOST=http://localhost:4019
Generate the encryption key with Node:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
Validate and start:
docker compose config
docker compose up -d
Open http://localhost:4018 and create the first account.
After that, consider setting:
CB_RESTRICT_SIGNUP=1
That prevents open signup after your initial user/team setup.
Field Note - Local Docker Trial
I tested Chartbrew locally on 2026-08-27 with Docker 29.7.2 and Docker Compose v5.5.0.
The host already had many running containers, so I did not run the repo compose file directly. I used an isolated Compose project named chartbrew_foss_trial with remapped host ports:
- Frontend:
4518 - API:
4519 - Redis:
6389 - MySQL:
3309
The first attempt hit Docker’s address pool exhaustion when Compose tried to create a new network:
all predefined address pools have been fully subnetted
The successful trial used Docker’s existing bridge network and unique container names. MySQL became healthy, Chartbrew ran all migrations, logs reported the Socket.IO Redis adapter as enabled, the API returned:
Welcome to chartBrew server API
The frontend returned HTTP/1.1 200 OK.
Idle memory during the trial was roughly 414 MiB for the app, 485 MiB for MySQL, and 13 MiB for Redis. I removed only the trial containers and trial database volume afterward.
Image Tag Caveat
The repository tag analyzed was v5.3.1, dated 2026-07-31.
During the Docker check, razvanilin/chartbrew:v5.3.1 did not exist on Docker Hub, while razvanilin/chartbrew:latest was available.
For production, prefer pinning to a stable tag or digest when the project publishes one that matches the version you want to run.
Security and Operations Notes
Chartbrew connects to sensitive systems, so treat it like an internal admin tool:
- Keep
CB_ENCRYPTION_KEYstable and private. It must be a 64-character hex string for AES-256 usage. - Protect the app behind TLS and your normal access controls.
- Keep
CB_ALLOW_PRIVATE_NETWORK_CALLS=falseunless you have a specific need and understand the risk. - Do not expose MySQL or Redis publicly.
- Set strong BullMQ dashboard credentials because
/apps/queuesis protected with Basic Auth. - Back up the database before upgrades because migrations run at application startup.
Recent repository history also shows active security hardening around Slack query execution, chart preview connection scoping, IPv6 SSRF handling, and team role escalation.
Conclusion
Chartbrew is worth a look if you want self-hosted dashboards without committing to a heavier warehouse-first BI stack.
It gives you a web UI for connecting sources, building datasets, creating charts, and sharing dashboards, while still keeping deployment understandable: one Node app, one relational database, and Redis.
The licensing deserves attention. Current versions use FSL-1.1-MIT: self-hosted internal use is allowed, but offering Chartbrew itself as a competing hosted product needs a commercial license. Each version becomes MIT two years after release.
For alternatives, compare it with Rill if you prefer code-first BI on DuckDB, WrenAI if you want natural-language analytics over databases, and Rybbit if your main use case is web/product analytics.
FAQ
Is Chartbrew open source?
Chartbrew uses the Functional Source License v1.1 with an MIT future grant.
That means current versions are source-available for permitted uses like internal self-hosting, and each version becomes MIT two years after its release date.
Can Chartbrew use PostgreSQL instead of MySQL?
Yes. The repository includes docker-compose-postgres.yml, and the environment supports CB_DB_DIALECT=postgres.
Use PostgreSQL if that is your standard operational database. Use MySQL if you want to follow the default compose path.
Does Chartbrew need Redis?
Yes for the full modern stack. Redis is used around queues, cache/runtime coordination, and Socket.IO scaling.
For Docker Compose, keep Redis internal to the Compose network unless you have a reason to expose it on the host.
What should I configure after first boot?
Create the first account, confirm the public client/API URLs are correct, then consider setting CB_RESTRICT_SIGNUP=1.
Also configure email settings if you need password reset and team invitations.
Comments