Zaroz
Units

Private names

Services in the same project can talk to each other over a private network, using names rather than addresses. Nothing here leaves the region, and nothing here is billed. This page is the reference for those names; the Minecraft network guide uses them end to end.

Two kinds of name

For a Workload (a Worker, a Web App, anything that runs units) with the slug lobby:

namereaches
lobbyevery ready unit. DNS answers with all of their addresses, so a client that picks one spreads over them. Use this for normal requests.
<key>.lobbyone specific unit, by its key: u1.lobby, u2.lobby, ... for units the scaling policy makes, or a name you chose, such as duel-77.lobby, for units your code creates.

A unit's key and its full private_name are both fields of the unit in the Units API, so a program never has to build a name by hand:

JSONCode
{ "key": "u2", "private_name": "u2.lobby", "state": "running" }

The key is stable for as long as the unit lives. When a unit is scaled away its name stops resolving, and a later unit can take the same key.

The rules

  1. Same project only. Every project is its own isolated network. A unit can reach any other unit of its own project on any port, and nothing in another project. A name never resolves outside the project that owns it, and there is no cross-project name.
  2. The slug must start with a letter. The name is a DNS label, and DNS requires a service name to begin with a letter (a DNS-1035 label). A Workload whose slug starts with a digit, for example 1api, simply gets no private name: its units have private_name: null. Rename it to api1 or lobby and the name appears. Renaming moves the name, which replaces the units through the normal rolling rollout.
  3. Only ready units answer. A unit that is starting, crashing or stopped is left out of lobby, and <key>.lobby does not resolve until that unit is ready.
  4. One name per slug. The slug is unique inside a project, so the name is too. If a product's own template already uses the slug as the name of a network service, the Workload keeps that one and gets no private name.

A name does not publish a port

A private name is only a name. It does not open, forward or load-balance any port: you connect to the name on the port your program listens on, for example u1.lobby:25565, exactly as if it were a host name in a LAN. Two consequences:

  • You never declare a port to make a private name work. Any port the unit listens on is reachable from the same project.
  • It is not a public address. To let the internet in, use an endpoint, which is a separate, billed object.

When to use which

  • Another service calling your API: use api. When units come and go, the name always points at the ones that are ready.
  • Something that must talk to one particular copy, for example a coordinator telling unit 3 to drain, or a game proxy sending players to a known server: use u3.lobby.
  • A name does not keep a request on the same unit: two connections to lobby can reach two different units, so do not rely on one unit remembering the previous request.

Examples

TerminalCode
# from a shell in any unit of the same project getent hosts lobby # one line per ready unit getent hosts u2.lobby # that unit's address nc -vz u2.lobby 25565 # reachable on any port the unit listens on
TypeScriptCode
// Node: connect to one specific backend by its private name import net from "node:net"; const socket = net.connect({ host: "u2.lobby", port: 25565 });
Code
import socket # any ready unit of the Workload `lobby` sock = socket.create_connection(("lobby", 25565), timeout=3)

In code mode, units you create from code get the keys you choose, such as duel-77.lobby.

Last modified on