Globals
Use global hooks to shape reads and updates for singleton documents such as site settings.
Global hooks give you the same document-level control as collection hooks, but for singleton documents. They are the right fit for site settings, navigation, feature flags, or any other record that exists once and is updated in place.
By the end of this page, you should know which global hook to use for read shaping, validation, and post-update side effects.
The shape
Globals support four lifecycle phases:
import { defineGlobal, defineTextField } from '@dyrected/core'
export const SiteSettings = defineGlobal({
slug: 'site-settings',
fields: [
defineTextField({ name: 'siteName', label: 'Site name' }),
],
hooks: {
beforeRead: [],
afterRead: [],
beforeChange: [],
afterChange: [],
},
})There are no delete hooks because globals are not deleted through the API.
As with collections, beforeRead, afterRead, and beforeChange can use either function hooks or declarative string hooks. afterChange stays function-only.
If you are targeting Cloud, read Cloud-safe hooks alongside this page. That page is the canonical guide for what survives sync:schema and what gets stripped.
The four lifecycle phases
beforeRead
beforeRead runs before Dyrected fetches the global. Use it when the read should depend on request metadata or the caller before the stored document is returned.
Its shape matches collection beforeRead, so it is most useful when you want to inspect req, user, or the incoming query parameters consistently across reads.
For Cloud-safe cases, the declarative string form is usually the better default:
hooks: {
beforeRead: [
"user != null ? query : { status: { equals: 'published' } }",
],
}afterRead
afterRead runs after the global document is fetched and before the response is sent.
Use it to shape what callers receive without changing what is stored:
hooks: {
afterRead: [
({ doc, user }) => {
if (user?.roles?.includes('admin')) return doc
return { ...doc, internalBannerText: undefined }
},
],
}As with collection hooks, this phase gets a read-only database adapter.
You can also express simple response shaping declaratively:
hooks: {
afterRead: [
"user != null ? doc : { internalBannerText: null }",
],
}For Cloud-safe afterRead details, including the exact expression context, see Cloud-safe hooks.
beforeChange
beforeChange runs before the global is updated. Its operation is always 'update', because globals are updated in place.
Use it for normalization and guardrails:
hooks: {
beforeChange: [
({ data, doc }) => {
const siteName = typeof data.siteName === 'string' ? data.siteName.trim() : doc?.siteName
return {
...data,
siteName,
}
},
],
}Throwing here cancels the update.
For Cloud-safe value patching, use a declarative string hook:
hooks: {
beforeChange: [
"{ siteName: data.siteName }",
],
}For Cloud-safe beforeChange details, including the exact expression context, see Cloud-safe hooks.
afterChange
afterChange runs after the global update is committed. This is the right place for cache revalidation, search-index sync, or notifying another system that site-wide config changed.
import { defineGlobal, defineTextField } from '@dyrected/core'
async function revalidateRoute(path: string) {
await fetch(`https://example.com/api/revalidate?path=${encodeURIComponent(path)}`, {
method: 'POST',
})
}
export const SiteSettings = defineGlobal({
slug: 'site-settings',
fields: [
defineTextField({ name: 'siteName', label: 'Site name' }),
],
hooks: {
afterChange: [
async () => {
await Promise.all([
revalidateRoute('/'),
revalidateRoute('/about'),
])
},
],
},
})This phase receives the updated doc, the previousDoc, and a writable database adapter. Like collection afterChange, its errors are isolated from the already-successful write.
afterChange is still self-hosted function-hook territory. Use it for side effects, not for Cloud-safe declarative transforms.
What globals are especially good at
Global hooks are most useful when one change has broad frontend impact:
- refreshing header or footer data after an update
- invalidating cached layout pages
- keeping a mirror of site settings in another service
- normalizing editor-entered config values before they become canonical
What differs from collections
- No
beforeDeleteorafterDelete operationis always'update'- Only
beforeRead,afterRead, andbeforeChangehave a Cloud-safe declarative string form
If you need per-document logic on many records, that belongs on a collection hook, not a global.
Related pages
- Hooks overview for the shared mental model.
- Cloud-safe hooks for the Cloud-specific subset and sync behavior.
- Collection hooks for repeatable content.
- Global configuration for the rest of the global config surface.
- Hook context for the request and user data hook functions receive.