Shared engines
Shared engines run one global container per engine and give each workspace a logical boundary inside it, created on the fly during switch. One fixed, well-known port; no per-workspace containers, volumes, or port juggling.
PostgreSQL — type: shared
Section titled “PostgreSQL — type: shared”A database per workspace, with real branch-from-parent semantics via PostgreSQL templates:
services: - name: app-db type: shared service_type: postgres auto_workspace: true shared: image: postgres:17 # default port: 5432 # fixed well-known port template_branching: true # CREATE DATABASE … TEMPLATE parent (default true)Creating workspace feature_x from main runs CREATE DATABASE child_resource TEMPLATE parent_resource using the recorded resource identifiers — schema and data are copied engine-side. With template_branching: false, new workspaces get empty databases.
ClickHouse — type: shared
Section titled “ClickHouse — type: shared”A database per workspace via CREATE DATABASE (no template branching — databases start empty):
services: - name: analytics type: shared service_type: clickhouse shared: image: clickhouse/clickhouse-server:latest # HTTP on :8123With type: shared, each workspace gets a numbered DB index (1–15; index 0 stores allocations), allocated atomically and tracked inside Redis itself:
services: - name: cache service_type: redis shared: image: redis:7 # default; port 6379RustFS object storage (S3-compatible)
Section titled “RustFS object storage (S3-compatible)”One global RustFS container, one bucket per project/service/workspace identity:
services: - name: storage service_type: rustfs # aliases: s3, objectstorage shared: image: rustfs/rustfs:latest # S3 API on :9000, console on :9001 port: 9000 user: rustfsadmin # access key (default) password: rustfsadmin # secret key (default)Keeping engines alive
Section titled “Keeping engines alive”Provisioning happens during switch; these commands keep the global containers themselves running:
devflow service up # one-shot reconcile: start every shared engine that's downdevflow daemon start # background controller, reconciles every 30sdevflow daemon start --interval 10devflow daemon start --once # same as service updevflow daemon start --foregrounddevflow daemon status # last reconcile + per-engine healthdevflow daemon stopThe daemon covers every registered project’s shared engines (type: shared, plus service_type: rustfs/redis), restarting any that go down.
Choosing shared vs local
Section titled “Choosing shared vs local”type: local (CoW) | type: shared | |
|---|---|---|
| Isolation | process + data directory | logical (db/bucket/index) in one process |
| Startup | per-workspace container start | instant (engine already running) |
| Memory | one engine per workspace | one engine total |
| Ports | dynamic per workspace | fixed well-known port |
| Data branching | full CoW clone of everything | Postgres: TEMPLATE copy · others: empty |
| Reset/seed granularity | per container | per database/bucket |
Mixing is normal: CoW Postgres for the data you branch, shared Redis/RustFS for caches and blobs. For a step-by-step Docker Compose migration, see Adding devflow to an existing project.
Resource ownership is recorded explicitly. Existing unowned resources require deliberate adoption; inventory does not start engines. See Data ownership and recovery.