Skip to main content

Best Motia Starter Kits & Templates 2026

·StarterPick Team
motiabackendnodejstypescriptai-agentsboilerplate
Share:

Best Motia Starter Kits & Templates 2026

TL;DR

Motia ranked #1 in JavaScript Rising Stars 2025 backend category with 13,800 new GitHub stars — and for good reason. It replaces the standard "Express + BullMQ + node-cron + separate Python AI service" stack with a single unified runtime where everything is a Step. The framework is still early-stage, which means the starter ecosystem is thin but growing fast. This guide covers every production-worthy Motia starter as of March 2026: the official templates, community boilerplates, and how to bootstrap a real SaaS-ready Motia project from scratch.

Key Takeaways

  • Official create-motia-app is the authoritative starting point — zero config, includes Workbench, TypeScript-first
  • Multi-language support from day one: TypeScript and Python Steps coexist — the official template scaffolds both
  • No mature paid SaaS boilerplates yet — Motia is too new (npm shows beta versions); community starters fill the gap
  • Community GitHub templates cover the most common patterns: REST API, event pipeline, AI agent workflow, and multi-tenant SaaS skeleton
  • Self-build is viable in 2026: Motia's DX is good enough that assembling your own starter from core primitives takes hours, not weeks
  • Best use case for Motia starters: apps that combine REST APIs + background jobs + AI agents — if you only need REST, Hono is lighter

What Makes a Good Motia Starter?

Unlike Next.js or SvelteKit starters where you choose between opinionated frameworks, Motia starters serve a different purpose: they scaffold the organizational patterns that the framework itself doesn't enforce. Motia tells you "put Steps in a folder" — it doesn't tell you how to structure a multi-tenant SaaS, where to put shared utilities, or how to wire your database.

A high-quality Motia starter should include:

  1. Typed Step organization — a clear folder convention for API, event, and cron Steps
  2. Shared state patterns — how to namespace keys in the built-in state store
  3. Error handling — compensating events and dead-letter patterns
  4. External persistence — Redis or PostgreSQL for production state (the default state store is in-memory)
  5. Python interop — at least one Python Step demonstrating the AI integration pattern
  6. Observability — Workbench-ready with trace context propagation
  7. Testing — unit tests for Steps in isolation

The Official Starter: create-motia-app

Source: github.com/MotiaDev/motia Cost: Free, MIT Stack: TypeScript + Motia 0.x + Workbench

The official Motia scaffolding CLI is the best starting point for any Motia project in 2026:

npx create-motia-app my-app
cd my-app
npm run dev

This starts the Motia runtime and the Workbench simultaneously. Visit http://localhost:3001 for the visual flow inspector.

What you get

my-app/
├── src/
│   └── steps/
│       ├── hello-api.step.ts        # Example API Step (GET /hello)
│       ├── hello-event.step.ts      # Example Event Step (subscribes to hello.triggered)
│       └── hello-cron.step.ts       # Example Cron Step (every minute)
├── motia.config.ts                  # Framework configuration
├── tsconfig.json
└── package.json

The starter demonstrates all three Step types in under 100 lines of code. This is Motia's strongest onboarding asset — you go from npx to a running, traceable, multi-step workflow in under 2 minutes.

What's missing in the official starter

  • No database integration (state store is in-memory only)
  • No Python Step example
  • No authentication pattern
  • No production deployment configuration (Vercel, Railway, Fly.io)
  • No error handling or retry pattern

The official starter is excellent for learning the Step model. For production, you extend it — or use a community template.


Community Starter: Motia REST API Template

Pattern: REST API with event-driven background processing Best for: APIs that need async processing (webhooks, data pipelines, order processing)

The most common Motia application pattern is a REST API frontend with event-driven background processing behind it. Here's the recommended project structure:

src/steps/
├── api/
│   ├── create-resource.step.ts    # POST /resources
│   ├── get-resource.step.ts       # GET /resources/:id
│   └── list-resources.step.ts     # GET /resources
├── events/
│   ├── process-resource.step.ts   # subscribes: ['resource.created']
│   ├── enrich-resource.step.ts    # subscribes: ['resource.processed']
│   └── notify-user.step.ts        # subscribes: ['resource.enriched']
├── cron/
│   └── cleanup-stale.step.ts      # 0 3 * * * (3am daily)
└── ai/
    └── analyze-resource.step.py   # Python AI Step

Core patterns from this template

State namespacing convention:

// Consistent key patterns for the shared state store
const KEYS = {
  resource: (id: string) => `resource:${id}`,
  resourceList: (userId: string) => `user:${userId}:resources`,
  resourceRisk: (id: string) => `resource:${id}:risk`,
};

Error emission as first-class events:

// src/steps/events/process-resource.step.ts
export default defineStep({
  type: 'event',
  subscribes: ['resource.created'],
  async handler({ data, emit, state }) {
    try {
      const result = await heavyProcessing(data.resourceId);
      await emit('resource.processed', { resourceId: data.resourceId, result });
    } catch (err) {
      // Error as event — downstream Steps can react to failure
      await emit('resource.processing_failed', {
        resourceId: data.resourceId,
        error: err.message,
        retryable: isRetryable(err),
      });
    }
  },
});

Dead letter pattern:

// src/steps/events/handle-processing-failure.step.ts
export default defineStep({
  type: 'event',
  subscribes: ['resource.processing_failed'],
  async handler({ data, state }) {
    const resource = await state.get(KEYS.resource(data.resourceId));

    const failureCount = (resource.failureCount || 0) + 1;
    await state.set(KEYS.resource(data.resourceId), {
      ...resource,
      failureCount,
      lastError: data.error,
      status: failureCount >= 3 ? 'dead_letter' : 'retry_pending',
    });

    // Alert after 3 failures
    if (failureCount >= 3) {
      await emit('alert.send', {
        severity: 'high',
        message: `Resource ${data.resourceId} entered dead letter after 3 failures`,
      });
    }
  },
});

Community Starter: Motia AI Agent Workflow

Pattern: Multi-step AI agent with human-in-the-loop Best for: AI-powered SaaS features (content generation, data analysis, classification pipelines)

This pattern combines TypeScript REST endpoints with Python AI Steps and a feedback loop:

src/steps/
├── api/
│   ├── submit-job.step.ts          # POST /jobs — triggers job.submitted
│   └── get-job-status.step.ts      # GET /jobs/:id — reads state
├── events/
│   ├── prepare-context.step.ts     # subscribes: ['job.submitted']
│   ├── review-ai-output.step.ts    # subscribes: ['job.ai_complete'] — human review gate
│   └── finalize-job.step.ts        # subscribes: ['job.approved']
└── ai/
    ├── run-analysis.step.py        # subscribes: ['job.context_ready']
    └── format-output.step.py       # subscribes: ['job.analyzed']

The Python AI Step pattern

# src/steps/ai/run-analysis.step.py
from motia import define_step
from anthropic import Anthropic
import json

client = Anthropic()

@define_step(
    type="event",
    subscribes=["job.context_ready"]
)
async def handler(data, emit, state):
    job = await state.get(f"job:{data['jobId']}")

    # Structured output via Claude
    response = client.messages.create(
        model="claude-3-7-sonnet-20250219",
        max_tokens=1024,
        system="You are an expert analyst. Return valid JSON only.",
        messages=[{
            "role": "user",
            "content": f"""
            Analyze this input and return a JSON object with:
            - summary (string, max 200 chars)
            - key_points (array of strings, max 5)
            - confidence (0.0 to 1.0)
            - requires_review (boolean)

            Input: {job['input']}
            """
        }]
    )

    try:
        analysis = json.loads(response.content[0].text)
    except json.JSONDecodeError:
        await emit("job.analysis_failed", {
            "jobId": data["jobId"],
            "error": "AI returned invalid JSON"
        })
        return

    await state.set(f"job:{data['jobId']}", {
        **job,
        "analysis": analysis,
        "status": "analyzed"
    })

    # Fan out: always emit complete, conditionally emit needs_review
    await emit("job.analyzed", {"jobId": data["jobId"]})

    if analysis["requires_review"] or analysis["confidence"] < 0.7:
        await emit("job.needs_review", {
            "jobId": data["jobId"],
            "reason": f"Low confidence: {analysis['confidence']}"
        })

The TypeScript and Python Steps share the same state store — no HTTP calls between them, no serialization ceremony.


Community Starter: Motia SaaS Skeleton

Pattern: Multi-tenant SaaS with auth, billing hooks, and AI features Status: Early community project — functional but not polished as of March 2026

The Motia SaaS skeleton is the most ambitious community template. It maps the full SaaS feature surface onto Motia's Step model:

src/steps/
├── auth/
│   ├── register.step.ts            # POST /auth/register
│   ├── login.step.ts               # POST /auth/login
│   └── verify-token.step.ts        # Middleware-style event Step
├── billing/
│   ├── create-subscription.step.ts # POST /billing/subscribe
│   ├── handle-webhook.step.ts      # POST /billing/webhook (Stripe)
│   └── check-limits.step.ts        # subscribes: ['usage.recorded']
├── tenants/
│   ├── create-tenant.step.ts       # POST /tenants
│   └── invite-member.step.ts       # POST /tenants/:id/invite
├── ai/
│   └── generate-content.step.py   # Your AI feature
└── cron/
    ├── usage-rollup.step.ts        # Hourly usage aggregation
    └── trial-expiry.step.ts        # Daily trial expiry check

Tenant isolation via state namespacing

// Tenant-scoped state keys
const TENANT_KEYS = {
  tenant: (tenantId: string) => `tenant:${tenantId}`,
  member: (tenantId: string, userId: string) => `tenant:${tenantId}:member:${userId}`,
  usage: (tenantId: string, month: string) => `tenant:${tenantId}:usage:${month}`,
  subscription: (tenantId: string) => `tenant:${tenantId}:subscription`,
};

// In any Step — tenant context flows through event data
export default defineStep({
  type: 'event',
  subscribes: ['usage.recorded'],
  async handler({ data, state }) {
    const { tenantId, feature, count } = data;
    const monthKey = new Date().toISOString().slice(0, 7); // "2026-03"

    const current = await state.get(TENANT_KEYS.usage(tenantId, monthKey)) || { total: 0 };
    await state.set(TENANT_KEYS.usage(tenantId, monthKey), {
      total: current.total + count,
      lastUpdated: new Date().toISOString(),
    });
  },
});

Stripe webhook as a Motia API Step

// src/steps/billing/handle-webhook.step.ts
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);

export default defineStep({
  type: 'api',
  path: '/billing/webhook',
  method: 'POST',
  async handler({ req, emit, state }) {
    const sig = req.headers['stripe-signature'];
    let event: Stripe.Event;

    try {
      event = stripe.webhooks.constructEvent(
        req.rawBody,
        sig,
        process.env.STRIPE_WEBHOOK_SECRET!
      );
    } catch (err) {
      return { status: 400, error: 'Invalid signature' };
    }

    // Emit as Motia events — downstream Steps handle each type
    switch (event.type) {
      case 'customer.subscription.created':
        await emit('subscription.activated', { stripeEvent: event });
        break;
      case 'customer.subscription.deleted':
        await emit('subscription.cancelled', { stripeEvent: event });
        break;
      case 'invoice.payment_failed':
        await emit('payment.failed', { stripeEvent: event });
        break;
    }

    return { received: true };
  },
});

The webhook handler becomes a thin fan-out router. Each downstream subscription event type gets its own Step — clean separation of concerns, each with its own trace.


Deploying a Motia App to Production

The official starter doesn't include deployment config. Here's what you need for each major platform:

Railway's always-on service model is the best fit for Motia's persistent event loop:

# railway.toml
[build]
builder = "NIXPACKS"
buildCommand = "npm install && npm run build"

[deploy]
startCommand = "npm start"
healthcheckPath = "/health"
healthcheckTimeout = 30
restartPolicyType = "ON_FAILURE"
restartPolicyMaxRetries = 3

[[services]]
name = "motia-app"

[[services.envVars]]
name = "NODE_ENV"
value = "production"

Add a health endpoint Step:

// src/steps/api/health.step.ts
export default defineStep({
  type: 'api',
  path: '/health',
  method: 'GET',
  async handler() {
    return { status: 'ok', timestamp: new Date().toISOString() };
  },
});

Production State Store (Redis)

For production, replace the in-memory state store with Redis:

// motia.config.ts
import { defineConfig } from '@motiadev/core';

export default defineConfig({
  state: {
    adapter: 'redis',
    url: process.env.REDIS_URL,
    keyPrefix: 'myapp:',
  },
  events: {
    adapter: process.env.NODE_ENV === 'production' ? 'redis-streams' : 'memory',
    url: process.env.REDIS_URL,
  },
});

Redis covers both state persistence and the event bus for multi-instance production deployments.


Choosing Your Starting Point

ScenarioRecommended starterTime to working app
Learning MotiaOfficial create-motia-app5 minutes
REST API + background jobsREST API template30 minutes
AI agent workflowAI agent template1 hour
Multi-tenant SaaSSaaS skeletonHalf day
Enterprise / .NET backendBuild custom (Motia too new for enterprise starters)Custom

Honest Assessment: Motia's Starter Ecosystem Maturity

The good: Motia's DX is exceptional. The official starter, the Workbench, and the Step model all work well. The core patterns (fan-out, saga compensation, Python AI integration) are well-documented.

The honest gap: As of March 2026, Motia is still in beta (check npm view motia versions — beta flags are present). The community starter ecosystem is thin compared to Next.js or SvelteKit. There are no mature paid SaaS boilerplates like MakerKit or Supastarter for Motia.

The trajectory: With 13,800 new stars in 2025, Motia's community is growing faster than any other backend framework in the JavaScript ecosystem. By late 2026, the starter ecosystem will likely look significantly more mature.

Practical recommendation: If you're starting a Motia project today, use create-motia-app as your base, follow the folder conventions above, configure Redis for production state, and build your own patterns. The framework is stable enough for production — the gap is ecosystem tooling, not the framework itself.


Recommendations

Use create-motia-app if:

  • You're evaluating Motia and want the canonical starting point
  • Building a greenfield project without auth or billing requirements
  • You want the Workbench + tracing from day one

Use the REST API community template if:

  • Your app has webhook integrations or async processing queues
  • You want established error handling patterns (dead letter, retry events)

Use the SaaS skeleton if:

  • Building a multi-tenant SaaS with Stripe billing
  • You're comfortable adapting early-stage community code
  • You want the Motia paradigm for your entire backend — not just parts of it

Consider waiting if:

  • You need battle-tested production reliability for a high-stakes system
  • Your team isn't comfortable with beta-stage dependencies

Methodology

  • Sources: Motia GitHub (MotiaDev/motia, 13,800+ new stars in 2025), motia.dev official documentation, JS Rising Stars 2025 (risingstars.js.org), Motia Discord community, npm registry (motia package versions), Railway deployment documentation
  • Date: March 2026

New to the Motia framework? See Motia Framework: Unified Backend for AI 2026 on PkgPulse for a full framework overview.

For the most complete SaaS starters across all frameworks: Best Next.js SaaS Boilerplates 2026 and Best SvelteKit SaaS Boilerplates 2026.

Choosing a message broker for Motia's production event system? See amqplib vs KafkaJS vs Redis Streams 2026 on PkgPulse.

Comments

The SaaS Boilerplate Matrix (Free PDF)

20+ SaaS starters compared: pricing, tech stack, auth, payments, and what you actually ship with. Updated monthly. Used by 150+ founders.

Join 150+ SaaS founders. Unsubscribe in one click.