Studio plugin configuration reference

Options, mapping rows, structure helpers, and embeddable tables of @sanity/workflow-studio-plugin, and how it differs from the @sanity/workflow-studio adapter.

This page lists the configuration contract of @sanity/workflow-studio-plugin at Workflows 0.37: the workflowStudioPlugin options, mapping rows, the structure helpers, and the table components a custom Studio tool can embed. To install the plugin and start a workflow from the document editor, follow Add Workflows to Sanity Studio.

Plugin and adapter packages

Package

What it provides

Use it when

@sanity/workflow-studio-plugin

workflowStudioPlugin, the document strip, the Workflows document view, the Workflows tool, structure helpers, and RunsTable/ForMeTable.

You want the ready-made Studio interface. This page documents it.

@sanity/workflow-studio

The Studio adapter: useWorkflowEngine, useWorkflowSession, useDocumentWorkflows, useWorkflowInstances, useWorkflowInstancePreviews, makeStudioObserver, and project-user helpers. The plugin is built on it.

You build your own Studio controls, such as a Document Action. Its session contract is in the reactive session and adapter reference, and its exports are in TypeDoc.

The plugin requires sanity 6.15 or later in the 6.x line, react and react-dom 19.2.7 or later, styled-components 6.4.2 or later, @sanity/sdk 3.1 or later in the 3.x line, and @sanity/workflow-components, @sanity/workflow-diagram, @sanity/workflow-engine, @sanity/workflow-react, and @sanity/workflow-studio at the same version as the plugin.

Example

import {defineConfig} from 'sanity'
import {structureTool} from 'sanity/structure'
import {
  workflowDefaultDocumentNode,
  workflowStudioPlugin,
} from '@sanity/workflow-studio-plugin'

export default defineConfig({
  // ...your projectId, dataset, schema...
  plugins: [
    structureTool({defaultDocumentNode: workflowDefaultDocumentNode()}),
    workflowStudioPlugin({
      partition: 'dev',
      mappings: [
        {
          docType: 'article',
          definition: 'article-review',
          label: 'Article review',
          autoStart: true,
        },
      ],
    }),
  ],
})

workflowStudioPlugin

workflowStudioPlugin(config) is a Studio plugin factory. Add its return value to plugins in defineConfig. The plugin validates config when sanity.config.ts is evaluated, so a configuration error stops the Studio from starting.

WorkflowPluginConfig

WorkflowPluginConfig is the options object passed to workflowStudioPlugin. Every property is optional and read-only.

  • partition

    string, optional

    The engine partition every workflow read and write is scoped to. Must match the partition the definitions were deployed under. Defaults to default, the partition a deployment resolves to when it is alone on its workflow resource and omits partition. Lowercase ASCII letters, digits, and dashes; an invalid value throws ContractViolationError when the config is evaluated.

    When the partition holds no deployed definitions, the plugin logs a browser console warning naming the partitions on its workflow dataset that do.

  • tag

    string, deprecated

    The pre-0.37 name for partition (LegacyTagWorkflowPluginConfig). The plugin uses the value and logs [workflows] workflowStudioPlugin: Replace tag: "dev" with partition: "dev". Removing "tag" without adding "partition" selects the "default" partition instead. A tag that differs from partition throws workflowStudioPlugin: "tag" and "partition" disagree.

  • workflowDataset

    string, optional

    The dataset holding workflow definitions and instances. Defaults to the workspace's own dataset.

  • mappings

    readonly WorkflowMapping[], optional

    Rows that override or extend the bindings discovered from definition subjects. Defaults to none, in which case the effective table comes entirely from discovery.

  • effectHandlers

    Record<string, EffectHandler<SanityClient>>, optional

    Effect handlers to run in the browser while an editor has the Studio open on a workflow that commits an action. An effect with no handler registered here stays pending for another runtime to claim, which is what unattended or consequential work needs.

  • resourceClients

    (parsed: ParsedGdr) => WorkflowClient | undefined, optional

    Resolves clients for documents in other datasets, projects, or resources. Defaults to per-dataset routing derived from the Studio client. A served resource is part of the declared surface for written references, so keep the resolver identity stable: define it at module scope or memoize it.

  • previewHydration

    {pageSize?: number; interPageDelayMs?: number}, optional

    Throttles progressive loading of run previews. pageSize defaults to 500 and interPageDelayMs to 0. Intended for development harnesses simulating small pages and slow reads; production defaults need no override.

WorkflowMapping

A mapping row binds one Studio document type to one deployed definition, replacing whatever discovery derived for that exact docType and definition pair, or adding the pair when discovery did not produce it. One document type may appear on several rows. Two rows for the same pair throw while sanity.config.ts is evaluated, so the Studio does not start.

Without mapping rows, the plugin discovers bindings itself. It reads the latest deployed version of each definition and binds every startable workflow whose input-sourced subject field accepts a Studio schema document type. A row is needed to bind a reserved sanity. or system. type, to bind a definition that uses a doc.ref field named subject instead of a first-class subject, to enable autoStart, or to change the label, start values, or perspective.

  • docType

    string, required

    The Studio schema type this row binds. Reserved types in the sanity. and system. namespaces need an explicit row. A workflow that binds the document through a subject must explicitly accept its type. Engine-owned document types are invalid mapping targets.

  • definition

    string, required

    The name the definition was deployed under.

  • label

    string, required

    The label editors see in menus and dialogs. Required on an explicit row; discovery-derived rows fall back to the definition's title, then its name.

  • autoStart

    boolean, optional

    Starts this workflow when an editor creates a fresh document of docType in Studio. Defaults to false. Existing documents and writes outside Studio are unaffected.

  • initialStateBuilder

    (subjectGdr: GlobalDocumentReference) => InitialFieldValue[], optional

    Seeds workflow fields for a manual start. Replaces the default subject seed entirely, so an empty array seeds nothing. Does not run during auto-start.

  • contextBuilder

    (subjectGdr: GlobalDocumentReference) => StartContext, optional

    Seeds $context for the run. Not applied when the workflow starts through autoStart.

  • perspectiveField

    {name: string; required?: boolean}, optional

    Binds the run to the editor's selected Content Release through the named release.ref entry. required defaults to false, in which case the workflow starts with no perspective and uses its own defaults. When required is true, starting is blocked until an active release is selected.

A row whose definition is not deployed, or whose seeded values do not fit the deployed definition, is disabled rather than thrown. Its start control shows Unavailable — this workflow isn’t set up correctly for <Type> documents, and the reason appears under Setup issue on that workflow's page in the Workflows tool and in the browser console, prefixed [workflow-studio-plugin]. A row rejects when it seeds an undeclared, duplicate, wrong-kind, or non-input field, a document type the subject's types does not accept, a local document type the Studio schema does not declare, or one of the engine's own document types. A required input the row leaves unset is not an error; the start dialog collects it.

Structure helpers

  • workflowDefaultDocumentNode

    () => DefaultDocumentNodeResolver

    Takes no arguments. Returns a resolver giving every document type the form view plus the Workflows view; the plugin decides at runtime which workflows apply. Pass it as structureTool({defaultDocumentNode: workflowDefaultDocumentNode()}).

  • workflowsView

    (S: StructureBuilder) => ViewBuilder

    The Workflows view for a single document. Append it to a document type's own views([...]) to place the view selectively instead of on every type.

import {structureTool} from 'sanity/structure'
import {workflowsView} from '@sanity/workflow-studio-plugin'

structureTool({
  defaultDocumentNode: (S, {schemaType}) =>
    schemaType === 'article'
      ? S.document().views([S.view.form(), workflowsView(S)])
      : S.document(),
})

Workflow tables

RunsTable renders workflow runs and ForMeTable renders tasks assigned to one person. Both keep the Workflows tool's document previews, member faces, task hints, and virtualized rows. Render them inside a Studio configured with workflowStudioPlugin, in a height-constrained container with overflowY: 'auto' so rows can scroll. For controls outside Studio, use Reusable UI components; these tables depend on Studio providers.

The tables are controlled components. Your tool loads data and renders loading, error, and empty states; filters and sorts rows before passing them in; owns selection, focus, and keyboard navigation; and resets the scroll position when the scope or sort changes.

RunsTable

  • Requiredrows

    readonly RunRow[]

    The rows to render, already filtered and sorted. Build them with runRowsOf.

  • Requiredscope

    'open' | 'closed'

    Which columns to show: in-flight runs or settled runs.

  • RequiredscopedToWorkflow

    boolean

    Hides the workflow column when every row belongs to one workflow.

  • Requiredsort

    RunSort

    The current sort, {key, dir}, shown in the header. key is document, workflow, stage, outcome, started, or ended; dir is asc or desc.

  • RequiredonSort

    (key: RunSortKey) => void

    Reports the column a user asked to sort by. It does not reorder rows; apply the sort and pass new rows and sort.

  • RequiredonSelectRun

    (row: RunRow) => void

    Called when a user selects a row.

  • Requirednow

    Date

    The clock relative timestamps and overdue marks are measured against. Update it to refresh them.

  • RequiredonNavigateKey

    (event: RunNavigationKeyEvent) => void

    Called for keyboard input on the selected row, with {key, preventDefault}. The host owns navigation.

  • RequiredselectedId

    string | undefined

    The selected row's id. That row becomes the table's roving tab stop.

  • RequiredselectedRef

    (element: HTMLElement | null) => void

    Receives the selected row's element, for host focus and scrolling.

ForMeTable

  • Requiredrows

    readonly ForMeTaskRow[]

    The task rows to render, already filtered and sorted. Build them with forMeTaskRowsOf.

  • Requiredsort

    ForMeSort

    The current sort, {key, dir}. key is document, due, opened, task, or workflow.

  • RequiredonSort

    (key: ForMeSortKey) => void

    Reports the column a user asked to sort by. It does not reorder rows.

  • RequiredonSelect

    (row: ForMeTaskRow) => void

    Called when a user selects a row.

  • Requirednow

    Date

    The clock relative timestamps and overdue marks are measured against. Update it to refresh them.

  • RequiredonNavigateKey

    (event: RunNavigationKeyEvent) => void

    Called for keyboard input on the selected row, with {key, preventDefault}. The host owns navigation.

  • RequiredselectedId

    string | undefined

    The selected row's id. That row becomes the table's roving tab stop.

  • RequiredselectedRef

    (element: HTMLElement | null) => void

    Receives the selected row's element, for host focus and scrolling.

Row builders

  • runRowsOf({previews, definitions, now})(): RunRow[]

    Builds one row per instance preview. A run preview is a reduced instance record used in lists. definitions is a ReadonlyMap of deployed definitions by name, used for titles; a missing definition falls back to its raw name. Include settled parent previews so a spawned child keeps its root document attribution. now is the moment overdue is measured against.

  • forMeTaskRowsOf({rows, who})(): ForMeTaskRow[]

    Selects the tasks in rows that who holds, one row per task. who is {userId, roles}: an account-global user ID and resolved project role names. A direct assignment outranks a held role.

The package also exports the row and sort types these props use: RunRow, RunAttention, RunAttentionDetail, RunBlockedDetail, RunOverdueDetail, ForMeTaskRow, StageTask, AssignmentIdentity, TaskAssignment, TaskHolding, RunsScope, RunSort, RunSortKey, ForMeSort, ForMeSortKey, and RunNavigationKeyEvent. See TypeDoc for their fields.

Was this page helpful?

sanity.ioAll Systems Operational© Sanity 2026
Change site theme