fedService Federation

Scripts

A script is a command that knows what it needs: fed test:integration starts the database, runs its configured health check, executes your tests, and stops what it started. Define scripts in the scripts section of your config and run them with fed run <name> — or the shorthand, fed <name>.

Defining scripts

scripts:
  db:migrate:
    depends_on: [database]
    script: npx prisma db push

  test:integration:
    depends_on: [db:migrate, api]
    cwd: ./tests                      # Working directory (optional)
    timeout: "5m"                     # Only for non-interactive runs; see Timeout below
    script: npm run test:e2e -- "$@"  # "$@" passes arguments from CLI

Running scripts

fed run db:migrate                    # Run a script
fed db:migrate                        # Shorthand (if no command collision)
fed test:integration -- -t "auth"     # Pass arguments after --

Arguments after -- reach the script either way: a script that mentions "$@" or $1 receives them as shell positional parameters; any other script gets them appended to the command, shell-escaped. So script: npx prisma is enough to make fed prisma db push work.

Output modes

fed run --output <mode> controls where dependency-service logs go: captured (default — kept in a ring buffer, shown on failure), passthrough (streamed live), or file (written to a log file). Useful in CI.

Service lifecycle ("borrow or own")

A script is a good guest: it stops the services it started, and leaves alone the services that were already running.

Cleanup runs on every exit path: success, failure, and interruption. The first Ctrl+C lets the script shut down and then tears down what it started; a second Ctrl+C force-quits a script that ignores the first (the services it started are still stopped).

So fed start is how you keep a service up across many script runs:

fed start database          # database is now session-owned
fed test:integration        # borrows database, leaves it running
fed test:integration        # ...and again, no slow restart

fed run db:migrate          # nothing was running, so db is started…
                            # …and stopped again when the migration finishes

By default the lifecycle is decided at runtime by who started the service — no per-service configuration needed. When a script depends on another script, only the outermost run performs cleanup, so nested script-dependencies never tear down services mid-run. A script can opt out of ownership entirely with keep_services.

Keeping services running (keep_services)

Sometimes you want a script to leave its services up — a seed or scenario script that sets up state, prints a few URLs, and expects you to keep poking at the running stack afterward. Set keep_services: true and the run skips its borrow-or-own cleanup:

scripts:
  scenario:
    keep_services: true
    depends_on: [web]
    script: ./seed-scenario.sh
fed scenario     # starts web (+ its deps), seeds state, and leaves them running
# ...poke at the app in a browser...
fed stop         # tear the stack down when you're done

The services the run started are left on the same footing as a fed start: they persist until you stop them. Services that were already running are still borrowed, exactly as without the flag.

keep_services is read only for the script you invoke directly. When a keep_services script is pulled in as another script's dependency, the outermost run owns cleanup and its setting wins — a non-keeping parent still tears everything down.

keep_services can't be combined with isolated: true: an isolated script runs in a throwaway stack that is always cleaned up on exit, so there is nothing to keep running. fed rejects that combination at config-validation time.

Isolated scripts

For integration tests that need a throwaway stack without interfering with your running dev services:

scripts:
  test:integration:
    isolated: true     # Fresh ports and direct image-backed Docker resources
    depends_on: [database, api]
    script: npm run test:e2e
fed start                # Dev stack stays running
fed test:integration     # Tests get their own stack, cleaned up after

When isolated: true is set:

Service dependencies run in the isolated child stack. A dependency that names another script runs according to that script's own configuration; it does not automatically inherit the parent's isolated context.

Compose-backed services do not receive the child isolation ID: their project name remains derived from the Compose file path. Don't use a Compose service as an isolated: true dependency while the same Compose project is running in the parent stack.

For process and direct image-backed dependencies, this is the recommended way to run integration tests: your dev stack is untouched and each test run gets a clean child environment.

Environment variables

A script inherits fed's process environment. Entries mapped under environment: are added or overridden, but parameters are not exported automatically. Mapped values, and the script: command itself, accept {{PARAM}} placeholders resolved to the ports and secrets this directory was actually allocated:

scripts:
  psql:
    environment:
      DATABASE_URL: '{{DATABASE_URL}}'   # Interpolated parameter
      TEST_MODE: "true"                  # Plain value
    script: psql {{DATABASE_URL}}

That resolution is the reason to route commands through fed instead of running them bare: fed psql in an isolated worktree connects to that worktree's database, while a bare psql hits whichever stack owns the default port. Wrap anything that reads DATABASE_URL or a service port in a script, and the right values follow it across checkouts.

Working directory

Scripts run in the project root by default. Use cwd to change this:

scripts:
  test:e2e:
    cwd: ./tests/e2e
    script: npx playwright test

In v5.2.1 a relative script cwd is resolved by the spawned shell relative to the directory where you invoked fed, not automatically against the config file. Run fed from the project root when using a relative script cwd.

Timeout

In v5.2.1, timeout is used by fed's library API but is not enforced by the fed run CLI or its nested script dependencies. Do not rely on it to bound a command launched from the CLI:

scripts:
  long-migration:
    depends_on: [database]
    timeout: "30m"
    script: ./run-heavy-migration.sh

Supports milliseconds, seconds, minutes, or bare seconds: "500ms", "30s", "5m", "300". Hours such as "1h" are not accepted.

Script dependencies

Scripts can depend on both services and other scripts:

scripts:
  db:migrate:
    depends_on: [database]
    script: npx prisma migrate deploy

  db:seed:
    depends_on: [db:migrate]
    script: npx prisma db seed

  test:e2e:
    depends_on: [db:seed, api]
    script: npm run test:e2e

Dependencies are started in order. Service dependencies are started and health-checked before the script runs.

Back to overview →