Skip to content

Self-hosting the full stack outside Cloudflare — working Miniflare-based deployment, offering fixes upstream #352

Description

@tlvenn

We run Maple fully self-hosted (no Cloudflare, no Tinybird): vanilla ClickHouse per docs/self-hosted-clickhouse.md with the prebuilt collector, plus the three workers (api, alerting, electric-sync) running under Miniflare in a single container, Hyperdrive bound to a local Postgres 17, Electric fronted by the electric-sync worker, drizzle migrations on boot, chat/AI-triage on the OpenRouter fallback. It's validated end-to-end (auth → Electric shapes → ClickHouse queries) and lives at tlvenn/maple (deploy/workerd/).

Along the way we found the in-repo Docker path has drifted: apps/api/Dockerfile runs bun run start which no longer exists, docker-compose.yml references apps/alerting/apps/electric-sync Dockerfiles that aren't in the tree, and apps/web/Dockerfile can't build because .dockerignore excludes packages/browser/packages/effect-sdk and @maple-dev/clickhouse-builder's dist is never built (also @maple-dev/browser is imported by the web app but not declared, so it only resolves via hoisting).

If there's interest, I'd like to upstream this in pieces:

  1. the web Dockerfile/.dockerignore fixes — happy to open that PR immediately;
  2. cleaning up or fixing the stale api/compose Docker references — your call whether those should be fixed or removed;
  3. the Miniflare runtime as an official self-host deployment path, with docs.

No hard feelings if (3) isn't the direction you want — even just (1)+(2) would help other self-hosters.

Activity

  1. collegeimprovements commented on Aug 6, 2026

    @collegeimprovements

    Would be great if there is a blessed self-hosting guide. Ideally all powered by docker-compose. That will exponentially increase adoption. We are also blocked on this part right now in our company.

  2. Makisuo commented on Aug 6, 2026

    @Makisuo
    Collaborator

    Hey @tlvenn this is amazing you selfhost it even though it still quite painful to self host right now!
    My goal is it to make self hosting Maple as easy as possible best case making it a one click Selfhost experience, would love to see your fixes upstreamed to make it easier for people.

    Instead of miniflare I was thinking of using https://github.com/denoland/celld long term for a bit more performance miniflare is lacking in, in my experience.

    If you have any issues/painponts or similar with self hosting etc. feel free to create an issue regardless of what it is or DM me directly

  3. tlvenn commented on Aug 7, 2026

    @tlvenn
    ContributorAuthor

    Thanks — and glad the direction resonates! We took a close look at celld, since a production-grade runtime is exactly what we'd want long-term too. TL;DR: celld looks like the right destination, but Maple's current worker surface can't run on it yet — the gaps are in Maple's binding choices, not in our deployment glue. Here's the api + alerting surface mapped against celld v0.1.0 (per docs/cloudflare-compat.md, as of today):

    Maple uses today celld v0.1.0
    DO CHAT_SESSION (SQLite) ✅ core strength — replicated + hibernating, nicer than anything we get from Miniflare
    fetch workers, JS RPC, service bindings, vars ✅
    Hyperdrive → Postgres (postgres.js over TCP) ❌ not planned, and no TCP sockets (connect() is an inert stub) — the DB layer can't reach Postgres at all
    cron triggers / scheduled handler (4 on api, 4 on alerting) ❌ not planned — celld's answer is DO alarms
    KV (MCP_SESSIONS) ❌ not planned — celld's answer is a DO
    Queues (vcs-sync, planetscale-webhooks) ❌ "if demand appears"; no queue handler
    Workflows (clickhouse-schema-apply, ai-triage) ⏳ planned
    ratelimit binding ❌ unknown wrangler keys fail the deploy
    broad nodejs_compat ⚠️ much narrower than workerd — the api bundle is untested territory

    So a celld-native Maple is really an upstream refactor: sessions KV → DO, queues → DO alarms, workflows → celld's planned Workflows, crons → alarms, and — the hardest one — a non-TCP Postgres path in packages/db (celld does support outbound WebSockets, so a Neon-serverless-style WS driver or a pg-over-WS gateway would work). All very doable, and honestly aligned with celld's "everything on DOs" philosophy — but it's your call on sequencing, and until then the Miniflare container is a working bridge (it's running the full stack for us today: api + alerting + electric-sync, Hyperdrive→Postgres, Electric shapes end-to-end).

    Fun detail: of our three workers, the only one that runs on celld today is electric-sync (fetch + vars only) — we may prototype that as a first cell.

    Meanwhile I'll start upstreaming the low-hanging fixes from the issue (web Dockerfile/.dockerignore first). For the stale api Dockerfile + compose references — want them fixed or removed? Happy to shape the PR either way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions