The starter is Cloudflare-first: three Workers, one shared D1 database, a Cloudflare Queue plus its dead-letter queue for outbound webhook delivery, and shared Effect backbones in packages/capabilities (services), packages/api (HttpApi contracts), and packages/logger (wide-event logging).
Topology
The web Worker has the D1 binding wired; the shared capabilities runtime selects the Live layer when the binding is present and falls back to the in-memory Seed layer when it is not, so a fresh clone with no bindings still runs.
Why this shape
- Web and API are split Workers. The web Worker renders SSR, owns auth cookies, and runs server functions. The API Worker exposes the public REST and MCP Capability Interfaces over the same
packages/capabilitiesservices. Splitting them keeps the public surface independently deployable. - One D1 database. Auth tables (
user,session,account,verification) and starter tables (workspaces,workspace_members,workspace_invitations,audit_events,notifications,api_tokens,webhook_endpoints,webhook_deliveries) live in the same schema. There is no cross-database join story to design around. - Background is a separate Worker. The webhook queue consumer runs there with a dead-letter queue for replay after
maxRetries. Keeping it isolated from request-path code makes long-running operations safe. packages/capabilitiesis the shared backbone. Effect services for workspaces, audit events, notifications, tokens, and webhooks live here. The API app defines the matching HttpApi groups;packages/loggerdefines wide-event request scope helpers. Web, API, and background all depend on these.