Appearance
Singleton Tables
singletonTable() defines a table whose keys are statically known and each has its own type. Use it for typed app settings, config, or any table where the set of keys is fixed.
This differs from table() (collection of same-shape values, dynamic keys) and from the "singleton row" usage of table() (one row under a fixed key).
Typed-Key Form
Each call to item(key, schema) declares one key and its value type:
typescript
import { defineSchema, singletonTable, item } from "poe-apps-sdk/v1/backend.js";
import { z } from "zod";
const schema = defineSchema({
schemaVersion: 1,
tables: {
settings: {
schema: singletonTable(
item("theme", z.enum(["light", "dark"])),
item("itemsPerPage", z.number()),
),
},
},
mutators: { /* ... */ },
});
// Reads are type-narrowed per key:
await ctx.table("settings").get("theme"); // "light" | "dark" | undefined
await ctx.table("settings").get("itemsPerPage"); // number | undefined
await ctx.table("settings").get("invalid"); // TYPE ERROR — unknown keySingle-Row Form
For a single logical record (e.g. a game-state row), use table(valueSchema) with a fixed itemKey:
typescript
import { z } from "zod";
import { defineSchema, table } from "poe-apps-sdk/v1/backend.js";
const schema = defineSchema({
schemaVersion: 1,
tables: {
game: { schema: table(z.object({ status: z.string(), turn: z.number() })) },
},
});
await ctx.table("game").get("game");
await ctx.table("game").set({ itemKey: "game", value: { status: "active", turn: 1 } });singletonTable() only accepts item(key, schema) arguments — there is no no-key form that takes a raw schema.
When to Use Which
- Collection of items (todos, moves, messages):
table(valueSchema)— keys are dynamic strings. - Typed settings bag (per-key types differ):
singletonTable(item(...), item(...), ...). - Single logical record with one shape:
table(valueSchema)with a fixed itemKey like"game".