Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/MotiaDev/motia/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Steps are the building blocks of Motia applications. They define handlers that respond to various triggers like HTTP requests, queue messages, cron schedules, state changes, and stream events.

Functions

step

Defines a step with its configuration and handler.
function step<TConfig extends StepConfig>(
  config: TConfig,
  handler: Handlers<TConfig>
): StepDefinition<TConfig>

function step<TConfig extends StepConfig>(
  config: TConfig
): StepBuilder<TConfig>
config
TConfig extends StepConfig
required
The step configuration object.
name
string
required
The unique name of the step.
description
string
Optional description of the step’s purpose.
triggers
readonly TriggerConfig[]
required
Array of triggers that activate this step.
enqueues
readonly Enqueue[]
Topics this step can enqueue messages to.
virtualEnqueues
readonly Enqueue[]
Virtual queue topics for type safety without actual queue creation.
virtualSubscribes
readonly string[]
Virtual subscriptions for type safety.
flows
readonly string[]
Flow identifiers this step belongs to.
includeFiles
readonly string[]
Additional files to include with the step.
handler
Handlers<TConfig>
The handler function for processing step execution. Optional when using builder pattern.
return
StepDefinition<TConfig> | StepBuilder<TConfig>
Returns a step definition if handler is provided, otherwise returns a builder object.

Usage Examples

Direct Handler

import { step, http } from 'motia'
import { z } from 'zod'

export default step(
  {
    name: 'greet-user',
    triggers: [http('POST', '/greet', {
      bodySchema: z.object({ name: z.string() })
    })]
  },
  async (input, ctx) => {
    const { name } = ctx.getData()
    return {
      status: 200,
      body: { message: `Hello, ${name}!` }
    }
  }
)

Builder Pattern

import { step, queue } from 'motia'
import { z } from 'zod'

export default step({
  name: 'process-order',
  triggers: [queue('orders', {
    input: z.object({ orderId: z.string() })
  })]
}).handle(async (input, ctx) => {
  const order = ctx.getData()
  await processOrder(order.orderId)
})

Types

StepConfig

type StepConfig = {
  name: string
  description?: string
  triggers: readonly TriggerConfig[]
  enqueues?: readonly Enqueue[]
  virtualEnqueues?: readonly Enqueue[]
  virtualSubscribes?: readonly string[]
  flows?: readonly string[]
  includeFiles?: readonly string[]
}

StepDefinition

type StepDefinition<TConfig extends StepConfig> = {
  config: TConfig
  handler: Handlers<TConfig>
}

StepBuilder

type StepBuilder<TConfig extends StepConfig> = {
  config: TConfig
  handle: (handler: Handlers<TConfig>) => StepDefinition<TConfig>
}

Handlers

type Handlers<TConfig extends StepConfig> = (
  input: InferHandlerInput<TConfig>,
  ctx: FlowContext<InferEnqueues<TConfig>, InferHandlerInput<TConfig>>
) => Promise<ApiResponse | void>
The handler function receives:
  • input: The input data based on the trigger type
  • ctx: The flow context with utilities for state, logging, enqueuing, etc.

StepHandler

type StepHandler<TInput = any, TEnqueueData = never> = (
  input: TriggerInput<TInput>,
  ctx: FlowContext<TEnqueueData, TriggerInput<TInput>>
) => Promise<ApiResponse | void>

Enqueue

type Enqueue = string | { 
  topic: string
  label?: string
  conditional?: boolean 
}

Build docs developers (and LLMs) love