Motia Icon
Workbench

NOOP Steps

NOOP (No Operation) steps are a powerful feature in Motia that serve multiple purposes:

  1. Modeling external processes, webhooks and integrations
  2. Representing human-in-the-loop activities
  3. Creating custom visualizations in the workbench
  4. Testing flows during development
Currently, NOOP steps are only supported in TS or JS

File Structure

NOOP steps require two files with the same base name:

  • stepName.step.ts - Contains the step configuration
  • stepName.step.tsx - Contains the UI component (optional)

Step Configuration File (.ts)

// myStep.step.ts
import { NoopConfig } from 'motia'
 
export const config: NoopConfig = {
  type: 'noop',
  name: 'My NOOP Step',
  description: 'Description of what this step simulates',
  virtualEmits: ['event.one', 'event.two'],
  virtualSubscribes: [], // Required even if empty
  flows: ['my-flow'],
}

UI Component File (.tsx)

// myStep.step.tsx
import React from 'react'
import { BaseHandle, Position } from 'motia/workbench'
 
export default function MyStep() {
  return (
    <div className="p-4 bg-gray-800 rounded-lg border border-gray-600 text-white">
      <div className="text-sm font-medium">My Step UI</div>
      {/* Your custom UI elements */}
      <BaseHandle type="source" position={Position.Bottom} />
    </div>
  )
}

Example: Webhook Testing

Here's a complete example of a NOOP step that simulates webhook events:

// test-webhook.step.ts
import { NoopConfig } from 'motia'
 
export const config: NoopConfig = {
  type: 'noop',
  name: 'Webhook Simulator',
  description: 'Simulates incoming webhook events',
  virtualEmits: ['webhook.received'],
  virtualSubscribes: [],
  flows: ['webhook-flow'],
}
// test-webhook.step.tsx
import React from 'react'
import { BaseHandle, Position } from 'motia/workbench'
 
export default function WebhookSimulator() {
  return (
    <div className="p-4 bg-gray-800 rounded-lg border border-gray-600 text-white">
      <div className="text-sm font-medium mb-2">Webhook Simulator</div>
      <button 
        onClick={() => {
          fetch('/api/webhook', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ event: 'test' }),
          })
        }}
        className="px-3 py-1 bg-blue-600 rounded text-sm"
      >
        Trigger Webhook
      </button>
      <BaseHandle type="source" position={Position.Bottom} />
    </div>
  )
}

Representing External Processes

NOOP steps represent parts of your workflow that happen outside your system. Common examples include:

Webhook Callbacks

export const config: NoopConfig = {
  type: 'noop',
  name: 'Wait for Stripe Webhook',
  description: 'Waits for payment confirmation',
  virtualSubscribes: ['payment.initiated'],
  virtualEmits: ['/api/stripe/webhook'],
  flows: ['payment'],
}

Human Approvals

export const config: NoopConfig = {
  type: 'noop',
  name: 'Manager Review',
  description: 'Manager reviews request',
  virtualSubscribes: ['approval.requested'],
  virtualEmits: ['/api/approvals/submit'],
  flows: ['approval'],
}

External System Integration

  export const config: NoopConfig = {
    type: 'noop',
    name: 'GitHub Webhook',
    description: 'Waiting for repository events',
    virtualSubscribes: ['repository.watched'],
    virtualEmits: ['/api/github/webhook'],
    flows: ['repo-automation'],
  }

Physical Processes

export const config: NoopConfig = {
  type: 'noop',
  name: 'Order Fulfillment',
  description: 'Warehouse processes order',
  virtualSubscribes: ['order.placed'],
  virtualEmits: ['/api/warehouse/status'],
  flows: ['fulfillment'],
}

Visualization in Workbench

NOOP steps are visually represented in the Motia Workbench with the following characteristics:

  • Distinct node representation with clear input/output handles
  • Visual indicators for virtual event connections
  • Status indicators for waiting states
  • Clear visualization of external system dependencies

Custom UI

You can enhance your NOOP steps with custom React components for better visualization:

// customNode.step.tsx
import React from 'react'
import { BaseHandle, EventNodeProps, Position } from 'motia/workbench'
 
export default (_: EventNodeProps) => {
  return (
    <div className="p-3 px-6 flex flex-col max-w-[300px] bg-blue-500 border-white rounded-full text-white border border-solid text-center text-sm">
      <div>Custom Processing</div>
      <BaseHandle type="target" position={Position.Top} />
      <BaseHandle type="source" position={Position.Bottom} />
    </div>
  )
}
 
// customNode.step.ts
export const config: NoopConfig = {
  type: 'noop',
  name: 'Custom Process',
  virtualEmits: ['/api/process/complete'],
  virtualSubscribes: ['process.start'],
  flows: ['custom-flow']
}

Best Practices

CategoryGuidelines
File Organization• Keep configuration and UI code in separate files
• Use .step.ts for configuration
• Use .step.tsx for UI components
UI Components• Use functional React components
• Include proper TypeScript types
• Follow Tailwind's utility classes
• Keep components minimal and focused
• Design clear visual connection points
• Always include BaseHandle components for flow connections
Configuration• Always include virtualSubscribes (even if empty)
• Use descriptive names for virtual events
• Include clear descriptions
• Use descriptive, action-oriented names
External Process Modeling• Document expected timeframes and SLAs
• Define all possible outcomes and edge cases
• Use exact API route matching
Testing• Create isolated test flows
• Use realistic test data
• Handle errors gracefully
• Implement clear status indicators
• Label test steps explicitly
• Provide visual feedback for actions

Component Reference

Core Imports

ImportPurpose
BaseHandleA React component that renders connection points for nodes in the workflow. Used to define where edges (connections) can start or end on a node.
EventNodeProps(TypeScript only) Interface defining the properties passed to node components, including node data, selected state, and connection information.
Position(TypeScript only) Enum that specifies the possible positions for handles on a node (Top, Right, Bottom, Left). Used to control where connection points appear.

Handle Placement

Handle TypePosition
Input HandlesPosition.Top
Output HandlesPosition.Bottom
Flow DirectionTop to bottom

Styling Guidelines

CategoryGuidelines
ColorsUse semantic colors to indicate state (success, error, pending)
States• Implement clear visual indicators for active/inactive states
• Use subtle animations for state transitions
Design System• Follow your project's design tokens
• Maintain consistent spacing and padding
• Use standard border radiuses
• Ensure high contrast for readability
• Use consistent font sizes (14px-16px)
Need help? See our Community Resources for questions, examples, and discussions.