carte
Run your local web apps à la carte: visit https://myapp.localhost and
carte starts the app, then stops it once you're done with it.
- Many apps at once: carte stops the least recently used ones to keep memory in check.
- The whole Procfile: asset watchers, job workers and schedulers start and stop with the web server.
- A hostname per worktree: a worktree in a
feature-xfolder runs athttps://feature-x.myapp.localhost. - Projects and stacks: apps that work together start together, and worktrees with the same name form a stack.
- HTTPS everywhere, with a local certificate authority.
- A terminal UI for state, logs and controls.
- Sharing apps on the public internet through Cloudflare Tunnel or ngrok.
- Kubernetes Services at hostnames like
https://grafana.monitoring.prod.localhost, forwarded when you visit.
carte runs on macOS and Linux.
Install
With Homebrew:
Or with Cargo:
Setup
Setup runs once per machine and asks for your password where needed. It:
- creates a certificate authority for carte's hostnames and trusts it
- runs the daemon on ports 80 and 443. On Linux, this lets every program use ports from 80 up.
Apps are served under .localhost. To also serve them under .test, run
carte setup --tld test.
carte setup --check shows what's in place, and carte setup --uninstall
removes it.
Coming from puma-dev
carte setup offers to replace puma-dev, and to keep its .test
hostnames. To turn the apps linked in ~/.puma-dev into carte projects:
docs/puma-dev.md compares the two and covers the switch in detail.
Projects
A project is a group of apps that belong together. Each project is a
file in ~/.config/carte/projects/. For a single app, this is enough:
That writes ~/.config/carte/projects/myapp.toml with one line:
= "~/code/myapp"
and the app is at https://myapp.localhost.
carte runs the processes in the app's Procfile.dev or Procfile. Without
one, it runs a Rack app with Puma and a Node app with its dev script.
A project can also hold several apps that work together. Say the acme
product is three repos in ~/work, next to some unrelated ones:
~/work/
├── acme-accounts/ Rails API
├── acme-billing/ Rails API
├── acme-frontend/ Vite app calling the other two
└── side-project/
One file makes them a project:
# ~/.config/carte/projects/acme.toml
= "~/work"
= "acme-*"
= "acme-"
[]
= "{{url:app}}"
[]
= ["billing", "accounts"]
includepicks the threeacme-*repos as apps, and leavesside-projectout.strip_prefixshortens their hostnames toaccounts.acme.localhost,billing.acme.localhostandfrontend.acme.localhost.[env]gives every app the others' URLs, likeACME_BILLING_URL=https://billing.acme.localhost.depends_onstarts billing and accounts along with the frontend.
A repo can also carry its own defaults in a carte.toml.
docs/configuration.md is the reference for every setting.
Worktrees and stacks
Worktrees with the same folder name form a stack: their apps run together and call each other. Say you add a worktree to billing:
Now https://billing.feature-x.acme.localhost runs the worktree. The
frontend has no feature-x worktree, so
https://frontend.feature-x.acme.localhost runs its main checkout,
calling the feature-x billing. Remove the worktree, and carte stops it.
carte leaves databases alone. For separate data per worktree, use
CARTE_CHECKOUT in database.yml or similar.
Day to day
Once a project is added, there's little left to do. Visiting an app starts it, and it stops when you stop using it. New worktrees and changes to project files are picked up by themselves.
touch tmp/restart.txt restarts an app too.
docs/cli.md covers the rest of the CLI. Coding agents can use carte through its MCP server; see docs/mcp.md.
Sharing
Sharing is always explicit, and only shared apps are reachable. See docs/sharing.md.
Kubernetes
carte can forward to a Kubernetes cluster's Services, like
kubectl port-forward without the command. Give the cluster a project
file that names its kubeconfig context:
# ~/.config/carte/projects/prod.toml
= { = "prod" }
The Service grafana in the monitoring namespace is then at
https://grafana.monitoring.prod.localhost, or
https://grafana.prod.localhost if no other namespace has a grafana.
carte import kube writes a project file for each context you pick. See
Kubernetes.
Configuration
Machine settings live in ~/.config/carte/config.toml, and every key is
optional:
= "test"
= "15m"
carte reloads it when it changes. If a file is broken, carte keeps the last working version and shows the error.
Alternatives
carte is heavily inspired by puma-dev, which is a good choice if you just want a web server per app.
Overmind and process-compose run a project's processes in your terminal. They suit working on one app at a time.
portless gives dev servers
.localhost names, but you start and stop them yourself.
Contributing
See CONTRIBUTING.md.
License
MIT. See LICENSE.