Skip to content
Docsv0.7.2

Gateway & Worktrees

The gateway is a local nginx reverse proxy that maps a friendly domain — say api.local — to whichever service currently owns it. Because denvig treats a project as a family of git worktrees, you can run the same service in several checkouts at once and move a domain between them on demand, without editing config or restarting nginx.

This guide explains the model and walks through the common workflows.

A few rules make the rest of the guide predictable:

  • A domain has one owner at a time. The gateway routes the domain to exactly one running service. Whoever currently holds it is the owner.
  • Services run per-worktree. The api service in your main checkout and the api service in a feature/x worktree are distinct running services that can be up simultaneously — on different ports.
  • Domains are claimed at start. A service routes through the gateway using the domains in its http config. You can override those for a single start with --domains, which takes over the domain from any current owner.
  • Ownership is handed back on stop. When a service that claimed a domain via --domains stops, the domain is handed back to its previous owner if that owner is still running.

Start with a service that declares a domain in its .denvig.yml:

.denvig.yml
services:
api:
command: pnpm dev
cwd: apps/api
http:
port: 3000
domain: api.local
secure: true

Starting it in the primary checkout claims api.local:

Terminal window
denvig services start api

https://api.local now routes to this service. Confirm what the gateway sees:

Terminal window
denvig gateway status

Suppose you create a git worktree for a feature branch:

Terminal window
git worktree add ../denvig-feature feature/x

Denvig sees feature/x as another worktree of the same project. You can start its copy of the api service alongside the one already running in main. By default it would contend for the same configured domain, so be explicit about intent.

To bring the feature copy up without touching api.local, start it with --no-domains. It runs on its own port and the main checkout keeps the domain:

Terminal window
denvig services start api --worktree feature/x --no-domains

Both copies are now running. List them to see the tree:

Terminal window
denvig services list

Option B — swap the domain to the worktree

Section titled “Option B — swap the domain to the worktree”

To point api.local at the feature worktree’s service instead — while the main copy keeps running — claim the domain explicitly:

Terminal window
denvig services start api --worktree feature/x --domains api.local

The feature worktree is now the owner of api.local; the main copy keeps running on its port but no longer holds the domain. Your browser hits the feature branch at the same URL, with no nginx edits and no restart of the other service.

Stop the feature copy and ownership is handed back to the still-running main service:

Terminal window
denvig services stop api --worktree feature/x

api.local routes to main again.

  1. Bring up the baseline in your primary checkout — it owns api.local:

    Terminal window
    denvig services start api
  2. Add a worktree for the branch you want to test:

    Terminal window
    git worktree add ../denvig-feature feature/x
  3. Swap api.local over to the feature worktree to test it at the real URL:

    Terminal window
    denvig services start api --worktree feature/x --domains api.local
  4. When you’re done, stop the feature copy — the domain returns to main:

    Terminal window
    denvig services stop api --worktree feature/x

A start can claim several domains at once — useful when a service answers on more than one hostname:

Terminal window
denvig services start api --domains api.local,api.test

Each domain is claimed independently and each is handed back to its own previous owner on stop.

If you change a service’s http settings, or the gateway and your running services drift apart, reconcile and rebuild every nginx config:

Terminal window
denvig gateway configure

The same workflow is available programmatically — claim domains per start with service.start({ domains }):

const project = await denvig.projects.retrieve('github:marcqualie/denvig')
// Swap api.local to the feature worktree's service
const feature = await project.services.retrieve('api', { worktree: 'feature/x' })
await feature.start({ domains: ['api.local'] })
// Hand it back by stopping the feature copy
await feature.stop()
// Inspect or rebuild the gateway
await denvig.gateway.status()
await denvig.gateway.configure()

See the SDK Gateway and SDK Services references for the full API.