Motia Icon
Development Guide

Project Structure

Learn about Motia's project structure, file organization, and automatic step discovery system for building scalable workflow applications.

Project Structure

Understanding how to organize your Motia project is crucial for building maintainable and scalable workflow applications. This guide covers the directory structure, file naming conventions, and Motia's automatic step discovery system.

Basic Project Structure

Here's what a typical Motia project looks like:

01-api-gateway.step.ts
02-data-processor_step.py
03-send-notification.step.js
send-notification.tsx
package.json
requirements.txt
tsconfig.json
types.d.ts
config.yaml

File Descriptions

FilePurposeTypeAuto-Generated
01-api-gateway.step.tsTypeScript API endpointUser Code-
02-data-processor_step.pyPython data processingUser Code-
03-send-notification.step.jsJavaScript automationUser Code-
send-notification.tsxOptional UI override componentUser Code-
package.jsonNode.js dependencies (if using JS/TS)Config-
requirements.txtPython dependencies (if using Python)Config-
tsconfig.jsonTypeScript config (if using TypeScript)Config-
types.d.tsType definitions for your projectGeneratedBy TypeScript
config.yamliii configurationConfig-

Flexible Step Discovery

Motia automatically discovers and registers steps from your src/ directory. You're not required to use a specific directory structure - organize your code however makes sense for your project!

Directory flexibility and organization
  • Recursive discovery - nest steps in subfolders as deeply as you need (e.g., src/api/v1/users.step.ts, src/services/email/send_step.py)
  • Organize freely - structure by feature, language, team, or any pattern that works for you

Automatic Step Discovery

Key Concept: Automatic Discovery

Motia automatically discovers and registers any file that follows the .step. naming pattern as a workflow step, regardless of where it's located in your src/ directory. No manual registration required - just create a file with the right naming pattern and Motia will find it.

Discovery Rules

Motia scans your project and automatically registers files as steps based on these simple rules:

  1. File must contain .step. or _step. in the filename (e.g., my-task.step.ts, my_task_step.py)
  2. File must export a config object defining the step configuration
  3. File must export a handler function containing the step logic
  4. File extension determines the runtime (.ts = TypeScript, .py = Python, .js = JavaScript)

When you start the dev server, Motia will:

  • Recursively scan the src/ directory
  • Find all files matching *.step.* or *_step.* patterns in the src/ directory
  • Parse their config exports to understand step types and connections
  • Register them in the workflow engine

No directory requirement - Steps are discoverable from anywhere within src/, regardless of folder depth or organization pattern.

File Naming Convention

Motia uses this specific pattern for automatic step discovery:

[prefix-]descriptive-name.step.[extension]

The .step. part in the filename is required - this is how Motia identifies which files are workflow steps during automatic discovery.

Supported Languages & Extensions

LanguageExtensionExample Step FileRuntime
TypeScript.tsuser-registration.step.tsNode.js with TypeScript
Python.pydata-analysis_step.pyPython interpreter
JavaScript.jssend-notification.step.jsNode.js

Naming Examples by Step Type

Step TypeTypeScriptPythonJavaScript
API Endpoint01-auth-api.step.ts01-auth-api_step.py or auth_api_step.py01-auth-api.step.js
Queue Handlerprocess-order.step.tsprocess-order_step.py or process_order_step.pyprocess-order.step.js
Cron Jobdaily-report.step.tsdaily-report_step.py or daily_report_step.pydaily-report.step.js
Data Processingtransform-data.step.tsml-analysis_step.py or ml_analysis_step.pydata-cleanup.step.js

Step Organization Patterns

All examples below use src/ as the root directory.

Sequential Flow Organization

Perfect for linear workflows where order matters:

01-api-start.step.ts
02-validate-data_step.py
03-process-payment.step.js
04-send-confirmation.step.ts
05-cleanup_step.py
StepLanguagePurpose
01-api-start.step.tsTypeScriptAPI endpoint
02-validate-data_step.pyPythonData validation
03-process-payment.step.jsJavaScriptPayment processing
04-send-confirmation.step.tsTypeScriptEmail service
05-cleanup_step.pyPythonCleanup tasks

Language-Specific Configuration

TypeScript/JavaScript Projects

For Node.js-based steps, you'll need:

package.json
{
  "name": "my-motia-app",
  "version": "1.0.0",
  "scripts": {
    "dev": "iii",
    "build": "motia build",
    "start": "motia start"
  },
  "dependencies": {
    "motia": "^0.5.12-beta.121",
    "zod": "^3.24.4"
  },
  "devDependencies": {
    "typescript": "^5.7.3",
    "@types/node": "^20.0.0"
  }
}
tsconfig.json (for TypeScript)
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "Node",
    "esModuleInterop": true,
    "strict": true,
    "skipLibCheck": true
  },
  "include": ["**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules", "dist"]
}

Python Projects

For Python-based steps:

requirements.txt
# Core Motia dependency (install via pip install motia-python)
motia>=0.5.12

# Common dependencies
requests>=2.28.0
pydantic>=1.10.0

# Data processing (if needed)
pandas>=1.5.0
numpy>=1.21.0

Step Discovery Examples

Let's see how Motia discovers different step types:

Example 1: TypeScript API Step

src/user-api.step.ts
import { type Handlers, type StepConfig } from 'motia'
 
export const config = {
  name: 'user-api',
  description: 'Fetch users and enqueue event',
  triggers: [
    { type: 'api', path: '/users', method: 'GET' },
  ],
  enqueues: ['users.fetched'],
  flows: ['user-management'],
} as const satisfies StepConfig
 
export const handler: Handlers<typeof config> = async (req, { enqueue }) => {
  await enqueue({
    topic: 'users.fetched',
    data: { users: [] }
  })
 
  return {
    status: 200,
    body: { message: 'Users retrieved' }
  }
}

Example 2: Python Queue Step

src/data-processor_step.py
config = {
    "name": "data-processor",
    "description": "Process incoming data with Python",
    "triggers": [
        {"type": "queue", "topic": "users.fetched"}
    ],
    "enqueues": ["data.processed"],
    "flows": ["user-management"]
}
 
async def handler(input_data, ctx):
    processed_data = {
        "original": input_data,
        "processed_at": ctx.utils.dates.now().isoformat(),
        "count": len(input_data.get("users", []))
    }
 
    await ctx.enqueue({
        "topic": "data.processed",
        "data": processed_data
    })

Example 3: JavaScript Automation Step

src/send-notifications.step.js
export const config = {
  name: 'send-notifications',
  description: 'Send notifications via multiple channels',
  triggers: [
    { type: 'queue', topic: 'data.processed' },
  ],
  enqueues: ['notifications.sent'],
  flows: ['user-management']
}
 
export const handler = async (input, { enqueue, logger }) => {
  logger.info('Sending notifications', { data: input })
 
  const results = await Promise.all([
    sendEmail(input),
    sendSMS(input),
    sendPush(input)
  ])
 
  await enqueue({
    topic: 'notifications.sent',
    data: {
      results,
      sent_at: new Date().toISOString()
    }
  })
}
 
async function sendEmail(data) { /* implementation */ }
async function sendSMS(data) { /* implementation */ }
async function sendPush(data) { /* implementation */ }

Auto-Generated Files

Some files in your Motia project are automatically generated:

  • types.d.ts - TypeScript generates this for type definitions

Discovery Troubleshooting

If Motia isn't discovering your steps:

Common Issues

Missing .step. (or _step for Python) in filename

Won't be discovered:

user-handler.ts
data-processor.py
webhook.js

Will be discovered:

user-handler.step.ts
data-processor_step.py
webhook.step.js

Discovery Verification

Check if your steps are discovered:

npm run dev
 
# Look for step creation in your console:
# [CREATED] Step (Cron) src/petstore/state-audit-cron.step.ts created
# [CREATED] Step (Queue) src/petstore/process-food-order.step.ts created
# [CREATED] Step (Queue) src/petstore/notification.step.ts created
# [CREATED] Step (API) src/petstore/api.step.ts created

Next Steps

Now that you understand how Motia discovers and organizes steps: