Editorial Workflows

Definitions and instances

A definition describes a process. An instance is one run of that process.

A workflow definition is the authored, deployable description of a process. It combines fields, stages and transitions, activities and actions, conditions, effects, and guards into one versioned contract.

An instance is the durable state of one run. One definition can produce many instances, each with its own field values, current stage, history, pending effects, and child workflows.

Define a workflow

Use defineWorkflow to author a definition:

Loading...
const articleReview = defineWorkflow({
  name: 'article-review',
  title: 'Article review',
  initialStage: 'drafting',
  fields: [
    defineField({
      type: 'subject',
      name: 'subject',
      initialValue: {type: 'input'},
      required: true,
    }),
  ],
  stages: [
    defineStage({
      name: 'drafting',
      transitions: [defineTransition({name: 'submit', to: 'review', when: 'true'})],
    }),
    defineStage({name: 'review'}),
  ],
})

The definition is the complete authored contract. Deployment validates cross-field invariants, expands authoring conveniences, and produces the stored form used by the engine.

Deployments are immutable versions

Deploying validates the definition, expands authoring conveniences into stored primitives, and stores a content-addressed version. Deploying identical content is a no-op; changing the definition creates the next version.

An instance pins the definition version and a frozen definition snapshot when it starts. Redeploying therefore changes future runs without silently changing work already in flight.

Start an instance

The optional start block controls discovery and requirements. See the Start block reference for its complete shape.

Starting an instance creates one durable run from a deployed definition. Pass the definition name and any declared workflow inputs to engine.startInstance:

import {gdrFromResource} from '@sanity/workflow-engine'

const subject = gdrFromResource(
  {type: 'dataset', id: 'yourprojectid.production'},
  'article-123',
)

const {instance} = await engine.startInstance({
  definition: 'article-review',
  initialFields: [
    {
      type: 'subject',
      name: 'subject',
      value: {id: subject, type: 'article'},
    },
  ],
})

This supplies the subject input declared in the definition above. See Fields for input and subject declarations, and Conditions for controlling when a workflow may start.

Initial fields are a strict contract

The engine rejects an initial field when:

  • Its name is not declared at workflow scope.
  • Its declaration is not input-sourced.
  • Its type does not match the declaration.
  • The same field appears more than once.

evaluateStart returns allowed: false with the invalid fields. No instance is written.

What an instance stores

An instance is an engine-owned sanity.workflow.instance document. It records the pinned definition, current stage, resolved fields, stage-visit history, effects, child workflows, audit history, and lifecycle timestamps for one run.

To update an instance, use the engine rather than ordinary content patches.

Reference

Workflow definition

This is the top-level object passed to defineWorkflow(...). The engine compiles and deploys it as the versioned definition that instances reference.

Definition properties

The top-level properties accepted by defineWorkflow(...).

  • name

    string

    Stable identity used in deployed document IDs and subworkflow references.

  • Presentation metadata; description is optional.

  • The stage entered when an instance starts.

  • stages

    Stage[]

    One or more stage declarations.

  • fields

    FieldEntry[]

    Optional workflow-scope fields that live for the instance lifetime.

  • groups

    Group[]

    Optional presentation groups that fields, activities, and actions may join.

  • predicates

    Record<string, Condition>

  • roleAliases

    Record<string, string[]>

    Deployment-specific equivalences for advisory role checks.

  • lifecycle

    standalone | child

    Child definitions are intended to be spawned by a parent.

  • start

    AuthoringStartBlock

    Optional configuration for standalone-start discovery and requirements.

Named predicate context

Named predicates use the GROQ variables defined by the Conditions reference. This table shows which are available at this site.

  • Unavailable

    $actor, $assigned, $can, $params, $row

    Named predicates cannot reference other named predicates. See Conditions.

  • Available

    $self, $fields, $parent, $ancestors, $stage, $now, $context, $effects, $effectStatus, $activities, $allActivitiesDone, $anyActivityFailed, $subworkflows

    Always-bound instance variables.

Start block

The optional start block configures discovery and fresh standalone starts. See Start filters and requirements for behavior and evaluation context.

start: {
  kind: 'interactive',
  filter: "status == 'draft'",
  requirements: [
    {
      type: 'singleSubject',
      name: 'one-open-review',
      title: 'Review already in progress',
    },
    {
      type: 'groq',
      name: 'article-ready',
      title: 'Article is not ready',
      query: '$fields.ready == true',
    },
  ],
}
  • kind

    'interactive' | 'autonomous' | undefined

    Classifies who normally initiates the workflow. Defaults to interactive; it does not gate startInstance.

  • filter

    string | undefined

    GROQ visibility predicate used during discovery. It does not gate startInstance.

  • requirements

    StartRequirement[] | undefined

    Ordered requirements enforced before a fresh standalone start. Every requirement must pass.

GROQ start requirement

Use a GROQ requirement when readiness depends on supplied workflow inputs.

  • type

    'groq'

    Selects GROQ evaluation.

  • name

    string

    Unique name within the start requirements array. Verdicts identify the requirement by this name.

  • title

    string | undefined

    Optional editor-facing label.

  • description

    string | undefined

    Optional editor-facing explanation.

  • query

    string

    GROQ condition evaluated against the start input context.

Single-subject start requirement

Use a single-subject requirement to permit at most one unfinished run of this definition for the same subject. It requires one first-class input-sourced subject field; see Allow one active workflow per subject.

  • type

    'singleSubject'

    Selects definition-scoped subject exclusivity.

  • name

    string

    Unique name within the start requirements array. Verdicts identify the requirement by this name.

  • title

    string | undefined

    Optional editor-facing label.

  • description

    string | undefined

    Optional editor-facing explanation.

Workflow instance

A workflow instance is the engine-owned sanity.workflow.instance document returned by startInstance and subsequent engine verbs. Read it through the engine and change it only through engine verbs.

Identity and definition pin

These fields identify the run and preserve the definition it started with.

  • _id

    string

    Sanity document ID for the workflow instance.

  • _type

    sanity.workflow.instance

    Document type for a workflow instance.

  • tag

    string

    Engine environment partition that scopes instance reads.

  • workflowResource

    WorkflowResource

    Sanity resource where the instance is stored.

  • Name of the deployed workflow definition.

  • Definition version selected when the instance started.

  • pinnedContentHash

    string | undefined

    Content hash of the pinned definition when available.

  • Frozen JSON snapshot of the definition used at start.

State and hierarchy

These fields hold the instance’s resolved state and its place in a workflow hierarchy.

  • fields

    ResolvedFieldEntry[]

    Workflow-scope field values.

  • context

    ContextEntry[]

    Start context supplied once and read through $context.

  • ancestors

    GlobalDocumentReference[]

    Ancestor workflow instances, ordered root-first.

  • perspective

    WorkflowPerspective | undefined

    Perspective used for content reads.

  • currentStage

    StageName

    Name of the current stage.

  • stages

    StageEntry[]

    Stage visits in entry order; the current visit has no exitedAt.

  • subworkflows

    SubworkflowEntry[] | undefined

    Child workflows spawned by this instance.

Effects, history, and idempotency

These fields track queued work and committed engine activity.

  • pendingEffects

    PendingEffect[]

    Effects waiting to be claimed or completed.

  • effectHistory

    EffectHistoryEntry[]

    Completed effect results.

  • history

    HistoryEntry[]

    Committed engine events for the instance.

  • processedRequests

    ProcessedRequest[] | undefined

    Unexpired idempotency keys for committed operations.

Lifecycle and model compatibility

These fields record lifecycle timestamps and the persisted data-model contract.

  • startedAt

    string

    ISO-8601 timestamp set when the instance starts.

  • ISO-8601 timestamp of the latest engine commit.

  • completedAt

    string | undefined

    Set when the instance reaches any terminal state.

  • abortedAt

    string | undefined

    Set with completedAt when the instance is aborted.

  • modelVersion

    number | undefined

    Persisted data-model version written on the document.

  • minReaderModel

    number | undefined

    Oldest engine data model allowed to read the document.

Visiting agent?

Was this page helpful?