Skip to main content

Access Permissions

SpacetimeDB enforces different levels of table access depending on the context. All contexts access tables through ctx.db, but the available operations differ based on whether the context is read-write or read-only.

Reducers - Read-Write Access

Reducers receive a ReducerContext which provides full read-write access to tables. They can perform all CRUD operations: insert, read, update, and delete.

#[spacetimedb::reducer]
fn example(ctx: &ReducerContext) -> Result<(), String> {
    // Insert
    ctx.db.user().insert(User {
        id: 0,
        name: "Alice".to_string(),
        email: "alice@example.com".to_string(),
    });

    // Read: iterate all rows
    for user in ctx.db.user().iter() {
        log::info!("User: {}", user.name);
    }

    // Read: find by unique column
    if let Some(mut user) = ctx.db.user().id().find(123) {
        // Update
        user.name = "Bob".to_string();
        ctx.db.user().id().update(user);
    }

    // Delete
    ctx.db.user().id().delete(456);

    Ok(())
}

Procedures with Transactions - Read-Write Access

Procedures receive a ProcedureContext and can access tables through transactions. Unlike reducers, procedures must explicitly open a transaction to read from or modify the database.

#[spacetimedb::procedure]
fn update_user_procedure(ctx: &mut ProcedureContext, user_id: u64, new_name: String) {
    // Must explicitly open a transaction
    ctx.with_tx(|ctx| {
        // Full read-write access within the transaction
        if let Some(mut user) = ctx.db.user().id().find(user_id) {
            user.name = new_name.clone();
            ctx.db.user().id().update(user);
        }
    });
    // Transaction is committed when the closure returns
}

See the Procedures documentation for more details on using procedures, including making HTTP requests to external services.

Views - Read-Only Access

Views receive a ViewContext or AnonymousViewContext which provides read-only access to tables. They can query and iterate tables, but cannot insert, update, or delete rows.

#[spacetimedb::view(name = find_users_by_name, public)]
fn find_users_by_name(ctx: &ViewContext) -> Vec<User> {
    // Can read and filter
    ctx.db.user().name().filter("Alice").collect()

    // Cannot insert, update, or delete
    // ctx.db.user().insert(...) // ❌ Compile error
}

Client Access - Read-Only Access

Clients connect to databases and can access public tables through subscriptions and queries. See the Subscriptions documentation for details on client-side table access.