Custom reactive adapters
Connect Editorial Workflows to an unsupported host or data layer by implementing the store-agnostic reactive observer contract.
Prerelease
Editorial Workflows is a prerelease, built in public. Read How the prerelease works before you rely on it.
Use the Studio plugin inside Sanity Studio and the App SDK adapter in a custom application. Build another adapter only when a different host or data layer must drive the reactive session.
Build your own adapter
@sanity/workflow-react is store-agnostic. An adapter connects its hook core to a reactive document store by implementing WorkflowObserver, four useSyncExternalStore-shaped reads plus one write:
type ObserverState<T> =
| {status: 'loading'}
| {status: 'ready'; value: T}
| {status: 'invalid'; invalid: InvalidDoc}
| {status: 'error'; error: unknown}
interface DocStore<T> {
subscribe: (onChange: () => void) => () => void
getSnapshot: () => ObserverState<T>
}
interface ObservedInstances {
instances: readonly WorkflowInstance[]
unreadable: readonly InvalidDoc[]
}
interface WorkflowObserver {
observeInstance: (instanceId: string) => DocStore<WorkflowInstance | null>
observeDocs: (
documents: SubscriptionDocument[],
perspective: WorkflowPerspective | undefined,
) => DocStore<ReadonlyMap<string, SanityDocument | null>>
observeGuards: (args: {
instanceId: string
resources: readonly DatasetResourceId[]
sharedIds?: readonly string[]
}) => DocStore<readonly MutationGuardDoc[]>
observeInstances: (query: CompiledQuery) => DocStore<ObservedInstances>
ensureDocumentExists: (args: EnsureDocumentExistsArgs) => Promise<void>
}Every store starts in loading and resolves to ready, invalid, or error; a later successful emission clears either failure. Content documents pass through unvalidated. The instance and guard wrappers surface validation failure through the store’s wholesale invalid state. validatedInstancesStore instead validates each list row and returns {instances, unreadable} in a ready snapshot. Keep resolved snapshots referentially stable, including the shared NO_GUARDS identity for an empty guard list. The builder kit lives at @sanity/workflow-react/observer: validatedInstanceStore, validatedGuardsStore, validatedInstancesStore, combineDocStores, combineGuardStores, ensureDocumentExists, and useKeyed. Pass the completed observer to the hooks from @sanity/workflow-react.
Next steps
- App SDK: build an application with the shipped adapter.
- The reactive session: understand the live projection an adapter supplies.
- API reference: find the complete observer and hook contracts.
Visiting agent?
Editorial Workflows includes an MCP server for inspecting, operating, authoring, validating, and deploying workflows. Ask your human to set up the MCP server.