From fdebc3cdb76e3b0ea038965166795949470b733e Mon Sep 17 00:00:00 2001 From: clockwork-labs-bot Date: Mon, 16 Feb 2026 22:00:59 -0500 Subject: [PATCH] docs: document how to access module owner via init reducer ctx.sender In the init reducer, ctx.sender is the identity of the user who published the database (the module owner). Document this behavior and show how to store the owner identity for later use in authorization checks. Closes #3229 --- .../00300-reducers/00500-lifecycle.md | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/docs/docs/00200-core-concepts/00200-functions/00300-reducers/00500-lifecycle.md b/docs/docs/00200-core-concepts/00200-functions/00300-reducers/00500-lifecycle.md index ef567fd2450..25a92904eb0 100644 --- a/docs/docs/00200-core-concepts/00200-functions/00300-reducers/00500-lifecycle.md +++ b/docs/docs/00200-core-concepts/00200-functions/00300-reducers/00500-lifecycle.md @@ -110,6 +110,65 @@ The `init` reducer: - Runs when clearing with `spacetime publish -c` - Failure prevents publishing or clearing +:::tip Module Owner +In the `init` reducer, `ctx.sender` is the **module owner** — the identity of the user who published the database. This is the only place where the owner identity is automatically provided, so if you need to reference it later (e.g. for authorization), store it in a table during `init`: + + + + +```typescript +const config = table({ name: 'config' }, { + ownerIdentity: t.identity().primaryKey(), +}); + +export const init = spacetimedb.init((ctx) => { + ctx.db.config.insert({ ownerIdentity: ctx.sender }); +}); +``` + + + + +```csharp +[SpacetimeDB.Table(Name = "Config")] +public partial struct Config +{ + [SpacetimeDB.PrimaryKey] + public Identity OwnerIdentity; +} + +[SpacetimeDB.Reducer(ReducerKind.Init)] +public static void Init(ReducerContext ctx) +{ + ctx.Db.Config.Insert(new Config { OwnerIdentity = ctx.Sender }); +} +``` + + + + +```rust +#[table(accessor = config)] +pub struct Config { + #[primary_key] + pub owner_identity: Identity, +} + +#[reducer(init)] +pub fn init(ctx: &ReducerContext) -> Result<(), String> { + ctx.db.config().try_insert(Config { + owner_identity: ctx.sender(), + })?; + Ok(()) +} +``` + + + + +You can then check `ctx.sender` against the stored owner identity in other reducers to restrict admin-only operations. +::: + ## Client Connected Runs when a client establishes a connection.