Use fed with Docker Compose
Keep the Compose file you already have. Include it once and fed expands its services into the same dependency graph as native processes, hooks, and scripts.
Include the project
Suppose compose.yaml defines PostgreSQL and Redis:
# compose.yaml
services:
postgres:
image: postgres:16-alpine
ports:
- "${DB_PORT:-5432}:5432"
environment:
POSTGRES_PASSWORD: development
redis:
image: redis:7-alpine
Include it from fed.yaml, pass the allocated port once for the project,
then run the application on the host:
parameters:
DB_PORT: { type: port, default: 5432 }
API_PORT: { type: port, default: 8080 }
compose:
- file: ./compose.yaml
environment:
DB_PORT: "{{DB_PORT}}"
services:
api:
process: npm run dev -- --port {{API_PORT}}
depends_on: [postgres]
environment:
DATABASE_URL: "postgres://postgres:development@localhost:{{DB_PORT}}/app"
entrypoint: api
fed validate
fed start
fed passes the resolved DB_PORT value to the Compose command. Compose uses
it in its normal environment substitution. No generated override file is required.
The imported services are named postgres and redis, exactly as
they are in Compose. Their Compose health checks remain authoritative.
Avoid name collisions
Use a namespace when importing multiple projects with overlapping service names:
compose:
- file: ./infrastructure/compose.yaml
namespace: infrastructure
- file: ./observability/compose.yaml
namespace: observability
profiles: [development]
services:
api:
process: npm run dev
depends_on: [infrastructure/postgres]
Compose profiles listed on an import are enabled while fed inspects and operates that project. Importing the same canonical file twice is rejected.
Make host ports adjustable
Worktree isolation can only change ports declared as fed parameters. A literal mapping
such as 5432:5432 remains fixed and will collide with another checkout.
- Replace each Compose host port with an environment variable such as
${DB_PORT:-5432}. - Declare the same name as a
type: portparameter infed.yaml. - Pass the parameter under the Compose import's
environment. - Use the parameter in native service URLs and project scripts.
The container-side port can remain fixed. Only the host side must vary.
Run it in a worktree
git worktree add ../app-fix -b fix/session
cd ../app-fix
fed isolate enable
fed start
Compose derives its project name from the Compose file path, so copies in separate Git worktree directories receive separate Compose projects. fed supplies different values for the declared host-port parameters.
Know the limits
- Rich Compose dependency conditions are not silently weakened. Imports currently accept
service_started;service_healthyandservice_completed_successfullyproduce a validation error until Fed can preserve those semantics. - Literal ports do not move. fed warns about common literal host-port and
localhostreferences, but it cannot rewrite arbitrary commands or files. - Bind mounts stay bind mounts. Two stacks that mount the same path still share that path.
- Rotating fed isolation does not rotate Compose volumes. Compose keeps the project namespace derived from its file path.
- Isolated scripts do not create a second Compose project inside one checkout. Do not use a Compose-backed dependency in an
isolated: truescript while the same Compose project is running in the parent stack.
If a test needs a throwaway database alongside the development database in the same
checkout, define that database directly with image: or give the test a
separate Compose project yourself.
Migrate gradually
A project can mix all three service types:
- Keep stable infrastructure in Compose.
- Run the application and workers as native processes for fast reloads and local debugging.
- Move a container to a direct
image:service only when fed-managed volumes or isolated scripts make that useful.
See the complete Postgres and Redis example in the repository. The integration suite starts the imported project against a real Docker daemon, reads logs from a fresh Fed process, preserves Postgres data while Redis is stopped independently, and verifies final cleanup.