Ports & Port Allocation
Every kilter project needs a bundle of host ports — the app, postgres, redis, a mail UI, maybe eight Ory endpoints. Kilter allocates them deterministically per project: the same project always gets the same ports on the same machine, and no two projects' allocations collide. That's what lets you run several projects side by side without a single "port already in use" fight.
Container ports vs localhost ports
Each service has two port numbers, and they mean different things:
| Example (postgres) | Who uses it | |
|---|---|---|
| Container port | 5432 | Pods, via in-cluster DNS: postgres.<ns>.svc:5432 |
| Localhost port | 30530 | Your host: browser, psql, curl, GUI clients |
The container port is the service's conventional port and is stable everywhere. The localhost port is the NodePort-style mapping kilter allocated for this project — kilter picks it, and it differs across projects by design.
So a service's two connection strings look like:
# In-cluster:
REDIS_URL=redis://redis.kilterkb-dev.svc:6379
# Localhost:
REDIS_URL=redis://localhost:30531Use the in-cluster form in code that runs in a pod; the localhost form in anything on your host. (More on this split in Namespaces & isolation.)
Reading kilter env
kilter env prints every connection string for the current project — app URL, each service's localhost and in-cluster addresses, credentials for dev services. It is generated from the live allocation, which makes it the source of truth:
kilter env
# http://localhost:30529 ← your app
# DATABASE_URL=postgresql://localhost:30530/…
# REDIS_URL=redis://localhost:30531
# MAILPIT_UI=http://localhost:30540
# …When something can't connect, check kilter env first — before your .env file, before the code. If the values disagree, kilter env wins and the .env file is stale.
Never hardcode ports across projects
Ports are deterministic per project, not global. Copying a .env, a script, or a snippet from one project into another carries the wrong ports with it — project A's 30530 may be project B's mailpit, or nothing at all. Every copied config must have its ports re-derived from that project's own kilter env.
Safe patterns:
- Read ports from the environment, never as literals:
process.env.DATABASE_URL, notlocalhost:30530in code. - Regenerate, don't copy: when setting up a project on a new machine, run
kilter envthere rather than shipping a.envaround. - Container ports are the exception —
5432,6379,1025are stable conventions and fine to rely on for in-cluster addresses.