Named .test URLs for local dev servers. Stop memorizing port numbers.
http://myapp.test instead of http://localhost:3000
http://nexus.test instead of http://localhost:3013
http://praxis.test instead of http://localhost:3002
dot-test automatically discovers Rails projects in the current directory, assigns stable port numbers, and runs a local DNS server + HTTP reverse proxy so *.test domains route to the right backend.
Zero dependencies. Single binary. Works with however you start your apps.
brew install dot-testOr build from source:
go install github.com/zarpay/dot-test@latestcd ~/projects # or wherever your apps live
dot-test setup # one-time macOS DNS config (needs sudo)
dot-test sync # discover projects, assign ports
dot-test up # start the daemonOpen http://yourapp.test in your browser.
- Discover — Scans your projects directory for Rails apps (looks for
config/application.rb) - Assign — Gives each app a stable port number starting from 3000, persisted across runs
- Update — Writes
PORT=<assigned>to each app's.envfile - Route — Runs a DNS server (
.test→127.0.0.1) and HTTP proxy (hostname → port)
Your apps read the port from .env via dotenv-rails or foreman. You start them normally with bin/dev. dot-test handles the rest.
dot-test [sync] Discover projects, assign ports, update .env files
dot-test list Show current port mappings
dot-test up Start DNS + reverse proxy daemon
dot-test down Stop daemon
dot-test setup One-time OS configuration (creates /etc/resolver/test)
dot-test clean Remove all config and stop daemon
dot-test version Show version
dot-test help Show help
Ports are assigned sequentially starting from 3000 and persist in a .dot-test file inside your projects directory.
dot-test respects hardcoded ports. Before assigning, it checks:
bin/devforPORT=XXXXor--portflagsProcfile.devfor-pport assignmentsship-manifest.dev.tomlandProcfile.tomlfor bind addressesdocker-compose.ymlfor port mappings
Hardcoded ports show as (pinned) in output. Other projects are assigned ports around them.
$ dot-test sync
33 projects:
http://empirium.test -> localhost:3200 (pinned)
http://fizzy.test -> localhost:3122 (pinned)
http://nexus.test -> localhost:3013
http://praxis.test -> localhost:3002
http://zar-core.test -> localhost:3030
Updating .env files...
33 updated
Done. Run 'dot-test up' to start the daemon.
| Variable | Default | Description |
|---|---|---|
DOT_TEST_DIR |
current directory | Directory to scan for projects |
DOT_TEST_PORT |
80 |
HTTP proxy listen port |
DOT_TEST_DNS_PORT |
15353 |
DNS server listen port |
dot-test writes PORT=<port> to each project's .env file. For apps to pick this up automatically, they need one of:
dotenv-railsgem in their Gemfileforemanorovermindinbin/devwith aProcfile.dev
Apps that won't read .env are flagged with a warning during sync. You can always start those manually:
PORT=3005 rails sIf you visit a .test URL and the backend isn't running, you get:
dot-test: nexus.test is not running
Start it with: cd ~/projects/nexus && bin/dev
dot-test setup creates /etc/resolver/test, which tells macOS to route DNS queries for *.test to dot-test's built-in DNS server. This persists across reboots.
For systemd-resolved, add to /etc/systemd/resolved.conf:
[Resolve]
DNS=127.0.0.1:15353
Domains=~testThen restart: sudo systemctl restart systemd-resolved
MIT