Skip to main content

Storage Scoping

Each table in your extension's schema can be scoped to control which installations share the same data. The scope is declared with .storage(scope) on defineTable.

Scopes

ScopeRows shared byUse case
"instance"One specific overlay installPer-install rules, settings, state
"overlay"All installs on the same overlayShared overlay leaderboard
"account"All installs across all overlays in one accountAccount-wide vote history
"global"All installs of this extension across all accountsGlobal community leaderboard

Example

// server/schema.ts
import { defineSchema, defineTable, v } from "@zaflun/lumio-sdk/server";

export default defineSchema({
// One set of rules per overlay install
rules: defineTable({
text: v.string(),
revealed: v.boolean(),
}).storage("instance"),

// Votes shared across all overlays in the account
votes: defineTable({
choice: v.string(),
userId: v.string(),
}).storage("account"),

// Global leaderboard shared across ALL streamers using this extension
globalLeaderboard: defineTable({
accountId: v.string(),
score: v.number(),
userName: v.string(),
}).storage("global"),
});

How scoping works

The scope is implemented via a scope_key column added automatically to each table:

Scopescope_key value
"instance"install_id (UUID of this specific install)
"overlay"overlay_id (UUID of the overlay)
"account"account_id (UUID of the account)
"global"extension_id (UUID of the extension itself)

All declarative functions (queryRows, insertRow, etc.) and ctx.db operations automatically filter by the correct scope_key based on the calling installation's context. You never need to filter by scope manually.

Choosing the right scope

"instance" (most common)

Use when each overlay install should have completely independent data:

// Each overlay the streamer creates has its own rules list
rules: defineTable({ text: v.string() }).storage("instance")

"overlay"

Use when multiple extensions installed on the same overlay should share data (rare):

// All extensions on "Gaming Overlay 1" share this chat log
chatLog: defineTable({ message: v.string() }).storage("overlay")

"account"

Use when data should persist across all overlays a streamer creates:

// Song requests appear on all overlays for this streamer
songRequests: defineTable({ title: v.string(), artist: v.string() }).storage("account")

"global"

Use for community features across all streamers:

// Global trivia high scores across all Lumio streamers
highScores: defineTable({
accountId: v.string(),
userName: v.string(),
score: v.number(),
}).storage("global")
warning

"global" scope means any installation can read and write this data. Use it only for truly public, community data. Never store sensitive or per-streamer data in global scope.

Mixing scopes in one schema

You can mix scopes freely within one schema:

export default defineSchema({
rules: defineTable({ text: v.string() }).storage("instance"), // per install
votes: defineTable({ choice: v.string() }).storage("account"), // per account
topPlays: defineTable({ score: v.number() }).storage("global"), // global
});