<!-- generated by iii-skill-render. DO NOT EDIT (changes here are overwritten on the next render). Edit docs/next/understanding-iii/namespaces.mdx. -->
Scanned 9/3/2026
Install to Claude Code
npx -y skills add iii-hq/iii --skill understanding-iii --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Understanding Iii?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/iii-hq-understanding-iii-3fd91116)More formats (shields.io, HTML) on the badges page.
<!-- generated by iii-skill-render. DO NOT EDIT (changes here are overwritten on the next render). Edit docs/next/understanding-iii/namespaces.mdx. -->
# Namespaces
## What a namespace is
A namespace is a routing value that the engine stores with a function id and a worker name. It is
not part of either value. For example `state::get` can exist as the same function id in `default`,
`orders`, and `analytics` namespaces.
The engine uses these registry keys:
- `(namespace, function_id)` for functions.
- `(namespace, worker_name)` for workers.
- `(namespace, trigger_type_id)` for trigger type providers.
A worker connection has one namespace. Its function, service, and trigger type registrations use
that namespace.
## Trigger types and the two namespaces a trigger names
A trigger names two namespaces, and they answer different questions:
- **`namespace`** is where the target function resolves when the trigger fires.
- **`trigger_namespace`** is where the trigger type's provider is found.
Both are optional. `namespace` absent means the engine's default namespace.
`trigger_namespace` absent is not `default`: the engine resolves it, taking the
registering worker's namespace first and the default namespace second.
That order is what lets a project ship its own provider for a trigger type the
engine also provides. The engine's own providers (`http`, `cron`, `state`,
`stream`) live in the default namespace, so a worker that names nothing reaches
them. A project that registers its own provider for the same type id gets that
one instead, without any worker changing how it binds.
Naming `trigger_namespace` explicitly is strict: that namespace or nothing. A
binding that names one is never moved.
A provider that registers after a binding already fell back to the default
namespace claims that binding back. Start order therefore does not decide which
provider serves a project.
## What namespaces enable
Namespaces let you ship one reusable worker package and deploy it for more than one tenant on the
same engine. Each tenant can run a worker named `state` and expose `state::get`. The worker package
does not need tenant-specific names.
```text
orders ──► state ──► state::get
analytics ─► state ──► state::get
```
Without namespaces, the two deployments claim the same worker name and function id. The engine
cannot route a call to the correct tenant. With namespaces, the tenant namespace selects the
deployment.
## Why the namespace is not a prefix
iii does not change `state::get` to `orders/state::get`. A function id is part of the worker
contract. It appears in schemas, skills, console output, commands, and documentation. A deployment
value must not change that contract.
The worker author defines the function id. The operator selects the namespace when they deploy the
worker. These two values stay separate.
## Why routing is strict
A call with `namespace: "orders"` resolves in `orders` only. A call with no namespace resolves in the
namespace of the calling worker.
The engine does not search other namespaces after a miss. A fallback could send a call to another
tenant. Instead, the engine returns `function_not_found` and lists the namespaces where the function
id exists.
The discovery functions are less strict when no namespace is present. For `engine::functions::info`
and `engine::workers::info`, a `default` entry has priority. If there is no `default` entry, a name
that exists in only one namespace resolves there. A name that exists in multiple namespaces returns
an ambiguity. An explicit namespace always uses strict resolution.
## Why the engine rejects a collision
Only one live worker can own a worker name in a namespace. Only one live worker can own a function
id in a namespace. The engine rejects a second owner instead of replacing the current owner.
A worker-name conflict is fatal. The engine closes the new connection because the worker cannot use
its declared identity. A function-id conflict rejects only that function. The worker stays connected
and serves its other functions.
Worker registration and function registration are separate operations. A connected worker does not
confirm that all its functions are registered. The SDK reports a function conflict as a warning.
A restart does not conflict with its own connection after teardown starts. The new connection can
reclaim the same worker name.
## How a connection gets its namespace
A worker declares its namespace in the `engine::workers::register` call. The engine starts a
namespace timer when the WebSocket connection opens. The default timeout is `5000 ms`.
A client can send registration messages before `engine::workers::register`. The engine holds
`RegisterFunction`, `UnregisterFunction`, `RegisterService`, `RegisterTrigger`, and
`UnregisterTrigger` messages until it knows the namespace. It does not register them in `default`
and move them later.
If `engine::workers::register` arrives first, the engine sets the declared namespace. An absent
value selects `default`. The engine then processes the held messages in arrival order.
If the timer expires first, the engine sets the connection namespace to `default` and processes the
held messages. A later worker registration cannot change that namespace.
To change the timeout, use `registration_namespace_grace_ms` or `III_NAMESPACE_GRACE_MS`. See
[Registration namespace timeout](../using-iii/configuration#registration-namespace-timeout).
## Use namespaces
For deployment configuration, SDK examples, cross-namespace calls, trigger targets, discovery, and
registration errors, see [Use namespaces](../using-iii/namespaces).
## Related
- [Use namespaces](../using-iii/namespaces)
- [Engine protocol](../reference/engine-protocol#namespaces)
- [Upgrade from 0.22.x](../upgrading/from-0-22-x)
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!