local dev for a distributed stack

Run the slice of your stack you're working on. Locally, wired to the rest.

$npm install -g @pinkynrg/crew
Star on GitHub

Zero dependencies · macOS & Linux · MIT on GitHub

crew start
crew start: pick a connected slice of services in the dependency graph, run it locally, watch the labelled logs

the config file

You don't hand-write it.

crew config is a visual editor: pick a project's folder and crew fills in the mechanical parts it can read from your package.json, lockfiles and .envs — type, runner, start command and env-file path. The URLs are yours to add: the project's local URL/port, and its deployed host for each environment. Out comes one readable config.json, committable, no secrets.

crew config
crew config: add a frontend and a backend by picking their folders (crew auto-fills type, runner, env and start command), add each one's local URL and deployed host per env, and create a guard
add a frontend & a backend from their folders (scaffolding auto-filled), fill their URLs, then a guard

what it holds

  • path + tasks.start: where each repo lives and how to run it. Drop {envfile} in the command and crew injects the wired env file it materializes for the run.
  • match: the host(s) it's deployed under, per env. crew matches these against the URLs in your env files to auto-discover who depends on whom.
  • local: its local URL, so crew can rewrite a peer's env to point at your local copy instead of the deployed one.

Committable as-is: no secrets, no machine paths. Those live in a gitignored local.json beside it.

crew reads these hosts → derives this graph
web api auth
config.json
{
  "projects": {
    "web": {
      "path": "web",
      "type": "frontend",
      "tasks": {
        "start": "dotenv -e  -- npm run dev"
      },
      "env": ".envs/{env}.env",
      "match": {
        "your-env": "web.example.com"
      },
      "local": "http://localhost:3000"
    },
    "api": {
      "path": "api",
      "tasks": {
        "start": "uvicorn app:main --reload --env-file "
      },
      "env": ".envs/{env}.env",
      "match": {
        "your-env": "api.example.com"
      },
      "local": "http://localhost:4000"
    },
    "auth": {
      "path": "auth",
      "tasks": {
        "start": "godotenv -f  go run ."
      },
      "env": ".envs/{env}.env",
      "match": {
        "your-env": "auth.example.com"
      },
      "local": "http://localhost:4500"
    }
  }
}

why not docker

Every service is a switch.

On is local, off is remote. Flip a service on and crew runs it locally and rewrites every peer that talks to it to point at your localhost. Flip it off and it stays on its deployed environment, callers untouched. The slice you run is just which switches are on — one service, or the whole stack.

Tap a service to flip it — the URLs and wiring update live.

Docker Compose has no equivalent to that switch: a service is in the compose file or it isn't, and pointing at the deployed one is a manual env edit — so you run the whole graph locally or maintain a second file full of stubs, and either drifts from production. crew reads the wiring from the .env files you already ship, so there's nothing to keep in sync.

crewComposeTiltmirrordovermind
Runs natively, no containers
Uses your real remote stack
No daemon or cluster
No parallel config to keep

Columns are the representative tool of each family. crew sits between process-runners (overmind, foreman, mprocs) and remote-wiring tools (mirrord, Telepresence): the native-slice-plus-real-remote of the latter, with none of the cluster, daemon, or containers — just URL swaps in the .env files you already have.

run one service or all of them native processes, no daemon no images, no rebuilds wiring from your env files

Assumes each project ships at least one environment file with its peers' URLs, plus a deployed host those point at. That's what crew borrows for the services you leave off. Nothing deployed to point at? A full-stack tool like Compose fits your case better.

questions

Is it safe to point at real environments?

Short version: crew reads your env files and rewrites a throwaway copy — it never edits your repo, and there are no secrets in the committable config.

Does crew modify my repos or my .env files?

No. It reads your env file and writes a wired copy to ~/.config/crew/tmp/<project>.env (URLs swapped to localhost for the peers you're running), passes that path to your start command via {envfile}, and deletes it on teardown. Your checkout and its committed env files are never touched.

Where do my secrets live?

In your own env files, same as today — crew only reads them. The committable config.json holds no secrets; machine-local bits (projects dir, remembered selection) live in a gitignored local.json. The temporary wired copy under ~/.config/crew/tmp/ is the only materialized secret, and it's regenerated per run and removed on exit.

What if a remote environment is down?

Then the services you left off are unreachable, exactly as if you called that deployed environment directly. crew doesn't proxy or cache; turn those services on to run them locally, or wait for the environment to recover.

Do I have to run everything?

No — that's the whole point. Run one service or all of them; whatever you don't run stays on its deployed env, wired in automatically.

Which platforms are supported?

macOS and Linux. It's POSIX-only — teardown relies on process groups (setsid / kill(-pgid)) — and needs Node ≥ 18.

get started

From zero to a running set.

  1. Install
    $ npx @pinkynrg/crew

    Zero dependencies, so it lands instantly. Or install it globally with npm i -g @pinkynrg/crew.

  2. Register your projects, or write the config file manually
    $ crew config

    A two-pane visual editor: pick a folder and crew prefills each project (path, start command, type), or write the config.json yourself, as shown above.

  3. Run the set
    $ crew start env=your-env

    Pick a connected slice in the dependency graph (click or arrow keys); crew runs those locally, wires them together, and leaves the rest on their resolved remote env.