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
This tutorial walks you through creating the simplest possible Motia application: a “Hello World” API that accepts HTTP requests and processes them in the background.
What you’ll learn:
Creating HTTP-triggered Steps
Enqueuing background jobs
Using queue-triggered Steps
Working with state storage
Structured logging
Prerequisites
Before starting, make sure you have:
Node.js version 19 or higher
Bun installed (or npm/pnpm)
Project Setup
Create a new project
Create a new directory and initialize your project: mkdir hello-world-app
cd hello-world-app
npm init -y
Install dependencies
npm install motia zod
npm install -D typescript @types/node
Update your package.json to include: {
"type" : "module" ,
"scripts" : {
"dev" : "iii" ,
"build" : "motia build" ,
"start" : "bun run --enable-source-maps dist/index-production.js"
}
}
Building the Application
Step 1: Create the HTTP API Step
Create steps/hello-api.step.ts:
import type { Handlers , StepConfig } from 'motia'
import { z } from 'zod'
export const config = {
name: 'HelloAPI' ,
description: 'Receives hello request and enqueues event for processing' ,
triggers: [
{
type: 'http' ,
path: '/hello' ,
method: 'GET' ,
responseSchema: {
200 : z . object ({
message: z . string (),
status: z . string (),
appName: z . string (),
}),
},
},
],
enqueues: [ 'process-greeting' ],
flows: [ 'hello-world-flow' ],
} as const satisfies StepConfig
export const handler : Handlers < typeof config > = async ( _ , { enqueue , logger }) => {
const appName = 'Hello World App'
const timestamp = new Date (). toISOString ()
logger . info ( 'Hello API endpoint called' , { appName , timestamp })
await enqueue ({
topic: 'process-greeting' ,
data: {
timestamp ,
appName ,
greetingPrefix: process . env . GREETING_PREFIX || 'Hello' ,
requestId: Math . random (). toString ( 36 ). substring ( 7 ),
},
})
return {
status: 200 ,
body: {
message: 'Hello request received! Check logs for processing.' ,
status: 'processing' ,
appName ,
},
}
}
Key concepts:
Triggers : The http trigger defines a GET endpoint at /hello
Response schema : Zod schema validates the response structure
Enqueues : Declares this Step can enqueue messages to the process-greeting topic
Flows : Groups related Steps together for organization
Step 2: Create the Background Processing Step
Create steps/process-greeting.step.ts:
steps/process-greeting.step.ts
import type { Handlers , StepConfig } from 'motia'
import { z } from 'zod'
const inputSchema = z . object ({
timestamp: z . string (),
appName: z . string (),
greetingPrefix: z . string (),
requestId: z . string (),
})
export const config = {
name: 'ProcessGreeting' ,
description: 'Processes greeting in the background' ,
triggers: [
{
type: 'queue' ,
topic: 'process-greeting' ,
input: inputSchema ,
},
],
enqueues: [],
flows: [ 'hello-world-flow' ],
} as const satisfies StepConfig
export const handler : Handlers < typeof config > = async ( input , { logger , state }) => {
const { timestamp , appName , greetingPrefix , requestId } = input
logger . info ( 'Processing greeting' , { requestId , appName })
const greeting = ` ${ greetingPrefix } ${ appName } !`
await state . set ( 'greetings' , requestId , {
greeting ,
processedAt: new Date (). toISOString (),
originalTimestamp: timestamp ,
})
logger . info ( 'Greeting processed successfully' , {
requestId ,
greeting ,
storedInState: true ,
})
}
Key concepts:
Queue trigger : Listens to the process-greeting topic
Input validation : Zod schema validates incoming queue messages
State storage : Persists data using state.set(bucket, key, value)
Structured logging : Includes contextual data with log messages
Running the Application
Start the development server
The server will start and display available endpoints.
Test the API
Open a new terminal and make a request: curl http://localhost:3000/hello
You should see: {
"message" : "Hello request received! Check logs for processing." ,
"status" : "processing" ,
"appName" : "Hello World App"
}
Check the logs
In your terminal running the dev server, you’ll see: [HelloAPI] Hello API endpoint called
[ProcessGreeting] Processing greeting
[ProcessGreeting] Greeting processed successfully
Customization
Add Environment Variables
Create a .env file:
Now requests will use “Welcome” instead of “Hello”.
Retrieve Stored Greetings
Add a new Step to retrieve greetings from state:
steps/get-greeting.step.ts
import type { Handlers , StepConfig } from 'motia'
import { z } from 'zod'
export const config = {
name: 'GetGreeting' ,
description: 'Retrieves a stored greeting' ,
triggers: [
{
type: 'http' ,
path: '/greeting/:requestId' ,
method: 'GET' ,
responseSchema: {
200 : z . object ({
greeting: z . string (),
processedAt: z . string (),
originalTimestamp: z . string (),
}),
404 : z . object ({ error: z . string () }),
},
},
],
enqueues: [],
flows: [ 'hello-world-flow' ],
} as const satisfies StepConfig
export const handler : Handlers < typeof config > = async (
{ request },
{ state , logger }
) => {
const { requestId } = request . pathParams || {}
const greeting = await state . get ( 'greetings' , requestId )
if ( ! greeting ) {
return {
status: 404 ,
body: { error: 'Greeting not found' },
}
}
logger . info ( 'Retrieved greeting' , { requestId })
return {
status: 200 ,
body: greeting ,
}
}
Next Steps
Now that you’ve built your first Motia application, explore more advanced features:
Todo API Build a full CRUD API with validation
Message Queue Learn pub/sub patterns and streams
Scheduled Tasks Run jobs on a schedule with cron
API Reference Explore the full Motia API