Skip to main content
Get your first Motia project up and running in under 5 minutes. This guide will walk you through installation, project creation, and running your first API endpoint.

Prerequisites

Before you begin, ensure you have:
  • Node.js 18+ for TypeScript/JavaScript Steps
  • Python 3.10+ (optional) for Python Steps
  • curl or Homebrew for CLI installation

Step 1: Install the Motia CLI

brew tap MotiaDev/tap
brew install motia-cli
The Motia CLI will automatically install the iii engine when you create your first project.

Verify Installation

motia-cli --version

Step 2: Create Your First Project

Create a new Motia project using the CLI:
motia-cli create my-app
The CLI will prompt you to:
  1. Choose a language (TypeScript, JavaScript, or Python)
  2. Select a template (basic, todo app, or custom)
  3. Auto-install the iii engine if not already present
The CLI generates an iii-config.yaml file that configures the runtime environment.

Step 3: Navigate to Your Project

cd my-app
Your project structure looks like this:
my-app/
├── steps/                 # Your Step files live here
│   └── hello-api.step.ts  # Example Step
├── iii-config.yaml        # iii engine configuration
├── package.json           # Node dependencies (for JS/TS)
└── .env                   # Environment variables

Step 4: Start the iii Engine

Start the iii engine to power your Motia app:
iii -c iii-config.yaml
You should see output indicating:
  • ✅ HTTP server running on port 3111
  • ✅ WebSocket server on port 49134
  • ✅ Stream API on port 3112
  • ✅ Metrics available on port 9464

iii Console Dashboard

Access the iii Console at http://localhost:3112 to view your Steps, monitor requests, and inspect logs in real-time.

Step 5: Test Your First Step

Let’s examine the generated hello-api.step.ts (or .js/.py depending on your choice):
// steps/hello-api.step.ts
import type { Handlers, StepConfig } from 'motia'
import { z } from 'zod'

export const config = {
  name: 'HelloAPI',
  description: 'A simple hello world endpoint',
  triggers: [
    {
      type: 'http',
      path: '/hello',
      method: 'GET',
      responseSchema: {
        200: z.object({
          message: z.string(),
          timestamp: z.string(),
        }),
      },
    },
  ],
} as const satisfies StepConfig

export const handler: Handlers<typeof config> = async (_, { logger }) => {
  logger.info('Hello endpoint called')
  
  return {
    status: 200,
    body: {
      message: 'Hello from Motia!',
      timestamp: new Date().toISOString(),
    },
  }
}

Make a Request

Test your endpoint with curl:
curl http://localhost:3111/hello
Expected response:
{
  "message": "Hello from Motia!",
  "timestamp": "2026-03-04T10:30:00.000Z"
}

Success!

You’ve just created and tested your first Motia Step! The HTTP trigger automatically mapped your handler to /hello.

What You Have Now

With this simple setup, you already have:

REST APIs

HTTP endpoints with automatic validation

Type Safety

Zod schema validation and TypeScript support

Logging

Structured logging out of the box

Zero Config

Auto-discovery means no manual wiring

Add a Background Job

Let’s extend this with a queue-based background job. Create a new file:
// steps/process-hello.step.ts
import type { Handlers, StepConfig } from 'motia'
import { z } from 'zod'

const inputSchema = z.object({
  message: z.string(),
  timestamp: z.string(),
})

export const config = {
  name: 'ProcessHello',
  description: 'Background processor for hello messages',
  triggers: [
    {
      type: 'queue',
      topic: 'hello.received',
      input: inputSchema,
    },
  ],
} as const satisfies StepConfig

export const handler: Handlers<typeof config> = async (input, { logger }) => {
  logger.info('Processing hello message', input)
  // Do background work here
  await new Promise(resolve => setTimeout(resolve, 1000))
  logger.info('Processing complete')
}
Now update your hello-api Step to enqueue messages:
export const config = {
  name: 'HelloAPI',
  triggers: [{ type: 'http', path: '/hello', method: 'GET' }],
  enqueues: ['hello.received'], // Add this line
} as const satisfies StepConfig

export const handler: Handlers<typeof config> = async (_, { logger, enqueue }) => {
  const data = {
    message: 'Hello from Motia!',
    timestamp: new Date().toISOString(),
  }
  
  // Enqueue for background processing
  await enqueue({
    topic: 'hello.received',
    data,
  })
  
  return { status: 200, body: data }
}
After adding new Steps, the iii engine automatically detects them. Watch your console for “Processing hello message” logs.

Next Steps

You’ve now built an API endpoint with background job processing! Here’s what to explore next:
1

Learn Step Anatomy

Understand the config and handler pattern in depthGo to Your First Step →
2

Explore Triggers

Add cron jobs, state listeners, and stream subscriptionsView Trigger Types →
3

Add State Management

Store and react to state changesLearn about State →
4

Build Real-time Features

Use streams for real-time data synchronizationExplore Streams →

Troubleshooting

Ensure Redis is running if you’re using queue or stream features:
docker run -d -p 6379:6379 redis:latest
Or disable them in iii-config.yaml if not needed.
Steps must:
  • Be in the steps/ directory
  • Have .step.ts, .step.js, or _step.py suffix
  • Export both config and handler
Change ports in iii-config.yaml:
modules:
  - class: modules::api::RestApiModule
    config:
      port: 3111  # Change this

Resources

Examples

20+ production examples

Discord

Get help from the community

API Reference

Complete API documentation

Build docs developers (and LLMs) love