Migrate from ngrok
If you know ngrok, you already know Beamd. Here's the command mapping and what's different.
Beamd's developer loop is deliberately ngrok-shaped: run a command, get an
HTTPS URL, Ctrl-C to stop. The differences are about where the URL lives
and who drives it.
The command mapping
| ngrok | Beamd | Notes |
|---|---|---|
ngrok http 3000 | beamd open 3000 | Foreground; Ctrl-C to stop. |
ngrok http 3000 --domain api.example.com | beamd open 3000 --as api | --as is one label on your base domain → api.<base>. |
ngrok config add-authtoken <t> | beamd login (hosted) or beamd login --server <edge> --token <t> (self-host) | Credentials are per-edge accounts. |
| Run in the background | beamd open 3000 -d → beamd list / beamd close <name> | -d hands the tunnel to a background agent. |
ngrok.yml + ngrok start --all | A committed .beamd + beamd run -- <cmd> | Config travels with the repo. |
| Reserved/custom domain (paid) | Self-host on your own domain | Apache-2.0; no per-seat pricing. |
What's the same
- Foreground by default. A bare
beamd openholds the tunnel until youCtrl-C— exactly likengrok http. - Instant HTTPS. Real certificates, no warning interstitial.
- A bare port works.
beamd 3000is shorthand forbeamd open 3000.
What's different
- Your domain, your edge. Self-hosting is a first-class, free path: one
binary, your DNS, wildcard certs from Let's Encrypt. Tunnels live at
*.beam.example.cominstead of a shared provider domain. See the Setup walkthrough. - A stable subdomain per app. Built for multi-app dev — run
web,api, anddocsside by side, each at its own predictable name. Derive the name from your project with--from repo|branch|dir. - Agent-native. Beyond the CLI, Beamd exposes an MCP server and a local API so an AI agent can open and close tunnels as part of its workflow — not just a human at a terminal.
beamd runwraps your dev server. It picks a port, sets$PORTand$BEAMD_URL, fixes allowed-host checks (Vite/Next), and tears everything down on exit. See Wrap a dev server.
One naming gotcha
ngrok lets you point a full custom hostname at a tunnel. Beamd names are a
single DNS label — the wildcard cert is exactly one level deep
(*.<base>). Encode structure with hyphens, not dots:
- ✅
beamd open 3000 --as web-api - ❌
beamd open 3000 --as web.api(nested labels won't get a cert)
More on naming in Naming & project config.