Motia Icon
Development Guide

Flows

Group multiple steps to be visible in diagrams in the iii development console

Flows group related Steps together so you can see them as connected workflows in the iii development console. Add flows to your Step config - it's an array of flow names.

How It Works

Add flows to any Step config. Each string is a flow name.

import { type Handlers, type StepConfig } from 'motia'
 
export const config = {
  name: 'CreateResource',
  description: 'Create a new resource',
  triggers: [
    { type: 'api', path: '/resources', method: 'POST' },
  ],
  enqueues: [],
  flows: ['resource-management'],
} as const satisfies StepConfig

Example

Two Steps working together in one flow.

API and Queue Steps connected in a flow

API Step - Create resource:

src/create-resource.step.ts
import { type Handlers, type StepConfig } from 'motia'
 
export const config = {
  name: 'CreateResource',
  description: 'Create a new resource and trigger email',
  triggers: [
    { type: 'api', path: '/resources', method: 'POST' },
  ],
  enqueues: ['send-email'],
  flows: ['resource-management'],
} as const satisfies StepConfig
 
export const handler: Handlers<typeof config> = async (req, { enqueue, logger }) => {
  logger.info('Creating resource', { title: req.body.title })
 
  await enqueue({
    topic: 'send-email',
    data: { email: req.body.email }
  })
 
  return { status: 201, body: { id: '123' } }
}

Queue Step - Send email:

src/send-email.step.ts
import { type Handlers, type StepConfig } from 'motia'
 
export const config = {
  name: 'SendEmail',
  description: 'Send an email notification',
  triggers: [
    { type: 'queue', topic: 'send-email' },
  ],
  enqueues: [],
  flows: ['resource-management'],
} as const satisfies StepConfig
 
export const handler: Handlers<typeof config> = async (input, { logger }) => {
  logger.info('Sending email', { email: input.email })
}

Both Steps have flows: ['resource-management']. In the iii development console, they appear connected.


Multiple Flows

A Step can belong to multiple flows.

import { type Handlers, type StepConfig } from 'motia'
 
export const config = {
  name: 'SendEmail',
  description: 'Send an email notification',
  triggers: [
    { type: 'queue', topic: 'send-email' },
  ],
  enqueues: [],
  flows: ['resource-management', 'user-onboarding'],
} as const satisfies StepConfig

This Step appears in both flows in the iii development console.

Steps Without Flows

Steps work fine without flows.

import { type Handlers, type StepConfig } from 'motia'
 
export const config = {
  name: 'HealthCheck',
  description: 'Health check endpoint',
  triggers: [
    { type: 'api', path: '/health', method: 'GET' },
  ],
  enqueues: [],
} as const satisfies StepConfig

Flows in the iii Development Console

The iii development console has a dropdown to filter by flow. Select a flow to see only the Steps that belong to it.

Flow dropdown in iii development console

Virtual Connections

Use virtualEnqueues and virtualSubscribes for visualization without actual events:

import { type StepConfig } from 'motia'
 
export const config = {
  name: 'CreateResource',
  description: 'Create a resource requiring approval',
  triggers: [
    { type: 'api', path: '/resources', method: 'POST' },
  ],
  enqueues: [],
  virtualEnqueues: ['approval.required'],
  flows: ['resource-management'],
} as const satisfies StepConfig

Virtual connections show as gray/dashed lines in the iii development console. Real connections (from enqueues and queue triggers) show as dark solid lines.

Virtual connections with labels in iii development console

Labels

Add labels to connections in the iii development console:

import { type StepConfig } from 'motia'
 
export const config = {
  name: 'SendEmail',
  description: 'Send email notifications',
  triggers: [
    { type: 'api', path: '/send', method: 'POST' },
  ],
  enqueues: [],
  virtualEnqueues: [
    { topic: 'email-sent', label: 'Email delivered' },
    { topic: 'email-failed', label: 'Failed to send', conditional: true },
  ],
  flows: ['notifications'],
} as const satisfies StepConfig

NOOP Steps

NOOP Steps don't run code. They're for visualization only:

import { NoopConfig } from 'motia'
 
export const config: NoopConfig = {
  type: 'noop',
  name: 'ApprovalGate',
  virtualEnqueues: ['approved'],
  virtualSubscribes: ['approval.required'],
  flows: ['resource-management']
}

Learn about customizing how flows look


On this page