Maple is a free, open source monitoring & observability project written in TypeScript and released under a custom open-source licence. It has 1,783 GitHub stars, 119 forks and 29 open issues, and was last pushed 5 hours ago. On this registry it ranks #85 of 97 tracked projects in Monitoring & Observability, with 5 head-to-head comparisons available. It gained 9 stars over the last 6 tracked days.

What is Maple?

What it is

Maple is an open-source observability platform for traces, logs, and metrics, and it lives in the OpenTelemetry ecosystem within the Infrastructure & Operations / Monitoring & Observability category. The project is built on OpenTelemetry and ClickHouse, and the repository is organized as a TypeScript monorepo with a single-page application frontend and an Effect-based backend API.

Maple solves the concrete problem of collecting, querying, and operating telemetry data in one self-hostable codebase. The README describes an OTLP ingest gateway, a dashboard, alert evaluation, query and observability logic, and a native iOS app, which gives teams a path from raw telemetry ingestion to investigation and alerting without assembling each component separately.

Key capabilities

  • The ingest application accepts OTLP data through a gateway that performs key authentication, organization enrichment, and collector forwarding.
  • The API application exposes an Effect HTTP API, includes Tinybird proxy code, MCP server code, and AI chat/triage built on @opencode-ai/ai.
  • The web application is a TanStack Router single-page application built with Vite and shares domain contracts, query logic, and UI primitives through packages.
  • The alerting application runs as an evaluation worker, and the Cloudflare deployment model also includes a cron-driven alerting Worker.
  • The local mode runs as a single binary with OTLP ingest, embedded ClickHouse, and the dashboard, while Docker Compose runs API, web, ingest, and an OpenTelemetry collector.
  • The iOS application is native SwiftUI and uses Clerk with the v2 API.

Who uses it and how

  • Teams that need self-hosted telemetry can run the Docker local stack and point services to the API, web, ingest, and OpenTelemetry collector ports shown in the README.
  • Developers can try Maple as a local binary through Homebrew, then use bun dev to run selected apps such as api, web, ingest, or alerting behind a local Cloudflare runtime.
  • Platform teams can deploy the project to Cloudflare with Alchemy v2, using Workers for the API, alerting, ElectricSQL shape-proxy Worker, web, landing, and local UI.
  • Teams with CI can use the provided GitHub workflows for staging on pushes to main, manual production dispatch, and pull-request previews, with secrets fetched from Infisical through OIDC.
  • Operators can use the CLI utilities package and the shared query-engine package for command-line and observability query workflows.

Getting started

Typical install uses bun install after installing Bun >=1.3, and local trial uses brew install Makisuo/tap/maple followed by maple start. Docker local deployment uses docker compose -f docker-compose.yml up --build, and Cloudflare deployment uses Alchemy scripts such as bun run alchemy:deploy:stg and bun run alchemy:deploy:pr.

When to use it — and when not to

Maple fits teams that want an OpenTelemetry and ClickHouse based observability codebase with ingest, dashboard, alerting, query, and native app pieces in one monorepo. It is less suitable when a project requires a clear license, a long maintenance record, or a documented hosted option, because the provided metadata shows license NOASSERTION, zero contributors, a zero-year repository age, and a pull-request preview mode that binds no database. Teams that self-host must operate the listed backing services, including ClickHouse for local mode and Cloudflare resources such as Hyperdrive with PlanetScale Postgres, KV, queues, Workflows, and a Durable Object for the API.

project readme (upstream, from github) — read inline

Open-source observability for traces, logs & metrics — built on OpenTelemetry + ClickHouse.

Maple Monorepo

Maple is now organized as a monorepo with a SPA frontend and an Effect-based backend API.

Workspace Layout

  • apps/web: TanStack Router SPA (Vite)
  • apps/api: Effect HTTP API (Tinybird proxy + MCP server code + AI chat/triage on @opencode-ai/ai)
  • apps/ingest: OTLP ingest gateway (key auth + org enrichment + collector forwarding)
  • apps/landing: Astro landing site
  • apps/alerting: Alert evaluation worker
  • apps/cli: CLI utilities
  • apps/ios: Native SwiftUI app (Clerk + v2 API)
  • packages/domain: Shared Effect HTTP contracts and domain types
  • packages/query-engine: Shared query and observability logic
  • packages/ui: Shared UI primitives and components

Prerequisites

  • Bun >=1.3

Install

bun install

Try Maple Locally

Run Maple as a single local binary with OTLP ingest, embedded ClickHouse, and the dashboard:

brew install Makisuo/tap/maple
maple start

See docs/local-mode.md for Homebrew, manual installer, update, and uninstall details.

Develop

Run the whole stack — the Cloudflare Workers under alchemy's local runtime, the rest as child processes of the same alchemy dev — behind https://.localhost:

bun dev

Or just some of it (api, alerting, electric-sync, web, landing, ingest, local-ui, scraper):

bun dev api web

A single non-Worker app can also run on its raw port, outside the stack:

bun --filter=@maple/web dev

Validate

bun run typecheck
bun run build
bun run test

Docker (Local)

Run the local multi-service stack (API + web + ingest + otel collector):

docker compose -f docker-compose.yml up --build

Services:

  • API: http://localhost:3472
  • Web: http://localhost:3471
  • Ingest: http://localhost:3474
  • OTEL collector: 4317 (gRPC), 4318 (HTTP), 13133 (health/extensions)

Cloudflare Deploy (Alchemy)

Deployments run on Alchemy v2 (Effect-based): the root alchemy.run.ts exports a single Alchemy.Stack("maple", …) whose program yields one module per app:

  • apps/api/src/worker.ts — the api Worker: Hyperdrive (PlanetScale Postgres) MAPLE_DB, KV, queues, the two Workflows and the ChatSession Durable Object, all yielded from its init
  • apps/alerting/src/worker.ts — cron-driven alerting Worker (cross-script workflow ref)
  • apps/electric-sync/src/worker.ts — ElectricSQL shape-proxy Worker
  • apps/web/src/worker.ts / apps/landing/src/worker.ts / apps/local-ui/src/worker.ts — static builds via Command.Build + asset-serving Workers

Stage grammar is prd / stg / pr- / dev names, resolved via @maple/infra/cloudflare (parseMapleStage, resolveMapleDomains, resolveWorkerName, resolveHyperdriveRefId, resolveDatabaseMode). stg/prd bind the dashboard-managed Hyperdrive by config ID (resolveHyperdriveRefId) — origin credentials never touch a deploy. MAPLE_PG_URL is only needed for dev stages, whose Hyperdrive alchemy manages itself. PR previews bind no database at all (resolveDatabaseMode"none"): DB-backed routes 500, everything else in the preview works.

Run locally:

bun run alchemy:deploy:stg
PR_NUMBER=123 bun run alchemy:deploy:pr

The first v2 deploy against a stage with live v1-created resources needs --adopt (the pr script passes it already); v1 state is incompatible and simply abandoned — never run a v1 alchemy destroy against a live stage.

Tear down:

bun run alchemy:destroy:stg
PR_NUMBER=123 bun run alchemy:destroy:pr

CI workflows:

  • STG (default on push to main): .github/workflows/deploy-stg.yml
  • PRD (manual only via workflow_dispatch): .github/workflows/deploy-prd.yml
  • PR preview lifecycle: .github/workflows/deploy-pr-preview.yml (pull_request opened/synchronize/reopened/closed)

Secrets source model (CI):

  • Secrets are fetched from Infisical via Infisical/secrets-action using OIDC (credential-less — GitHub's OIDC token authenticates a machine identity, no long-lived token stored). CI needs:
    • GitHub repo variable INFISICAL_PROJECT_SLUG (the project slug — a variable, not a secret: GitHub masks secret values everywhere, and a slug like maple would then blank out the PR-preview deployment URL app-pr-.maple.dev)
    • GitHub repo secret INFISICAL_MACHINE_IDENTITY_ID (the machine identity ID)
  • Infisical environments (prod, staging, dev — mapped from the old Doppler prd/stg/pr configs) must define:
    • CLOUDFLARE_API_TOKEN
    • CLOUDFLARE_DEFAULT_ACCOUNT_ID (bridged to alchemy v2's CLOUDFLARE_ACCOUNT_ID in the root alchemy.run.ts; ALCHEMY_PASSWORD/ALCHEMY_STATE_TOKEN were v1-only and are no longer read)
    • TINYBIRD_HOST
    • TINYBIRD_TOKEN
    • EMAIL_FROM (sender address on an onboarded Cloudflare Email Service domain; delivery uses the EMAIL worker binding, no API key)
    • MAPLE_INGEST_KEY_ENCRYPTION_KEY
    • MAPLE_INGEST_KEY_LOOKUP_HMAC_KEY
    • MAPLE_AUTH_MODE
    • MAPLE_ROOT_PASSWORD (required in self_hosted mode)
    • CLERK_SECRET_KEY
    • CLERK_PUBLISHABLE_KEY
    • CLERK_JWT_KEY

Setup note: the machine identity must have a GitHub OIDC auth method configured in Infisical (scoped to this repo, ideally to the production/staging/pr-preview GitHub environments) and read access to the project. The workflows select secrets via project-slug (INFISICAL_PROJECT_SLUG) and per-stage env-slug (prod/staging/dev).

Runtime API URL behavior:

  • Deploy-time web builds resolve VITE_API_BASE_URL from the Cloudflare api worker domain (api.maple.dev in prd, api-staging.maple.dev in stg, worker.dev URL for pr-*).
  • Local bun --filter=@maple/web dev can still use root .env VITE_API_BASE_URL for local API routing.

Environment

  • Canonical env example: .env.example
  • API-only env example: apps/api/.env.example
  • Real .env values are local-only and should stay untracked.

The web app expects VITE_API_BASE_URL to point to the API (defaults to http://localhost:3472).

For ingest + key auth, set these at minimum in your root .env when running the ingest gateway:

  • MAPLE_INGEST_KEY_LOOKUP_HMAC_KEY
  • MAPLE_INGEST_KEY_ENCRYPTION_KEY (required when ingest reads encrypted credentials from Postgres)
  • INGEST_PORT
  • INGEST_FORWARD_OTLP_ENDPOINT
  • MAPLE_INTERNAL_ORG_ID (the org the gateway's own telemetry is filed under; no default)
  • INGEST_FORWARD_TIMEOUT_MS
  • INGEST_MAX_REQUEST_BODY_BYTES
  • INGEST_REQUIRE_TLS
  • INGEST_REPLAY_MAX_SESSION_BYTES (optional; ceiling on the decompressed rrweb payload one replay session may record, default 1 GiB, 0 disables)

Persistence (PostgreSQL / PGlite)

Maple persists application state in PostgreSQL:

  • Production and staging use PlanetScale Postgres through Cloudflare Hyperdrive.
  • Wrangler development uses the Docker Postgres started by bun db:up.
  • Non-Worker local entrypoints use embedded PGlite under apps/api/.data/pglite; set MAPLE_DB_URL=memory:// for an ephemeral database.

Migration commands:

bun db:up
bun db:migrate:local
bun run --cwd packages/db db:generate
bun run --cwd packages/db db:studio

CI migrates deployed PlanetScale branches over their direct port before Alchemy deploys the Workers. See docs/persistence.md for the full workflow.

Ingest Keys

  • Maple now manages per-org ingest keys in the database (public + private).
  • Keys are available in Settings and can be rerolled independently.
  • Reroll revokes the previous key immediately.
  • Private ingest keys are encrypted at rest with MAPLE_INGEST_KEY_ENCRYPTION_KEY (base64-encoded 32-byte key).
  • Ingest key lookup/auth uses non-reversible HMAC hashes via MAPLE_INGEST_KEY_LOOKUP_HMAC_KEY.

Auth Modes

Maple supports exactly two auth modes via MAPLE_AUTH_MODE:

  1. clerk
    • Create a Clerk application with Organizations enabled.
    • Set MAPLE_AUTH_MODE=clerk
    • Set CLERK_SECRET_KEY
    • Optionally set CLERK_JWT_KEY for networkless verification
    • Set CLERK_PUBLISHABLE_KEY for the web app
    • Optionally override VITE_CLERK_SIGN_IN_URL and VITE_CLERK_SIGN_UP_URL
  2. self_hosted
    • Set MAPLE_AUTH_MODE=self_hosted
    • Set MAPLE_ROOT_PASSWORD (required)
    • Set MAPLE_DEFAULT_ORG_ID (defaults to default)
    • Users must sign in at /sign-in with the root password before accessing the dashboard/API.
    • Session tokens are valid for 12 hours and renew silently against POST /api/auth/session/refresh, up to an absolute cap

readme truncated — read the full docs on github

Frequently asked questions

Is Maple free to use?

Maple is open source. There is no licence fee and no seat count — you can self-host it or, where the project offers one, pay a vendor for a managed version instead.

What does Maple do?

OpenTelemetry observability with traces, logs, and metrics

What is Maple written in?

Maple is primarily written in TypeScript. Its source is publicly available at https://github.com/MapleTechLabs/maple, and it has 1,783 GitHub stars.