Open-Source Wikis

/

tldraw

/

Apps

/

apps/dotcom

tldraw/tldraw

apps/dotcom

Active contributors: Steve Ruiz, Mitja Bezenšek, Mime Čuvalo, Max Drake, David Sheldrick

Purpose

apps/dotcom/ is everything that runs at https://tldraw.com: the React Router single-page app, the Cloudflare workers that back it, and the Zero view-syncer that replicates app-state from Postgres to clients.

Directory layout

apps/dotcom/
├── README.md
├── snapshot-state.sh
├── restore-state.sh
├── wait-for-migrations.sh
├── client/                         # the SPA
├── sync-worker/                    # the multiplayer server
├── asset-upload-worker/            # asset uploads → R2
├── image-resize-worker/            # image variant serving
├── tldrawusercontent-worker/       # serves user content
└── zero-cache/                     # Zero view-syncer (Fly.io)

Client

apps/dotcom/client/ is a Vite-built React app with React Router (src/routes.tsx, src/routeDefs.ts) and Sentry instrumentation. The two main areas:

  • Anonymous editor. The classic tldraw.com/r/<roomId> whiteboard.
  • tla (tldraw app). A signed-in area at apps/dotcom/client/src/tla/ with folders, file management, sharing, and account settings. "tla" is short for "tldraw app".

Major sub-folders:

apps/dotcom/client/src/
├── main.tsx
├── routes.tsx
├── routeDefs.ts
├── routes.test.tsx
├── components/         # app-level React components
├── pages/              # route components
├── hooks/
├── utils/
├── tla/                # signed-in area (folders, files, sharing)
├── assets/
└── app.d.ts

The client uses the SDK via <Tldraw />, customizes it through the override system (packages/tldraw/src/lib/ui/overrides.ts), and connects to multiplayer via useSync from @tldraw/sync pointing at apps/dotcom/sync-worker/.

Workers

The dotcom backend is a fleet of Cloudflare Workers, each its own workspace.

sync-worker

apps/dotcom/sync-worker/ is the production multiplayer server. It hosts TLSocketRoom instances inside Durable Objects, persists snapshots to R2, and uses sqlite (in the DO) for tombstone tracking. Configured via wrangler.toml. Reads/writes dotcom-shared types so the client knows the message format.

asset-upload-worker

Handles uploaded image/video blobs from the canvas. Stores in R2 and returns asset URLs.

image-resize-worker

Serves resized image variants on demand (canvas needs different sizes for different zoom levels). Cached at the edge.

tldrawusercontent-worker

Serves user-generated content under a separate domain to isolate untrusted content from the main app domain.

zero-cache

apps/dotcom/zero-cache/ runs the Zero view-syncer on Fly.io. It replicates the Postgres app database (folders, file metadata, sharing) to clients in near real-time. Two roles deploy independently:

  • replication-manager — pulls Postgres replication events.
  • view-syncer — fans out per-client views.

Each has its own flyio-*.template.toml config (these are also among the most-changed files in the last 90 days). The wait-for-migrations.sh script in apps/dotcom/ ensures DB migrations run before zero-cache starts in dev.

How it works

graph TB
    User -->|HTTPS| Client[apps/dotcom/client]
    Client -->|wss://| SyncWorker[apps/dotcom/sync-worker]
    Client -->|HTTPS| AssetUpload[asset-upload-worker]
    Client -->|HTTPS| ImageResize[image-resize-worker]
    Client -->|HTTPS| UserContent[tldrawusercontent-worker]
    Client -->|sync| ZeroCache[zero-cache view-syncer]
    SyncWorker -->|R2| R2[Cloudflare R2]
    SyncWorker -->|sqlite in DO| DO[Durable Object SQLite]
    ZeroCache -->|replication| Postgres[(Postgres)]
    AssetUpload -->|R2| R2
    ImageResize -->|R2| R2

The split between room state (snapshots in R2 + DO sqlite, served by sync-worker) and app state (folders, files, sharing in Postgres, served by zero-cache) is deliberate: room state is large and mutates many times per second; app state is small and mutates rarely.

Deployments

GitHub Actions:

  • .github/workflows/deploy-dotcom.yml — main rolling deploy.
  • .github/workflows/staging-e2e.yml — staging environment Playwright tests.
  • .github/workflows/staging-cleanup-daily.yml.
  • .github/workflows/trigger-dotcom-hotfix.yml.
  • .github/workflows/trigger-production-build.yml.

internal/scripts/deploy-dotcom.ts (one of the most-touched files in the last 90 days) is the orchestrator. The Sentry release name is computed in apps/dotcom/client/sentry-release-name.ts.

Integration points

  • Imports. tldraw, @tldraw/sync, @tldraw/sync-core, @tldraw/store, dotcom-shared, worker-shared.
  • External services. Cloudflare (Workers, Durable Objects, R2, KV), Fly.io (zero-cache), Postgres, Sentry, Vercel-style preview deploys.

Entry points for modification

  • A new dotcom feature. Most lives under apps/dotcom/client/src/tla/ (signed-in) or apps/dotcom/client/src/components/ (anon).
  • A new sync behavior. Usually a sync-core change first, then plumbed through sync-worker.
  • A new asset type. Touch asset-upload-worker and dotcom-shared.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

apps/dotcom – tldraw wiki | Factory