
Connects Claude to a running Valkey or Redis instance and surfaces real time observability data through MCP tools. You get memory stats, client connections, keyspace metrics, slow queries, and cluster health without leaving your editor. Built on top of BetterDB's monitoring stack, which they also ship as a standalone web dashboard and CLI. Useful when you're debugging cache behavior, investigating performance issues, or need to check database state while writing code that hits Redis. The same company ships semantic caching libraries for LLMs, so the MCP integration feels like a natural extension of that tooling.
claude mcp add monitor --env BETTERDB_URL=YOUR_BETTERDB_URL --env BETTERDB_TOKEN=YOUR_BETTERDB_TOKEN --env BETTERDB_INSTANCE_ID=YOUR_BETTERDB_INSTANCE_ID -- npx -y @betterdb/mcpRun in your terminal. Replace YOUR_* placeholders with real values; add --scope user to install for every project.
Review the command, arguments, and environment values before installing — MCP servers run with your local permissions.
Verified live against the running server on Jun 10, 2026.
list_instancesList all Valkey/Redis instances registered in BetterDB. Shows connection status and capabilities.List all Valkey/Redis instances registered in BetterDB. Shows connection status and capabilities.
No parameters — call it with no arguments.
select_instanceSelect which instance subsequent tool calls operate on.1 paramsSelect which instance subsequent tool calls operate on.
instanceId*stringadd_connectionAdd a new Valkey/Redis connection to BetterDB. Optionally set it as the active default.6 paramsAdd a new Valkey/Redis connection to BetterDB. Optionally set it as the active default.
host*stringname*stringpasswordstringportintegersetAsDefaultbooleanusernamestringtest_connectionTest a Valkey/Redis connection without persisting it. Use before add_connection to validate credentials.5 paramsTest a Valkey/Redis connection without persisting it. Use before add_connection to validate credentials.
host*stringname*stringpasswordstringportintegerusernamestringremove_connectionRemove a connection from BetterDB.1 paramsRemove a connection from BetterDB.
instanceId*stringset_default_connectionSet a connection as the active default for BetterDB.1 paramsSet a connection as the active default for BetterDB.
instanceId*stringget_infoGet INFO stats for the active instance. Contains all health data: memory, clients, replication, keyspace, stats (hit rate, ops/sec), and server info. Optionally filter to a section: server|clients|memory|stats|replication|keyspace.2 paramsGet INFO stats for the active instance. Contains all health data: memory, clients, replication, keyspace, stats (hit rate, ops/sec), and server info. Optionally filter to a section: server|clients|memory|stats|replication|keyspace.
instanceIdstringsectionstringget_slowlogGet the most recent slow commands from the slowlog.2 paramsGet the most recent slow commands from the slowlog.
countnumberinstanceIdstringget_commandlogGet the most recent entries from COMMANDLOG (Valkey 8+ only, superset of slowlog).2 paramsGet the most recent entries from COMMANDLOG (Valkey 8+ only, superset of slowlog).
countnumberinstanceIdstringget_latencyGet latency event history for the active instance.1 paramsGet latency event history for the active instance.
instanceIdstringget_memoryGet memory diagnostics: MEMORY DOCTOR assessment and MEMORY STATS breakdown.1 paramsGet memory diagnostics: MEMORY DOCTOR assessment and MEMORY STATS breakdown.
instanceIdstringget_clientsGet the active client list with connection details.1 paramsGet the active client list with connection details.
instanceIdstringget_healthGet a synthetic health summary for the active instance: keyspace hit rate, memory fragmentation ratio, connected clients, replication lag (replicas only), and keyspace size. Use this as the first call when investigating an instance — it surfaces the most actionable signals wit...1 paramsGet a synthetic health summary for the active instance: keyspace hit rate, memory fragmentation ratio, connected clients, replication lag (replicas only), and keyspace size. Use this as the first call when investigating an instance — it surfaces the most actionable signals wit...
instanceIdstringget_slowlog_patternsGet analyzed slowlog patterns from persisted storage. Groups slow commands by normalized pattern, showing frequency, average duration, and example commands. Survives slowlog buffer rotation — data goes back as far as BetterDB has been running.2 paramsGet analyzed slowlog patterns from persisted storage. Groups slow commands by normalized pattern, showing frequency, average duration, and example commands. Survives slowlog buffer rotation — data goes back as far as BetterDB has been running.
instanceIdstringlimitnumberget_commandlog_historyGet persisted COMMANDLOG entries from storage (Valkey 8+ only). Supports time range filtering to investigate specific incidents. Returns empty with a note if COMMANDLOG is not supported on this instance.6 paramsGet persisted COMMANDLOG entries from storage (Valkey 8+ only). Supports time range filtering to investigate specific incidents. Returns empty with a note if COMMANDLOG is not supported on this instance.
commandstringendTimenumberinstanceIdstringlimitnumberminDurationnumberstartTimenumberget_commandlog_patternsGet analyzed COMMANDLOG patterns from persisted storage (Valkey 8+ only). Like get_slowlog_patterns but includes large-request and large-reply patterns in addition to slow commands.4 paramsGet analyzed COMMANDLOG patterns from persisted storage (Valkey 8+ only). Like get_slowlog_patterns but includes large-request and large-reply patterns in addition to slow commands.
endTimenumberinstanceIdstringlimitnumberstartTimenumberget_anomaliesGet anomaly detection events from persisted storage. BetterDB continuously runs Z-score analysis on memory, hit rate, CPU, and other metrics — this returns the detected anomalies. Use to investigate what triggered an alert or correlate with an incident.4 paramsGet anomaly detection events from persisted storage. BetterDB continuously runs Z-score analysis on memory, hit rate, CPU, and other metrics — this returns the detected anomalies. Use to investigate what triggered an alert or correlate with an incident.
instanceIdstringlimitnumbermetricTypestringstartTimenumberget_client_activityGet time-bucketed client activity from persisted snapshots. Shows connection counts, command distribution, and buffer usage over time. Use startTime/endTime to focus on a specific incident window.4 paramsGet time-bucketed client activity from persisted snapshots. Shows connection counts, command distribution, and buffer usage over time. Use startTime/endTime to focus on a specific incident window.
bucketSizeMinutesnumberendTimenumberinstanceIdstringstartTimenumberget_hot_keysGet hot key tracking data from persisted storage. BetterDB periodically scans keys using LFU frequency scores (when maxmemory-policy is an LFU variant) or OBJECT IDLETIME / COMMANDLOG-derived frequency. Each snapshot captures the top keys ranked by access frequency. Use this t...4 paramsGet hot key tracking data from persisted storage. BetterDB periodically scans keys using LFU frequency scores (when maxmemory-policy is an LFU variant) or OBJECT IDLETIME / COMMANDLOG-derived frequency. Each snapshot captures the top keys ranked by access frequency. Use this t...
endTimenumberinstanceIdstringlimitnumberstartTimenumberget_cluster_nodesDiscover all nodes in the Valkey cluster — role (master/replica), address, health status, and slot ranges. Returns an error message if this instance is not running in cluster mode.1 paramsDiscover all nodes in the Valkey cluster — role (master/replica), address, health status, and slot ranges. Returns an error message if this instance is not running in cluster mode.
instanceIdstringget_cluster_node_statsGet per-node performance stats: memory usage, ops/sec, connected clients, replication offset, and CPU. Use this to identify hot nodes, lagging replicas, or uneven load distribution.1 paramsGet per-node performance stats: memory usage, ops/sec, connected clients, replication offset, and CPU. Use this to identify hot nodes, lagging replicas, or uneven load distribution.
instanceIdstringget_cluster_slowlogGet the aggregated slowlog across ALL nodes in the cluster. This is the primary tool for finding slow commands in cluster mode — per-node slowlogs are incomplete. Returns an error message if not in cluster mode.2 paramsGet the aggregated slowlog across ALL nodes in the cluster. This is the primary tool for finding slow commands in cluster mode — per-node slowlogs are incomplete. Returns an error message if not in cluster mode.
instanceIdstringlimitnumberget_slot_statsGet per-slot key counts and CPU usage (Valkey 8.0+ only). Use orderBy='cpu-usec' to find hot slots, or 'key-count' to find the most populated slots. Returns an error message if not supported.3 paramsGet per-slot key counts and CPU usage (Valkey 8.0+ only). Use orderBy='cpu-usec' to find hot slots, or 'key-count' to find the most populated slots. Returns an error message if not supported.
instanceIdstringlimitnumberorderBystringkey-count · cpu-usecget_latency_historyGet the full latency history for a named event (e.g. 'command', 'fast-command'). Call get_latency first to see which event names are available, then use this to investigate a specific event's trend over time.2 paramsGet the full latency history for a named event (e.g. 'command', 'fast-command'). Call get_latency first to see which event names are available, then use this to investigate a specific event's trend over time.
eventName*stringinstanceIdstringget_acl_auditGet persisted ACL audit log entries from storage. Filter by username, reason (auth, command, key, channel), or time range. Use this to investigate why a connection is failing or audit access patterns.6 paramsGet persisted ACL audit log entries from storage. Filter by username, reason (auth, command, key, channel), or time range. Use this to investigate why a connection is failing or audit access patterns.
endTimenumberinstanceIdstringlimitnumberreasonstringstartTimenumberusernamestringstart_monitorStart the BetterDB monitor as a persistent background process. If already running, returns the existing URL. The monitor persists across MCP sessions and must be stopped explicitly with stop_monitor.2 paramsStart the BetterDB monitor as a persistent background process. If already running, returns the existing URL. The monitor persists across MCP sessions and must be stopped explicitly with stop_monitor.
portintegerstoragestringsqlite · memorydefault: sqlitecache_listList all caches (semantic_cache and agent_cache) registered for the active instance, with hit rate and total ops.1 paramsList all caches (semantic_cache and agent_cache) registered for the active instance, with hit rate and total ops.
instanceIdstringcache_healthDetailed health for a single cache. Response branches by type: semantic_cache reports category_breakdown + uncertain_hit_rate; agent_cache reports tool_breakdown.2 paramsDetailed health for a single cache. Response branches by type: semantic_cache reports category_breakdown + uncertain_hit_rate; agent_cache reports tool_breakdown.
cache_name*stringinstanceIdstringcache_threshold_recommendationThreshold-tuning recommendation for a semantic_cache, based on the rolling similarity-score window. Errors with INVALID_CACHE_TYPE on agent_cache.4 paramsThreshold-tuning recommendation for a semantic_cache, based on the rolling similarity-score window. Errors with INVALID_CACHE_TYPE on agent_cache.
cache_name*stringcategorystringinstanceIdstringminSamplesintegercache_tool_effectivenessPer-tool hit rate, cost saved, and TTL recommendation for an agent_cache. Errors with INVALID_CACHE_TYPE on semantic_cache.2 paramsPer-tool hit rate, cost saved, and TTL recommendation for an agent_cache. Errors with INVALID_CACHE_TYPE on semantic_cache.
cache_name*stringinstanceIdstringcache_similarity_distributionHistogram of recent similarity scores (20 buckets, width 0.1) for a semantic_cache. Errors on agent_cache.4 paramsHistogram of recent similarity scores (20 buckets, width 0.1) for a semantic_cache. Errors on agent_cache.
cache_name*stringcategorystringinstanceIdstringwindow_hoursintegercache_recent_changesRecent proposals for a single cache (any status), so agents can avoid re-proposing pending or recently-applied changes. Newest first.3 paramsRecent proposals for a single cache (any status), so agents can avoid re-proposing pending or recently-applied changes. Newest first.
cache_name*stringinstanceIdstringlimitintegercache_propose_threshold_adjustPropose a semantic-cache similarity-threshold change for review. Creates a pending proposal that requires human approval before any change is applied. Reasoning must be at least 20 characters.5 paramsPropose a semantic-cache similarity-threshold change for review. Creates a pending proposal that requires human approval before any change is applied. Reasoning must be at least 20 characters.
cache_name*stringcategoryvalueinstanceIdstringnew_threshold*numberreasoning*stringcache_propose_tool_ttl_adjustPropose an agent-cache per-tool TTL change for review. Creates a pending proposal that requires human approval. Reasoning must be at least 20 characters.5 paramsPropose an agent-cache per-tool TTL change for review. Creates a pending proposal that requires human approval. Reasoning must be at least 20 characters.
cache_name*stringinstanceIdstringnew_ttl_seconds*integerreasoning*stringtool_name*stringcache_propose_invalidatePropose a cache invalidation for review. Filter shape depends on cache type: semantic_cache requires filter_kind=valkey_search + filter_expression; agent_cache requires filter_kind in (tool|key_prefix|session) + filter_value. Warns when estimated_affected exceeds 10000.7 paramsPropose a cache invalidation for review. Filter shape depends on cache type: semantic_cache requires filter_kind=valkey_search + filter_expression; agent_cache requires filter_kind in (tool|key_prefix|session) + filter_value. Warns when estimated_affected exceeds 10000.
cache_name*stringestimated_affected*integerfilter_expressionstringfilter_kind*stringvalkey_search · tool · key_prefix · sessionfilter_valuestringinstanceIdstringreasoning*stringcache_list_pending_proposalsList pending cache proposals for the active instance, newest first. Optionally filter by cache_name.3 paramsList pending cache proposals for the active instance, newest first. Optionally filter by cache_name.
cache_namestringinstanceIdstringlimitintegercache_get_proposalFetch a single cache proposal by id, including its audit trail.1 paramsFetch a single cache proposal by id, including its audit trail.
proposal_id*stringcache_approve_proposalApprove a pending proposal. Synchronously applies the change to Valkey and returns the terminal status (applied|failed). Idempotent: a second call on an already-applied proposal returns the cached result.2 paramsApprove a pending proposal. Synchronously applies the change to Valkey and returns the terminal status (applied|failed). Idempotent: a second call on an already-applied proposal returns the cached result.
actorstringproposal_id*stringcache_reject_proposalReject a pending proposal. Optionally records a reason in the audit trail.3 paramsReject a pending proposal. Optionally records a reason in the audit trail.
actorstringproposal_id*stringreasonstringcache_edit_and_approve_proposalEdit an existing pending proposal and approve it in one step. Provide exactly one edit field matching the proposal type: new_threshold for threshold_adjust, new_ttl_seconds for tool_ttl_adjust. Invalidate proposals are not editable.4 paramsEdit an existing pending proposal and approve it in one step. Provide exactly one edit field matching the proposal type: new_threshold for threshold_adjust, new_ttl_seconds for tool_ttl_adjust. Invalidate proposals are not editable.
actorstringnew_thresholdnumbernew_ttl_secondsintegerproposal_id*stringstop_monitorStop a persistent BetterDB monitor process that was previously started with start_monitor or --autostart --persist.Stop a persistent BetterDB monitor process that was previously started with start_monitor or --autostart --persist.
No parameters — call it with no arguments.
The monitoring layer that Valkey deserves.
BetterDB persists what Valkey throws away - slowlogs, command patterns, client activity, anomaly signals - so you can debug what happened at 3am, not just what's happening now. Built for Valkey 8.x with native support for COMMANDLOG, CLUSTER SLOT-STATS, and per-thread I/O metrics. Redis 6+ compatible for everything else.
Website | Docker Hub | npm | Documentation | Blog
BetterDB is built by BetterDB Inc., a public benefit company operating under the OCV Open Charter.

docker run -d --name betterdb -p 3001:3001 betterdb/monitor:latest
Point your browser to http://localhost:3001. To monitor a specific instance:
docker run -d \
--name betterdb \
-p 3001:3001 \
-e DB_HOST=your-valkey-host \
-e DB_PORT=6379 \
-e DB_PASSWORD=your-password \
betterdb/monitor:latest
Connecting to a database on your host machine? Inside the container
localhostis the container itself, not your host — so usehost.docker.internalas the database host. On Docker Desktop (macOS/Windows) it works out of the box; on Linux add--add-host=host.docker.internal:host-gatewayto thedocker runcommand so the name resolves. The dashboard's one-click "connect to local instance" button auto-detects this and pre-fills the right host for you.
Two image variants are published, both multi-arch (linux/amd64, linux/arm64):
| Tag | What it is |
|---|---|
latest, X.Y.Z-no-ai | Default image - every monitoring feature included, without the dependencies for the experimental local-LLM AI Helper |
X.Y.Z | Adds the experimental AI Helper (bring your own Ollama; disabled by default via AI_ENABLED) |
See Docker Production Deployment for persistent storage, custom ports, licensing, and air-gapped setups.
helm repo add betterdb https://docs.betterdb.com/charts
helm repo update
helm install betterdb-monitor betterdb/betterdb-monitor \
--namespace betterdb --create-namespace \
--set db.host=my-valkey.default.svc.cluster.local \
--set db.password=yourpassword
Then kubectl port-forward -n betterdb svc/betterdb-monitor 3001:3001 and open http://localhost:3001, or enable the chart's ingress. PostgreSQL-backed history, bring-your-own Secrets, and air-gapped licensing are all covered in the Kubernetes guide and the chart README.
Run BetterDB Monitor without Docker:
npx @betterdb/monitor
On first run, an interactive setup wizard guides you through database connection, storage backend (SQLite, PostgreSQL, or in-memory), and server settings. Configuration is saved to ~/.betterdb/config.json.
npm install -g @betterdb/monitor # global install
betterdb --setup # re-run setup wizard
betterdb --port 8080 # override server port
betterdb --db-host 1.2.3.4 # override database host
betterdb --help # all options
Requires Node.js >= 20.0.0 and a Valkey or Redis instance to monitor. For SQLite storage, also npm install -g better-sqlite3.
@betterdb/mcp.betterdb_* metrics. See docs/prometheus-metrics.md.| Interface | Details |
|---|---|
| Web UI | http://localhost:3001 |
| MCP server | npx @betterdb/mcp (stdio) - create a token under Settings → MCP Tokens |
| Prometheus | http://localhost:3001/api/prometheus/metrics |
| REST API (OpenAPI) | http://localhost:3001/docs |
| Health check | http://localhost:3001/api/health |
Note: In production builds (Docker, CLI) API routes are served under the
/apiprefix. In local development (pnpm dev) there is no prefix - e.g.http://localhost:3001/health.
| Database | Minimum Version | Supported Features |
|---|---|---|
| Valkey | 8.0+ | All features including COMMANDLOG (8.1+) and CLUSTER SLOT-STATS |
| Redis | 6+ | All features except the Valkey-exclusive COMMANDLOG and CLUSTER SLOT-STATS |
The backend uses a unified adapter over the wire-compatible iovalkey client and auto-detects Valkey vs Redis from the INFO response (DB_TYPE=auto). Capabilities like COMMANDLOG and SLOT-STATS are detected per version, and the UI gracefully degrades when a feature isn't available.
Managed services are supported too - guides for AWS ElastiCache, MemoryDB, Redis Cloud, and Upstash live in docs/providers, and @betterdb/agent reaches VPC-only instances over an outbound WebSocket.
The Docker image contains the monitoring application (backend + frontend). It requires:
docker run -d \
--name betterdb-monitor \
-p 3001:3001 \
-e DB_HOST=your-valkey-host \
-e DB_PORT=6379 \
-e DB_PASSWORD=your-password \
-e STORAGE_TYPE=postgres \
-e STORAGE_URL=postgresql://user:pass@postgres-host:5432/dbname \
betterdb/monitor
Set the PORT environment variable and match the -p mapping:
docker run -d \
--name betterdb-monitor \
-p 8080:8080 \
-e PORT=8080 \
-e DB_HOST=your-valkey-host \
betterdb/monitor
If your Valkey and PostgreSQL are running on the same host:
docker run -d \
--name betterdb-monitor \
--network host \
-e DB_HOST=localhost \
-e DB_PORT=6380 \
-e DB_PASSWORD=devpassword \
-e STORAGE_TYPE=postgres \
-e STORAGE_URL=postgresql://dev:devpass@localhost:5432/postgres \
betterdb/monitor
| Variable | Required | Default | Description |
|---|---|---|---|
DB_HOST | Yes | localhost | Valkey/Redis host to monitor |
DB_PORT | No | 6379 | Valkey/Redis port |
DB_PASSWORD | No | - | Valkey/Redis password |
DB_USERNAME | No | default | Valkey/Redis ACL username |
DB_TYPE | No | auto | Database type: auto, valkey, or redis |
STORAGE_TYPE | No | memory | Storage backend: memory or postgres |
STORAGE_URL | Conditional | - | PostgreSQL connection URL (required if STORAGE_TYPE=postgres) |
PORT | No | 3001 | Application HTTP port |
NODE_ENV | No | production | Node environment |
ANOMALY_DETECTION_ENABLED | No | true | Enable anomaly detection |
ANOMALY_PROMETHEUS_INTERVAL_MS | No | 30000 | Prometheus summary update interval (ms) |
BETTERDB_LICENSE_KEY | No | - | Online license key (Pro/Enterprise), validated over the network |
BETTERDB_OFFLINE_LICENSE_FILE | No | - | Path to a signed offline license .jwt for air-gapped hosts (see below) |
BETTERDB_OFFLINE_LICENSE | No | - | Offline license token as an inline JWT string |
BETTERDB_DATA_DIR | No | /app/data | Directory for persisted license state (mount a writable volume) |
ENCRYPTION_KEY | No | - | Key (min 16 chars) used to envelope-encrypt stored connection passwords and SSH tunnel secrets at rest. Without it, secrets are stored in plaintext |
BETTERDB_SSH_KEY_DIR | No | - | Directory that server-side SSH private keys must live in. Enables the "server file path" key source for SSH tunnels; a connection's key path must resolve inside it. Unset disables file-based keys (inline pasted keys still work) |
BETTERDB_TELEMETRY | No | true | Set false to disable anonymous telemetry |
Full reference, including AI, webhook tuning, and health-gate thresholds: docs/configuration.md. For OTLP trace ingest and metrics/event export, see docs/opentelemetry.md.
Connections can reach a database through an SSH bastion/jump host instead of connecting directly — useful for Valkey/Redis in a private subnet, ElastiCache, or MemoryDB. Enable Connect via SSH tunnel when adding a connection and provide the SSH host, port, and username. A single hop is supported.
Authentication is either a password or a private key. Private keys come from one of two sources:
ENCRYPTION_KEY is set (envelope encryption); without that key it is stored in plaintext, like connection passwords. Works everywhere, including managed/cloud deployments.BETTERDB_SSH_KEY_DIR environment variable to the directory holding the allowed keys, and the referenced path must resolve inside it, so the API can never be coerced into reading arbitrary files. Leave BETTERDB_SSH_KEY_DIR unset to disable this option.Optionally pin the SSH server's host key fingerprint (SHA256:...) on the connection; when set, the tunnel is refused unless the server presents a matching key, preventing man-in-the-middle attacks on the bastion path. Left blank, the server identity is not verified (a warning is logged).
The tunnel forwards to the database over 127.0.0.1; when TLS is enabled the certificate is still validated against the real database hostname. Set ENCRYPTION_KEY so SSH passwords, key passphrases, and inline keys are encrypted at rest.
Known limitation — cluster/Sentinel topologies: only the connection you configure is tunnelled. Cluster and Sentinel monitoring fan out to the other nodes using the addresses those nodes advertise (CLUSTER NODES / Sentinel), and those per-node connections are made directly, not through the tunnel. If the other nodes are only reachable via the bastion (e.g. ElastiCache/MemoryDB in a private subnet), per-node views will be unavailable. Use SSH tunnels for single-node/primary monitoring, or place the monitor where it can reach the cluster nodes directly.
BetterDB Monitor unlocks Pro/Enterprise features in one of two ways, depending on whether the host has internet access:
BETTERDB_LICENSE_KEY. The monitor validates it
against betterdb.com and caches a locally-verified signed token, so your
tier keeps working through short outages and restarts.Every entitlement is a signed RS256 JWT. The monitor verifies it locally against public keys embedded in the image - it never has to reach a license server to trust a token. So an air-gapped host can run paid tiers with zero connectivity:
.jwt, Pro/Enterprise). It contains no
secrets and can't be tampered with - any edit breaks the signature.BETTERDB_OFFLINE_LICENSE_FILE (path), BETTERDB_OFFLINE_LICENSE
(inline string), or paste it in the UI under Settings → License → "Air-gapped
environment? Activate an offline license."When an offline token is configured and no BETTERDB_LICENSE_KEY is set, the
monitor makes zero outbound requests - license checks, telemetry, and update
pings are all disabled. It runs the granted tier until the token expires (perpetual
licenses re-download yearly), then reverts to Community.
# fully offline - no network required
docker volume create betterdb-data
docker run --rm -v betterdb-data:/d alpine chown 1001:1001 /d # volume writable by UID 1001 (one-time)
docker run -d --name betterdb-monitor -p 3001:3001 \
-e DB_HOST=your-valkey-host -e DB_PORT=6379 -e DB_PASSWORD=your-password \
-v /path/to/betterdb-license.jwt:/run/secrets/betterdb-license.jwt:ro \
-e BETTERDB_OFFLINE_LICENSE_FILE=/run/secrets/betterdb-license.jwt \
-v betterdb-data:/app/data \
betterdb/monitor
Verify with GET /api/license/status → source: offline-token, mode: offline,
airGapped: true.
Persistence: mount a writable volume at
/app/dataso the offline license and the online outage-grace token survive restarts. The container runs as UID 1001, so a freshly-created volume must bechowned to it (shown above) - otherwise persistence fails withEACCES … license.jwt.
For the full flow, verification precedence, and key-rotation runbook see Offline & Air-Gapped Licenses and the Configuration reference.
node:20-alpinelatest / -no-ai) / ~640MB (versioned image with the experimental AI Helper's local-LLM dependencies)linux/amd64, linux/arm64docker logs -f betterdb-monitor # follow logs
docker stop betterdb-monitor # stop
docker rm betterdb-monitor # remove
BetterDB Monitor persists audit trail, analytics, captures, and anomaly data to one of four backends:
| Backend | Use case | Notes |
|---|---|---|
memory | Testing, ephemeral environments | Default in Docker; all data lost on restart |
postgres | Production | STORAGE_TYPE=postgres + STORAGE_URL=postgresql://user:pass@host:port/db |
turso | Production / serverless SQLite | STORAGE_TYPE=turso + STORAGE_URL=libsql://... + STORAGE_AUTH_TOKEN; works in Docker |
sqlite | Local development / CLI | Native module stripped from the latest Docker image; STORAGE_SQLITE_FILEPATH optional |
Metrics are exposed at GET /api/prometheus/metrics in Prometheus text format: ACL audit, client connections, slowlog/commandlog patterns, memory, throughput, keyspace, replication, cluster slot stats, and Node.js runtime metrics - all prefixed betterdb_.
scrape_configs:
- job_name: 'betterdb-monitor'
metrics_path: '/api/prometheus/metrics'
static_configs:
- targets: ['your-monitor-host:3001']
Full metric reference: docs/prometheus-metrics.md and docs/prometheus-integration.md.
betterdb-monitor/
├── apps/
│ ├── api/ # NestJS backend (Fastify)
│ └── web/ # React frontend (Vite)
├── packages/ # Published packages (see below)
├── docs/ # Documentation site (Jekyll)
├── docker-compose.yml # Local Valkey (port 6380) and Redis (port 6382) for testing
└── package.json # Workspace root
This monorepo ships several standalone packages. See packages/ for the full list.
| Package | Language | Registry |
|---|---|---|
@betterdb/monitor | TypeScript | npm |
@betterdb/mcp | TypeScript | npm |
@betterdb/agent | TypeScript | npm |
@betterdb/semantic-cache | TypeScript | npm |
betterdb-semantic-cache | Python | PyPI |
@betterdb/agent-cache | TypeScript | npm |
betterdb-agent-cache | Python | PyPI |
cache-benchmark | Python | Replay harness for benchmarking semantic caches |
iovalkey for Valkey/Redis connections, TypeScript strict mode. Port 3001.Prerequisites: Node.js >= 20.0.0, pnpm >= 9.0.0, Docker.
pnpm install
cp .env.example .env
pnpm docker:dev # local Valkey (6380) and Redis (6382)
pnpm dev # web on :5173, api on :3001
To connect to Redis instead of Valkey, set DB_PORT=6382 in .env.
pnpm dev:api # API only
pnpm dev:web # frontend only
pnpm docker:dev:down # stop local databases
pnpm build # production build
pnpm test # API tests
Docker image builds:
pnpm docker:build # local build
pnpm docker:publish # multi-arch build & push (requires buildx)
apps/api/src/apps/web/src/api/packages/shared/src/types/anydocs/ is licensed under CC BY-SA 4.0.proprietary/ is covered by a commercial license (see proprietary/LICENSE). These features are free during early access.BETTERDB_URLURL of the BetterDB monitor instance
BETTERDB_TOKENsecretMCP authentication token generated from the BetterDB Settings page
BETTERDB_INSTANCE_IDInstance ID to target when using multi-instance cloud deployments