> ## Documentation Index
> Fetch the complete documentation index at: https://iii.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Namespaces

> Set worker namespaces, call namespaced functions, and handle namespace conflicts.

Every worker has an effective namespace. A worker uses `default` when you do not set one. Use a
non-default namespace when multiple tenants or projects must use the same worker name or function id
on one engine.

## Set a worker namespace

The SDK selects the worker namespace in this order:

| Priority | Source |
| - | - |
| 1 | The explicit `namespace` SDK option |
| 2 | The worker process `III_NAMESPACE` environment variable |
| 3 | `default` |

Use a non-empty string for a namespace. Leave the option out and the SDK reads `III_NAMESPACE`
itself, then falls back to `default`; an absent option gives the same result as passing
`process.env.III_NAMESPACE` (`os.environ.get("III_NAMESPACE")`,
`std::env::var("III_NAMESPACE").ok()`). A `null`, a `None`, or any other non-string value is invalid
and fails in both the SDK and at the engine.

### SDK option

Use the explicit option when application code must select the namespace. The option has priority
over `III_NAMESPACE`.

> [tab] Node / TypeScript
>
> ```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> import { registerWorker } from "iii-sdk";
>
> const worker = registerWorker(process.env.III_URL!, {
>   workerName: "state",
>   namespace: "orders",
> });
> ```

> [tab] Python
>
> ```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> import os
> from iii import InitOptions, register_worker
>
> worker = register_worker(
>     os.environ["III_URL"],
>     InitOptions(worker_name="state", namespace="orders"),
> )
> ```

> [tab] Rust
>
> ```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> use iii_sdk::{InitOptions, register_worker};
>
> let url = std::env::var("III_URL").expect("III_URL must be set");
> let worker = register_worker(
>     &url,
>     InitOptions {
>         namespace: Some("orders".into()),
>         ..Default::default()
>     },
> );
> ```

> [tab] Browser
>
> ```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> import { registerWorker } from "iii-browser-sdk";
>
> const worker = registerWorker("ws://localhost:49135", {
>   workerName: "checkout-tab",
>   namespace: "orders",
> });
> ```

The browser SDK cannot read a process environment. Pass its namespace explicitly or obtain it from
trusted runtime configuration.

## Trigger a function in a namespace

Set `namespace` on the invocation. The call resolves only in that namespace. Omit the field and the
call resolves in the caller's own namespace, which is where a worker's neighbours are. A worker with
no namespace of its own resolves in `default`, as before.

> [tab] CLI
>
> ```bash theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> iii trigger --namespace orders state::get key=cart
> ```

> [tab] Node / TypeScript
>
> ```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> const result = await worker.trigger({
>   function_id: "state::get",
>   payload: { key: "cart" },
>   namespace: "orders",
> });
> ```

> [tab] Python
>
> ```python theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> result = worker.trigger({
>     "function_id": "state::get",
>     "payload": {"key": "cart"},
>     "namespace": "orders",
> })
> ```

> [tab] Rust
>
> ```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> use iii_sdk::protocol::TriggerRequest;
> use serde_json::json;
>
> let result = worker
>     .trigger(
>         TriggerRequest {
>             function_id: "state::get".into(),
>             payload: json!({ "key": "cart" }),
>             action: None,
>             timeout_ms: None,
>         }
>         .namespace("orders"),
>     )
>     .await?;
> ```

A miss returns `function_not_found`. The error lists other namespaces where the function id exists.

> [!NOTE]
>
> `iii trigger --namespace <NS>` calls a function in that namespace. Without the flag it resolves in
> `default`: a CLI invocation has no namespace of its own to inherit.

## Point a trigger at a namespaced function

Both the typed helpers returned by `registerTriggerType` and the low-level `registerTrigger` bind
the target to the worker's namespace. Set `namespace` to bind it elsewhere, which is what a trigger
pointing at an engine builtin needs, since those exist only in `default`.

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
// Bound to this worker's namespace.
worker.registerTrigger({
  type: "http",
  function_id: "state::get",
  config: { api_path: "/orders/state", http_method: "GET" },
});

// Bound to `default`, where the engine's own functions live.
worker.registerTrigger({
  type: "cron",
  function_id: "engine::workers::list",
  config: { schedule: "0 * * * *" },
  namespace: "default",
});
```

## Observe a namespaced function

An observer resolves its source like a call: `source.namespace` when set, else the observing
worker's namespace (`engine::*` and `configuration::*` resolve to `default`). The target resolves the
same way; name another namespace with the object form of the target (Go: `ObserverOptions.TargetNamespace`).

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
worker.observe(
  { function_id: "orders::create", namespace: "shop" },
  { function_id: "audit::record", namespace: "audit" },
);
```

See [Observers](https://iii.dev/docs/0-25-0/using-iii/observers.md).

## Inspect namespaces

Every row from `engine::functions::list` and `engine::workers::list` contains a `namespace` field.
The list functions return all namespaces.

Pass `namespace` to an info function for strict lookup:

```bash theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
iii trigger engine::workers::info --json '{"name":"state","namespace":"orders"}'
```

Without a namespace, `engine::functions::info` and `engine::workers::info` first use a `default`
entry. If no `default` entry exists, they resolve a name that exists in only one namespace. They
return an ambiguity when the name exists in multiple namespaces.

## Handle a rejected registration

The engine sends `registrationrejected` when a live worker already owns the same identity in the
same namespace.

| Code | Effect |
| - | - |
| `WORKER_NAMESPACE_CONFLICT` | Fatal. The engine closes the new connection. The SDK does not reconnect. |
| `FUNCTION_NAMESPACE_CONFLICT` | The engine rejects one function. The worker stays connected and serves its other functions. |

For a worker-name conflict, change the worker name or namespace. For a function conflict, remove the
duplicate function id or move one worker to another namespace.

> [!WARNING]
>
> A connected worker does not confirm that all its functions are registered. SDKs report a function
> conflict as a warning. Treat the warning as a startup error when the worker requires every
> function.

For the wire fields and the exact conflict sequence, see
[`RegistrationRejected`](../reference/engine-protocol#registrationrejected).

## Configure RBAC for a namespace

An `iii-worker-manager` `expose_functions` rule without a namespace applies to `default` only. Add
the exact namespace when the rule must expose a namespaced function. See
[Namespace-scoped function rules](https://iii.dev/docs/0-25-0/creating-workers/worker-manager.md#namespace-scoped-function-rules).

## Related

* [Understand namespaces](https://iii.dev/docs/0-25-0/understanding-iii/namespaces.md)
* [Registration namespace timeout](https://iii.dev/docs/0-25-0/using-iii/configuration.md#registration-namespace-timeout)
* [Upgrade from 0.22.x](https://iii.dev/docs/0-25-0/upgrading/from-0-22-x.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.