devlanes runs a project's dev environment once per Git worktree on macOS, Linux and Windows 11. Each worktree is a lane with its own ports, hostnames and data; a per-user daemon owns the processes and the CLI and TUI are its clients. devlanes is in beta.
brew install devlanes-run/tap/devlanes
npm install -g devlanes
uv tool install devlanes
cargo binstall --git https://github.com/devlanes-run/devlanes devlanes
curl -fsSL https://devlanes.run/install.sh | shThese install release builds for macOS or Linux (glibc), arm64 or x86_64. pipx install devlanes works like uv, and pip install devlanes installs into a virtual environment; the update notice recognises pip only there, not in pip install --user or a system Python. Homebrew, npm, PyPI and install.sh install both devlanes and the devlanes-hosts helper; cargo binstall installs devlanes, and cargo binstall --git https://github.com/devlanes-run/devlanes devlanes-hosts-helper adds the helper. To build from source instead:
cargo install --locked --git https://github.com/devlanes-run/devlanes devlanes devlanes-hosts-helperOn Windows 11 24H2 or later, x64 or arm64, install from PowerShell; npm, uv and cargo binstall work there too. Windows lists the requirements and what differs:
irm https://devlanes.run/install.ps1 | iexBoth scripts install the latest release and verify the archive against the release's SHA256SUMS. install.sh installs to ~/.local/bin; DEVLANES_INSTALL_SUDO=1 allows sudo for a directory you can't write. They take a channel and a directory, and hand an existing install there to devlanes update:
curl -fsSL https://devlanes.run/install.sh | sh -s -- --channel next # latest build of main
curl -fsSL https://devlanes.run/install.sh | sh -s -- --dir ~/biniex "& {$(irm https://devlanes.run/install.ps1)} -Channel next"
iex "& {$(irm https://devlanes.run/install.ps1)} -Dir C:\tools\devlanes"devlanes update installs new releases the way devlanes was installed, and a build of main updates to the latest build of main. devlanes installs and updates to the latest release only. Installing an older release is not recommended; if you need one, use the npm or PyPI package with that version (npm install -g devlanes@X.Y.Z, uv tool install devlanes==X.Y.Z or pipx install devlanes==X.Y.Z). Updates has the details.
packaging describes the release pipeline.
devlanes uninstall stops the daemon, removes its login service and what devlanes setup changed, removes devlanes the way it was installed, and asks before deleting ~/.devlanes; --dry-run shows the plan first.
devlanes ships no dl command. To type dl, add an alias to your shell config, after the line that loads devlanes completions, so the alias completes like devlanes:
# zsh, ~/.zshrc
alias dl=devlanes
compdef dl=devlanes
# bash, ~/.bashrc
alias dl=devlanes
complete -o nospace -o bashdefault -F _clap_complete_devlanes dl
# fish, ~/.config/fish/config.fish (fish aliases inherit the command's completions)
alias dl devlanesdevlanes start # infra, setup, tasks, then services of this worktree's lane
devlanes status
devlanes logs api -f
devlanes # the TUIGetting started walks from install to two lanes. The CLI reference and the config reference are generated from the code, and tests fail when they fall behind.
devlanes --help lists the commands, and devlanes <command> --help describes each one. See design, development conventions, fixtures, the agent plugin and M0 commands. mprocs and dekit informed terminal interaction; pitchfork, process-compose, devenv, Coasts, portless, kache, overmind and Conductor informed process and worktree workflows.
# Project name shared by every worktree of this repository.
project: acme
# Long-running processes, started together after infra and setup.
services:
api:
# Runs a script from package.json with the project's package manager.
run_script:
file: api/package.json
name: dev
# HTTPS hostnames routed by the proxy. lane.domain is acme.localhost or acme<N>.localhost.
hosts: "api.${{ lane.domain }}"
web:
# Adds Vite's port and host flags to the command.
preset: vite
run_script:
file: web/package.json
name: dev
# Extra variables for this service; public_url is the API's https:// address in this lane.
env:
VITE_API_URL: "${{ services.api.public_url }}"
hosts: "${{ lane.domain }}"In the worktree of lane 2 this serves https://api.acme2.localhost and https://acme2.localhost, each on its own allocated port. The excerpt comes from minimal.yaml, which also has shared Postgres and a database per lane; devlanes.yaml shows every form.
Apache-2.0. See LICENSE.