Skip to content

wdl-dev/wdl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

WDL

CI Docker release Docker Hub: wdl-workerd Docker Hub: wdl-rust License

Chinese version: README.zh.md

WDL is a self-hosted multi-tenant Workers platform with multi-replica failover, built on stock Cloudflare workerd. It loads immutable Worker versions dynamically from Redis/Valkey through workerd's workerLoader API, then layers platform services around that runtime: control/auth, KV, R2, D1, Durable Objects, queues, cron, Workflows, ASSETS, service/platform bindings, live log tailing, Prometheus metrics, and deployment/lifecycle tooling. The project name began as "workerd dynamic loader"; WDL is the product name now that the platform extends well beyond dynamic loading.

What It Provides

  • Multi-tenant routing by namespace subdomain and custom host patterns.
  • Immutable worker versions with explicit promote/rollback and hard-delete lifecycle APIs.
  • Wrangler-compatible deployment through the wdl CLI.
  • KV, R2, D1, Durable Objects, queues, cron triggers, Workflows, ASSETS, service bindings, and platform bindings.
  • Secret-at-rest envelope encryption before values are written to Redis.
  • Live wdl tail over bounded Redis streams, structured logs, and Prometheus metrics.
  • Explicit failover semantics for D1/Durable Objects, plus multi-replica-safe dispatch for runtime, scheduler, and Workflows.
  • Local Docker Compose stack plus production-shaped Terraform and Kubernetes delivery paths.

Why WDL

workerd is the runtime, not the platform. It gives you Workers execution, but not the multi-tenant routing, state, storage, scheduling, secrets, control APIs, and lifecycle machinery needed to operate Workers as a platform. WDL provides that layer.

WDL builds around stock workerd, without forking it. Upstream workerd remains the runtime contract; WDL expresses the platform through workerd configs, static system workers, Rust services, Redis/Valkey state machines, and S3-compatible object storage. Operators get the Workers programming model while inheriting upstream workerd fixes instead of maintaining a runtime fork.

WDL is also more than a demo stack. Its control plane, routing, stateful binding ownership, dispatch workers, observability, release images, and infrastructure paths are written as single-region production platform components. "Production-ready" here means the platform has explicit recovery contracts, private mesh boundaries, release gates, and deployable Terraform/Kubernetes shapes; operators still own capacity planning, managed Redis/Valkey, storage durability, ingress protection, and regional disaster recovery.

What WDL Is Not

  • Not a global edge network. WDL runs in a single region on infrastructure you operate. It is not Cloudflare's global edge, anycast network, point-of-presence fabric, or DDoS protection service. That tradeoff is what lets WDL provide strongly consistent KV and read-your-writes D1.
  • Not a 100% drop-in for Cloudflare Workers. Compatibility is tracked surface-by-surface as stronger, different, or not implemented in the compatibility matrix.

Who It's For

  • Teams that want the Workers programming model and Wrangler workflow on their own infrastructure.
  • Internal platform teams offering multi-tenant Workers to their own developers.
  • Data-residency, sovereignty, compliance, or air-gapped environments that require operator-owned infrastructure.
  • Workloads already written to the Workers model that need an operator-owned deployment path without rewriting the application model.

How It Relates to Cloudflare Workers

WDL is not affiliated with, endorsed by, or sponsored by Cloudflare, Inc. Cloudflare, Cloudflare Workers, Wrangler, and workerd are trademarks or registered trademarks of Cloudflare, Inc.

You write standard module workers (export default { fetch }) with a normal wrangler.toml or wrangler.jsonc, pinned to Wrangler 4. wdl deploy runs wrangler deploy --dry-run for local bundling only; nothing is sent to Cloudflare. Do not use wrangler deploy against a WDL platform. Releases go through wdl deploy.

Workers serve from a path-prefixed URL on the platform domain:

https://<namespace>.<platform-domain>/<worker-name>/<path>

The worker sees the request path with the /<worker-name> prefix stripped.

Compatibility differences fall into three categories: stronger, different, and not implemented. WDL also adds platform-owned capabilities such as platform bindings. The surface-by-surface status lives in the compatibility matrix.

Hosted Platform Preview

WDL is infrastructure first: operators run their own platform and tenants deploy to it with the wdl CLI. The WDL Team may run an experimental hosted preview, with control at api.wdl.dev and workers serving from *.wdl.sh, purely to showcase what WDL can do with WDL-owned workloads. It is not a productized public platform and is not live yet; to help test it, email hi@wdl.dev.

Architecture Summary

WDL architecture overview

The platform is split into seven app services plus shared state:

Service Role
gateway Public/control ingress, host routing, custom pattern routing, WebSocket holder path.
user-runtime Tenant worker runtime pool, public-only outbound, local redis-proxy sidecar.
system-runtime Control/auth/static system workers and privileged __system__ runtime pool.
d1-runtime D1 SQLite execution with owner leases and supervised workerd process.
do-runtime Durable Object native facets, SQLite storage, alarms, owner leases, and WebSockets.
scheduler Cron, queue, and workflow tick dispatch.
workflows Workflows V2 state machine, DB 2 owner, and DO alarm delivery backend.

Valkey/Redis uses a deliberate logical split:

  • DB 0: control metadata, bundles, routes, auth, lifecycle, D1/DO owner state, workflow definitions.
  • DB 1: data-plane KV, queue streams, delayed queues, orphan streams, log-tail streams.
  • DB 2: workflow instance state, step records, ready/due shards, events, run leases.

S3-compatible storage backs ASSETS and R2. D1 and Durable Object SQLite files live on workerd localDisk storage. In production-shaped environments, those map to managed or provisioned storage; in local compose they map to volumes and s3mock.

High Availability And Failover

WDL's HA model is single-region and service-replica based. Gateway, runtime pools, scheduler, workflows, D1 runtime, and DO runtime are independent service families, so operators can run multiple tasks or pods where the module's concurrency contract allows it. Tenant worker versions are immutable and are loaded by id, so replacing a runtime replica does not mutate routing state.

Stateful bindings use ownership protocols instead of assuming that a service discovery target is the owner. D1 ownership is per physical database. Durable Object ownership is per owner scope. Both owner records carry task identity, lease expiry, and a monotonic generation fence, so stale replicas fail closed after a takeover. Supervisors drain local D1/DO owners during rollout, and ordinary task loss falls back to lease expiry and takeover by another replica. Scheduler projections are repairable, queues are at-least-once, cron/queue dispatch paths are multi-replica safe, and Workflows uses DB 2 leases and generation/run-token fences for execution progress. Scheduler rollout can still create a short dispatch gap, and missed cron slots follow the documented best-effort cron semantics instead of being replayed.

For the full architecture, see docs/architecture.md.

Quick Start

Install the standalone wdl CLI once, then install repository dependencies, compile the local workerd configs, start the stack from published Docker Hub images, and deploy a smoke worker. The compile step is required on a fresh clone because compose bind-mounts ./dist over the image's built configs.

npm install -g @wdl-dev/cli@1.2.1
npm ci
npm install --ignore-scripts --prefix test-workers/hello-jsonc
npm run compile:workerd:local
docker compose -f docker-compose.yml -f docker-compose.images.yml up -d --pull always --no-build
export ADMIN_TOKEN=local-dev-token
export CONTROL_URL=http://admin.test:8080
export CONTROL_CONNECT_HOST=localhost

wdl deploy test-workers/hello-jsonc --ns demo

Call tenant workers through the gateway:

curl -H "Host: demo.workers.local" "http://localhost:8080/hello-jsonc/"

Inspect the namespace through the CLI:

wdl workers --ns demo

This returns the namespace worker list and should show hello-jsonc as the active worker.

The control URL host must stay outside PLATFORM_DOMAIN; gateway uses that host to short-circuit to the static control worker. Adding demo.workers.local and admin.test to /etc/hosts is optional for this flow; it is only needed if you want browser-style requests to those names without explicit Host headers or CLI connect-host overrides.

Deploy a Worker

Use the same published wdl CLI version installed in Quick Start. Keep it aligned with the top-level WDL_CLI_PACKAGE value in .github/workflows/ci.yml; CI uses that pinned package for CLI integration tests.

To validate unpublished CLI changes, link or wrap the downstream checkout so wdl is on PATH. WDL_CLI_BIN remains available for focused integration runs that need an explicit executable override.

From the platform repository root, deploy a Wrangler project:

npm install --ignore-scripts --prefix test-workers/kv-demo
wdl deploy test-workers/kv-demo --ns demo

Exercise it through the gateway:

curl -H "Host: demo.workers.local" "http://localhost:8080/kv-demo/alice"

wdl deploy shells out to Wrangler dry-run, uploads the complete emitted bundle to control, then promotes the new immutable version. The CLI never writes Redis directly for ordinary operations; control remains the authority for validation, Redis commits, routing, lifecycle, and cleanup intent.

See docs/modules/cli.md for the full CLI and Wrangler input contract.

Common Commands

# Compile local workerd configs used by compose
npm run compile:workerd:local

# Recompile local configs and restart currently running compose services
# Rebuild Docker images separately after Rust or Dockerfile edits
npm run dev:rebuild

# Build local development images when changing Rust services or Dockerfiles
docker compose build

# Fast local JS gate
npm test

# Individual JS checks
npm run lint
npm run typecheck
npm run typecheck:strict
npm run test:unit

# Integration suite
npm run test:integration

# Rust checks from the repository root
cargo fmt --manifest-path rust/Cargo.toml --all --check
cargo clippy --manifest-path rust/Cargo.toml --workspace --all-targets -- -D warnings
cargo test --manifest-path rust/Cargo.toml --workspace
cargo deny --manifest-path rust/Cargo.toml check --config rust/deny.toml

Integration runner behavior, sharding, artifacts, and debug flags are documented in docs/testing.md.

Documentation Map

Start with docs/README.md. The active docs are the current design contract:

CLAUDE.md is intentionally only a short agent checklist and pointer map. It should not be treated as the canonical module reference.

Deployment Paths

  • Local development: docker-compose.images.yml uses published Docker Hub images; plain docker compose builds local development images.
  • Kubernetes: deploy/kubernetes/ Kustomize base and local overlay.
  • Terraform: terraform/ for AWS ECS-shaped deployment.

The delivery paths share the same service model and image contracts. Production deployments should keep Redis/Valkey private, keep runtime internal sockets private, and protect object storage, D1/DO localDisk storage, and secret-envelope root material as platform state.

Production deployments should also run replica counts and rollout policies that match the service's ownership contract: stateless workerd pools can be scaled horizontally, scheduler dispatch is replica-safe but may pause briefly during rollout, and D1/DO require stable per-replica storage identity plus private supervisor drain/renew access before scaling beyond one task.

Project Layout

Path Purpose
gateway/ Ingress routing worker.
runtime/ User/system runtime loader, dispatch, bindings, and workflow facade.
control/ Static control worker and handlers.
auth/ JSRPC auth worker.
d1-runtime/ D1 workerd runtime.
do-runtime/ Durable Object workerd runtime.
rust/ redis-proxy, scheduler, workflows, supervisor, and shared Rust crates.
shared/ Shared JS contracts, Redis client, observability, auth, version, D1 utilities.
system-workers/ Permanent platform-loaded workers.
test-workers/ Integration fixtures.
examples/ Manual demos and reference projects.
deploy/, terraform/ Deployment manifests and infrastructure.

The more detailed ownership map lives in docs/source-map.md.

Release Versioning

Project releases use signed annotated Git tags in the wdl.YYYYMMDD.N format, for example wdl.20260531.1. Before publishing Docker images, the release workflow validates that the tag matches the locked workerd package version, has release notes in CHANGELOG.md, points to the current repository default branch tip, and that the tag commit's CI workflow has completed successfully. The integration suite is part of that required CI run. Docker image tags use wdl.YYYYMMDD.<8-char-sha> so an image tag names the exact released commit without repeating the Git tag's build counter. The date/build suffix tracks the bundled workerd date version, but the wdl. namespace is intentionally separate from Cloudflare's numeric package majors. Project release tags are independent of the CLI package version and independent of per-worker versions such as v1 or v2.

License

Copyright 2026 Sean Consulting OÜ.

Licensed under the Apache License, Version 2.0. See LICENSE.

See NOTICE and AUTHORS.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, is licensed under Apache-2.0 without any additional terms or conditions.

About

Self-hosted multi-tenant Workers platform on stock Cloudflare workerd with multi-replica failover

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors