Overview
Steps are the fundamental building blocks of Motia applications. Each step is a self-contained unit of work that responds to triggers and can enqueue events for other steps. Steps are defined by two key components: a config and a handler.Anatomy of a Step
Every step file (.step.ts or .step.py) exports two main elements:
Config
The config defines metadata and behavior:- name: Unique identifier for the step
- description: Human-readable description
- triggers: Array of trigger configurations (HTTP, queue, cron, state, stream)
- enqueues: Topics this step can publish to
- flows: Flow names this step belongs to
- infrastructure: Resource limits (RAM, CPU, timeout)
Handler
The handler is an async function that processes inputs and returns responses. It receives:- input: The trigger payload (varies by trigger type)
- ctx: Flow context with utilities for enqueuing, logging, state management, and streams
Basic Example
Here’s a simple step that receives HTTP requests and enqueues events:Step Discovery
Motia automatically discovers steps in your project:- TypeScript/JavaScript: Files matching
**/*.step.{ts,js} - Python: Files matching
**/*.step.py
node_modules/, dist/, __pycache__/
Each step is assigned a unique ID using UUID v5 based on its file path:
motia-js/packages/motia/src/new/build/loader.ts:30
Working with Multiple Triggers
Steps can respond to multiple trigger types. Usectx.match() to handle each trigger differently:
motia-js/playground/steps/multi-trigger-example.step.ts
Schema Validation
Motia supports both Zod and JSON Schema for input validation:Infrastructure Configuration
Configure resource limits per step:motia-js/packages/motia/src/types.ts:147-163
Type Safety
Motia provides end-to-end type safety:Best Practices
Keep steps focused
Keep steps focused
Each step should have a single responsibility. Break complex workflows into multiple steps connected by events.
Use descriptive names
Use descriptive names
Step names should clearly indicate what they do:
CreateTodo, ProcessOrder, SendNotification.Leverage type safety
Leverage type safety
Use
as const satisfies StepConfig to ensure config correctness and get proper type inference in handlers.Handle errors gracefully
Handle errors gracefully
Return appropriate HTTP status codes for API triggers and use try-catch for async operations.
Use virtual enqueues for flexibility
Use virtual enqueues for flexibility
Use
virtualEnqueues when a step conditionally enqueues events, allowing the flow graph to remain accurate.Next Steps
Triggers
Learn about the 5 trigger types
Context
Explore the Flow Context API
State Management
Work with persistent state
Workflows
Organize steps into workflows