Skip to content

Projects

vxnsin edited this page Sep 4, 2026 · 1 revision

Projects

Which services a project has tends to live in whichever start script somebody wrote, and nowhere a person can read. A warden.toml beside the code says it once, in something that gets committed and reviewed.

[project]
name = "shop"

[services.api]
kind = "backend"

[services.worker]
kind = "worker"

[services.web]
kind = "frontend"
preferred_port = 8905
$ warden apply
SERVICE      KIND      ADDRESS         WHAT
shop-api     backend   127.0.0.1:8900  taken
shop-worker  worker    127.0.0.1:8901  taken
shop-web     frontend  127.0.0.1:8905  taken

Run it again and it says renewed three times and changes nothing. It renews what is there; it never shuffles a running project onto different ports.

Not the same file as the settings. warden setup also writes a warden.toml, in the platform config directory. This one lives beside your code and is read only by warden apply. Different place, different contents.

What the file may say

[project]

Key Meaning
name Prefixes every service, so api registers as shop-api
host Interface for every service, default 127.0.0.1

[services.<key>]

Key Meaning
kind Required. What the service is
name Register under this instead of <project>-<key>
host Just this one, overriding the project
preferred_port Wish for this port, take another if it is not free
require_port Insist on this port, and fail the whole run if it is taken
ttl Release it again after this many seconds
meta A table of strings kept with the registration

A misspelt key is refused by name — no setting called prefered_port; there is only host, kind, meta, .... A manifest that quietly does nothing is worse than one that will not load.

Writing the ports where the code can read them

$ warden apply --env .env
# Written by `warden apply` from warden.toml. Regenerate it; do not edit it.
SHOP_API_HOST=127.0.0.1
SHOP_API_PORT=8900
SHOP_WORKER_HOST=127.0.0.1
SHOP_WORKER_PORT=8901

The whole file is rewritten every time and says so at the top, because the one thing certain to happen otherwise is somebody editing it by hand and losing it. Add it to .gitignore; the manifest is the thing worth committing.

Variable names come from the project and the service key, uppercased, with anything else turned into an underscore: shop.eu and web-1 give SHOP_EU_WEB_1_PORT.

Giving them back

$ warden apply --release
SERVICE      KIND      ADDRESS         WHAT
shop-api     backend   127.0.0.1:8900  released

A service that was never registered comes back as gone rather than an error.

A half-registered project is not a state that exists

Services that insist on a particular port are registered first, since those are the ones that can refuse the whole run. If anything fails, what the run took, the run gives back before it stops:

$ warden apply
port 8002 is held by 'squatter'
$ warden ls
squatter  backend  -  127.0.0.1:8002

Nothing from the manifest is left behind.

What it is not

warden apply does not start anything. It makes the registry agree with the file and gets out of the way; starting the services is your process manager's job, reading the .env it just wrote. For a single command on a single port, warden run -- npm run dev is smaller and needs no file at all.

Clone this wiki locally