Namespaces
Namespaces provide logical isolation between environments (dev/staging/prod) or
between tenants sharing the same infrastructure. Most Stem components honor the
namespace when naming queues, result keys, and control channels. Unless you pass
an explicit namespace, adapters default to stem.
What uses the namespace
- Brokers & backends: queue streams, task results, heartbeats, and dead letters are scoped by the namespace configured on each adapter.
- Schedule & lock stores: schedule entries and scheduler locks use namespace-prefixed keys/tables so multiple schedulers can share a store.
- Revoke stores: revocation entries are scoped by namespace.
- Workflow stores: workflow runs and topic queues are namespaced.
- Control plane: worker control channels and heartbeat topics use the worker namespace.
- Dashboard: reads control/observability data using its configured namespace.
Configure namespaces
- Broker + Backend
- Worker Heartbeats
- Isolation
Broker namespace
Future<RedisStreamsBroker> connectNamespacedBroker() {
return RedisStreamsBroker.connect(
'redis://localhost:6379/0',
namespace: 'prod-us-east',
);
}
Backend namespace
Future<RedisResultBackend> connectNamespacedBackend() {
return RedisResultBackend.connect(
'redis://localhost:6379/1',
namespace: 'prod-us-east',
);
}
Broker + Backend (combined)
Future<void> configureNamespace() async {
final broker = await RedisStreamsBroker.connect(
'redis://localhost:6379/0',
namespace: 'prod-us-east',
);
final backend = await RedisResultBackend.connect(
'redis://localhost:6379/1',
namespace: 'prod-us-east',
);
await broker.close();
await backend.close();
}
lib/namespaces.dart
Future<void> configureWorkerNamespace() async {
final registry = SimpleTaskRegistry();
final broker = InMemoryBroker(namespace: 'prod-us-east');
final backend = InMemoryResultBackend();
final worker = Worker(
broker: broker,
registry: registry,
backend: backend,
heartbeatNamespace: 'prod-us-east',
);
await worker.shutdown();
await backend.close();
await broker.close();
}
Namespace isolation
Future<void> isolateNamespaces() async {
final teamABroker = await RedisStreamsBroker.connect(
'redis://localhost:6379/0',
namespace: 'team-a',
);
final teamBBroker = await RedisStreamsBroker.connect(
'redis://localhost:6379/0',
namespace: 'team-b',
);
await teamABroker.close();
await teamBBroker.close();
}
Environment variables
Stem does not use a single global namespace variable; instead, namespaces are
configured per adapter or via the worker observability settings. The default is
stem when no override is provided.
| Variable | Purpose | Default |
|---|---|---|
STEM_WORKER_NAMESPACE | Worker heartbeat/control namespace when using ObservabilityConfig.fromEnvironment | stem |
STEM_WORKFLOW_NAMESPACE | Workflow store namespace used by the CLI workflow runner | stem |
STEM_DASHBOARD_NAMESPACE | Namespace the dashboard reads | falls back to STEM_NAMESPACE or stem |
STEM_NAMESPACE | Dashboard fallback namespace value | stem |
CLI usage
When using a non-default namespace, pass it explicitly to worker control commands:
stem worker stats --namespace "staging"
stem worker ping --namespace "staging"
Tips
- Keep namespaces consistent across producers, workers, schedulers, and CLI.
- Use per-environment namespaces (e.g.,
dev,staging,prod) to avoid cross- environment interference. - If the dashboard shows no data, verify
STEM_DASHBOARD_NAMESPACEmatches your worker namespace.