Skip to main content

Running Multiple Dev Servers Concurrently with fyrer

fyrer can run multiple dev servers simultaneously, streaming each server's logs in a unified TUI. This guide shows how to configure persistent tasks for your dev servers and manage their dependencies so everything starts in the right order.

What is a persistent task?

Setting persistent: true on a task marks it as long-running. fyrer keeps it alive until you explicitly quit — unlike normal tasks, persistent tasks never exit on their own. This makes them the right choice for dev servers, watchers, and any other process you want running in the background while you work.

tasks:
dev:
cmd: bun --watch src/index.ts
persistent: true # keep alive until q / Ctrl+C
cache: false # cache cannot be combined with persistent

Basic dev server setup

The example below shows a typical frontend + backend monorepo. ui:build is a normal cacheable task that must finish before web:dev starts; api:dev runs independently.

packages:
- name: ui
root: ./packages/ui
tasks:
build:
cmd: bun build src/index.ts --outdir dist
inputs:
- src/**
outputs:
- dist/**
cache: true

- name: web
root: ./apps/web
env:
PORT: "3000"
tasks:
dev:
cmd: bun --watch src/index.ts
depends_on:
- ui:build # ui:build runs first, then web:dev starts
cache: false
persistent: true

- name: api
root: ./apps/api
tasks:
dev:
cmd: cargo run
cache: false
persistent: true

Starting all dev servers

Run the dev task across every package that defines one:

fyrer run dev

fyrer resolves the dependency graph, runs ui:build first, and then launches web:dev and api:dev concurrently once their prerequisites are satisfied.

Dependency ordering with persistent tasks

fyrer runs a streaming DAG: a task starts as soon as its dependencies succeed, up to the concurrency limit. A persistent task never exits, so any task that transitively depends on it will stay Skipped forever. Unrelated tasks are unaffected — they still run concurrently.

This means:

  • If web:dev and api:dev have no dependencies between them, they start concurrently once their own prerequisites are ready. ✅
  • If any task lists a persistent task in its depends_on, that task will wait forever and never start. ❌

Keep dev servers as leaves of the dependency graph — nothing should depend on them.

!

Do not add a depends_on entry that points to a persistent task. Because the persistent task never exits, any task waiting for it will never start and will block the entire run.

TUI navigation

While dev servers are running, fyrer's interactive TUI lets you inspect each one:

KeyAction
q or Ctrl+CQuit fyrer and kill all spawned process groups
j / k or / Select the previous / next task
u / d or PageUp / PageDownScroll the log pane
g / GJump to top / tail (follow) the log
rRestart the selected task
K (Shift+k)Kill the selected task
Mouse wheelScroll the log
EnterAfter run finishes, browse logs

Plain mode for scripts

To run dev servers without the TUI — for example inside a terminal multiplexer or a script — pass the -n flag:

fyrer run dev -n

In plain mode each log line is prefixed with [package:task] and colorized by package, making it easy to tell servers apart in a shared terminal session.