QUESTPIE

Global API

Complete reference for global() builder methods.

global(name)

Creates a new global builder. Globals are singleton records (one row per global) used for site settings, configuration, and other single-instance data.

import { global } from "#questpie/factories";

const siteSettings = global("siteSettings")
	.fields(({ f }) => ({
		siteName: f.text(255).required(),
		tagline: f.text(255).localized(),
		logo: f.upload(),
		maintenanceMode: f.boolean().default(false),
		socialLinks: f.object(),
	}))
	.options({ timestamps: true })
	.hooks({
		afterChange: async ({ data, kv }) => {
			await kv.delete("site-settings-cache");
		},
	})
	.access({
		read: true,
		update: ({ session }) => session?.user?.role === "admin",
	});

Builder Methods

All methods are chainable and return a new builder instance.

MethodDescription
.fields()Define data fields using the field builder
.options()Configure timestamps, versioning, scoped mode
.hooks()Attach lifecycle hooks
.access()Set access control rules
.set()Generic extension point for plugins

With @questpie/admin installed:

MethodDescription
.admin()Admin UI metadata (label, icon)
.form()Configure the form view

.fields(callback)

Define global fields using the field builder. Works identically to collection fields.

.fields(({ f }) => ({
  siteName: f.text(255).required(),
  description: f.textarea().localized(),
  logo: f.upload(),
  theme: f.select([
    { value: "light", label: "Light" },
    { value: "dark", label: "Dark" },
    { value: "system", label: "System" },
  ]).default("system"),
  analytics: f.object(),
}))

.options(config)

Configure global-level options.

.options({
  timestamps: true,       // Adds createdAt, updatedAt (default: true)
  versioning: true,       // Creates a versions table for history
  scoped: true,           // Scope globals by scope_id (multi-tenant)
})

When scoped is enabled, the global stores one row per scope instead of a single global row.

Versioning with Workflow

Like collections, globals support versioning with optional publishing workflow:

.options({
  versioning: {
    enabled: true,
    workflow: {
      stages: ["draft", "published"],
      initialStage: "draft",
    },
  },
})

.hooks(config)

Attach lifecycle hooks. Globals support the same hook types as collections.

.hooks({
  beforeChange: ({ data }) => {
    if (data.siteName) {
      data.siteName = data.siteName.trim();
    }
  },
  afterChange: async ({ data, kv }) => {
    // Invalidate cache when settings change
    await kv.delete("site-settings-cache");
  },
})

.access(config)

Set access control rules. Globals support read and update operations (no create/delete since they are singletons).

.access({
  read: true,
  transition: ({ session }) => session?.user?.role === "editor",
  update: ({ session }) => session?.user?.role === "admin",
})

transition controls workflow stage transitions. If it is omitted, workflow transitions fall back to the update rule.

.set(key, value)

Generic extension point for plugins to attach metadata.

.set("admin", { icon: { type: "icon", props: { name: "ph:gear" } } })

Admin Extension Methods

.admin(callback)

Set admin UI metadata for the global.

.admin(({ c }) => ({
  label: { en: "Site Settings" },
  icon: c.icon("ph:gear"),
}))

.form(callback)

Configure the admin form view.

.form(({ v, f }) => v.globalForm({
  fields: [
    f.siteName,
    f.tagline,
    {
      type: "section",
      label: "Appearance",
      fields: [f.logo, f.theme],
    },
  ],
}))

Server API

Read and update globals through the runtime API:

// Read the global value
const settings = await globals.siteSettings.get();
console.log(settings.siteName);

// Update the global
await globals.siteSettings.update({
	siteName: "New Site Name",
	maintenanceMode: true,
});

With localized fields, pass a locale:

const settings = await globals.siteSettings.get({ locale: "sk" });
await globals.siteSettings.update({ tagline: "Novy slogan" }, { locale: "sk" });

Client API

Access globals from the client using the typed API client:

const settings = await client.globals.siteSettings.get();
await client.globals.siteSettings.update({ siteName: "Updated" });

With workflow enabled, get() and update() accept stage:

const published = await client.globals.siteSettings.get({
	stage: "published",
});

await client.globals.siteSettings.update(
	{ announcement: "Launching soon" },
	{ stage: "draft" },
);

Workflow Transition API

Use transitionStage() to move a global to a target workflow stage without mutating the working row:

await globals.siteSettings.transitionStage({
	stage: "published",
});

The client SDK supports the same call, including scheduled transitions:

await client.globals.siteSettings.transitionStage({
	stage: "published",
	scheduledAt: new Date("2026-05-01T09:00:00Z"),
});

Transition validation matches collections: the target stage must exist, the transition graph must allow the move, access.transition must pass or fall back to access.update, and transition hooks run around the version snapshot.

Type Inference

Globals provide type inference through $infer:

type SettingsSelect = typeof siteSettings.$infer.select;
type SettingsInsert = typeof siteSettings.$infer.insert;
type SettingsUpdate = typeof siteSettings.$infer.update;

On this page