Run the same Vite app in multiple git worktrees without local-dev collisions.
Devtree gives each worktree its own public URL, managed env block, scoped dependency names, setup hooks, and garbage collection for orphaned local resources.
Devtree can launch either vite-plus or plain vite. It defaults to vite-plus for compatibility with existing projects.
Install Devtree itself:
pnpm add -D devtreeDependencies you may also need:
vite-plusorvite- required. Devtree runsvp devby default, orvite devwhendev_server.runneris"vite".portless- required unless you disable it withportless.enabled: falseorPORTLESS=0. Theportlesscommand must be available onPATH.tailscale- optional, only needed whentailscale.enabledistrue.varlockand@varlock/vite-integration- required only whenenv.provideris set to"varlock".
Install portless in the repo so devtree can find it:
pnpm add -D portlessIf you want portless available outside pnpm-managed scripts too, install it globally:
pnpm add -g portlessIf you use varlock, install both pieces together:
pnpm add -D varlock @varlock/vite-integrationThat gives you the varlock CLI plus the Vite integration Devtree expects.
portlessgives each local app a stable named URL instead of a random port. Devtree uses it to give every worktree its own predictable public URL and to run the dev server behind that URL.varlockis an env/schema tool for loading, validating, and injecting environment variables. Devtree uses it whenenv.provideris set to"varlock"so hooks and dev commands run with resolved, validated env values.
import { define_devtree_config } from "devtree";
export default define_devtree_config({
app_name: "my-app",
dev_server: {
runner: "vite-plus",
},
tailscale: {
enabled: true,
},
env: {
provider: "dotenv",
entries: ({ instance }) => [
{
kind: "value",
key: "APP_URL",
value: instance.public_url,
},
{
kind: "value",
key: "DATABASE_PORT",
value: String(instance.allocate_port("postgres", 5400)),
},
],
},
});By default Devtree manages a block inside .env.local. Set env.file_path if you want a different file.
Set dev_server.runner to "vite" if the app uses plain Vite and should launch with vite dev.
If you enable tailscale, Devtree checks for the tailscale CLI, reads the machine's MagicDNS hostname, starts Vite on 0.0.0.0, and adds that hostname to Vite's allowed hosts so the dev server can be reached over Tailscale.
Use your app's existing config helper. Plain Vite apps import from vite; VitePlus apps can keep importing from vite-plus.
import { defineConfig } from "vite";
import { devtree_vite_plugins } from "devtree/vite";
import devtree_config from "./devtree.config.ts";
export default defineConfig({
plugins: [...(await devtree_vite_plugins(devtree_config))],
});{
"scripts": {
"devtree": "devtree"
}
}Run these from the repo root, or any subdirectory inside a repo that has devtree.config.ts.
pnpm devtree doctor --fix
pnpm devtree setup
pnpm devtree dev
pnpm devtree info
pnpm devtree gc --dry-rundoctor --fixchecks prerequisites, bootstrapsportless, and validates Tailscale whentailscale.enabledis onsetupwrites env overrides, starts dependencies, runs hooks, and reports the detected Tailscale hostdevstarts the app through Devtreeinfoprints the current instance URL and namesgcremoves orphaned dependency resources from deleted worktrees
Other commands:
devtree deps start|stop|logsdevtree config tailscale.enabled truedevtree env write|show
devtree config <key.path> prints the current value from devtree.config.ts.
devtree config <key.path> <value> writes the new value back into devtree.config.ts.
Examples:
pnpm devtree config tailscale.enabled true
pnpm devtree config dev_server.runner vite
pnpm devtree config portless.https "inherit"
pnpm devtree config namespace personal-dev
pnpm devtree config tailscale.enabledAdd dependencies and hooks in devtree.config.ts when you want Compose services, custom setup steps, migrations, or pre-dev commands.
- Turn it on with
tailscale: { enabled: true }indevtree.config.ts. - Install the
tailscaleCLI and make sure you're logged in on the machine runningdevtree dev. devtree doctorfails when Tailscale is enabled but the CLI or MagicDNS hostname is unavailable.devtree setup,devtree dev, anddevtree infosurface the detected Tailscale host so you can verify the integration quickly.
If you use an AI agent, run npx @tanstack/intent@latest install.