Best Motia Starter Kits & Templates 2026
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-appis 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:
- Typed Step organization — a clear folder convention for API, event, and cron Steps
- Shared state patterns — how to namespace keys in the built-in state store
- Error handling — compensating events and dead-letter patterns
- External persistence — Redis or PostgreSQL for production state (the default state store is in-memory)
- Python interop — at least one Python Step demonstrating the AI integration pattern
- Observability — Workbench-ready with trace context propagation
- 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 (recommended for Motia in 2026)
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
| Scenario | Recommended starter | Time to working app |
|---|---|---|
| Learning Motia | Official create-motia-app | 5 minutes |
| REST API + background jobs | REST API template | 30 minutes |
| AI agent workflow | AI agent template | 1 hour |
| Multi-tenant SaaS | SaaS skeleton | Half day |
| Enterprise / .NET backend | Build 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.
Testing Motia Steps in Isolation
One of the practical questions that community Motia starters haven't fully answered yet is how to write unit tests for individual Steps. The good news: Motia Steps are pure functions. The handler function receives data, emit, and state as parameters — all of which can be mocked in a standard test framework like Vitest or Jest.
The testing pattern that works well across both TypeScript and Python Steps:
// tests/steps/process-resource.test.ts
import { describe, it, expect, vi, beforeEach } from 'vitest';
describe('process-resource Step', () => {
let mockEmit: ReturnType<typeof vi.fn>;
let mockState: { get: ReturnType<typeof vi.fn>; set: ReturnType<typeof vi.fn> };
beforeEach(() => {
mockEmit = vi.fn();
mockState = { get: vi.fn(), set: vi.fn() };
});
it('emits resource.processed on success', async () => {
mockState.get.mockResolvedValue({ id: '123', input: 'test-input' });
const step = await import('../src/steps/events/process-resource.step');
await step.default.handler({
data: { resourceId: '123' },
emit: mockEmit,
state: mockState,
});
expect(mockEmit).toHaveBeenCalledWith('resource.processed', expect.objectContaining({
resourceId: '123',
}));
});
it('emits resource.processing_failed on error', async () => {
mockState.get.mockRejectedValue(new Error('DB connection failed'));
const step = await import('../src/steps/events/process-resource.step');
await step.default.handler({
data: { resourceId: '456' },
emit: mockEmit,
state: mockState,
});
expect(mockEmit).toHaveBeenCalledWith('resource.processing_failed', expect.objectContaining({
resourceId: '456',
retryable: true,
}));
});
});
This testing model is one of Motia's hidden strengths compared to traditional Express middleware or BullMQ job processors. In those frameworks, testing a background job requires mocking the queue client and often standing up a test Redis instance. In Motia, each Step is a function — you pass in mocked dependencies and assert on the outputs. End-to-end integration tests using the Workbench's API are a complement, not a replacement, for unit tests at this level.
Migrating From Express + BullMQ to Motia
If you're considering moving an existing Node.js backend to Motia, the migration path is incremental. Motia doesn't require a big-bang rewrite — you can run it alongside an existing Express server during transition.
The pattern used by several early adopters:
- Keep Express for existing routes — don't break what's working
- Move new background jobs to Motia Event Steps — replace any new BullMQ queue consumers with Motia Steps
- Move new cron jobs to Motia Cron Steps — replace
node-croncalls one at a time - Migrate existing API endpoints to Motia API Steps — as you have bandwidth for each route
The key migration signal: when you find yourself writing a new API endpoint that immediately enqueues a BullMQ job, that endpoint-plus-job pair is a natural Motia API Step + Event Step. The pattern becomes obvious once you've written a few Motia workflows — the places where your current code has await queue.add('process-thing', data) are exactly where Motia's await emit('thing.created', data) belongs.
The largest practical friction during migration is the state store. If your existing background jobs rely on Redis for shared state (job progress, intermediate results), you need to decide whether to continue using Redis directly in Motia Steps or use Motia's state store abstraction. The state store abstraction is cleaner but means learning a new API. For migration scenarios, reading from Redis directly inside Motia Steps via the ioredis client is perfectly valid — you don't have to adopt Motia's state API immediately.
One area where Motia genuinely simplifies the migration process: the Workbench. When you convert an existing Express route + BullMQ processor pair to a Motia API Step + Event Step, the Workbench immediately visualizes the flow. During migration, this visibility is practically useful — you can see which Steps are running, which events are flowing, and where errors occur in real time without setting up a separate monitoring tool. Teams that have migrated incrementally report that the Workbench's trace view accelerates debugging during the transition period, because the old Express + BullMQ architecture had no equivalent visual representation of running background jobs. For the broader SaaS boilerplate context beyond Motia's backend, best SaaS boilerplates 2026 covers the full-stack starters that pair well with a Motia backend. And best free open-source SaaS boilerplates 2026 lists open-source options where the backend architecture is auditable — useful comparison for teams evaluating Motia's approach against established patterns.
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
Motia's Position in the 2026 Backend Framework Landscape
Motia occupies a specific niche: unified backend for modern AI-augmented applications where the primary challenge is orchestrating multiple data sources, API calls, and asynchronous processes rather than serving HTTP requests at high volume. This positions it well for AI agent backends, complex workflow orchestration, and event-driven architectures where traditional request/response frameworks feel wrong.
Where Motia is less suited: high-throughput APIs where raw request handling performance matters, applications with deep real-time state synchronization requirements (where a WebSocket-first framework like Phoenix or a dedicated real-time layer is better), or teams that need an extensive ecosystem of pre-built integrations. Motia's strength is the programming model, not the plugin library.
For teams evaluating Motia alongside more established options: the primary alternative for event-driven backend development in the JavaScript ecosystem is building with separate tools (an HTTP server plus a message queue plus a step function orchestrator), which Motia unifies into one programming model. The productivity gain of unification is real but requires accepting the ecosystem immaturity tradeoff.
The broader SaaS boilerplate market gives useful context for how Motia starters compare to the full range of options. Best SaaS boilerplates 2026 covers the established Next.js-based starters that are more mature for standard SaaS products. Best Next.js boilerplates 2026 is the right comparison for teams where the frontend framework drives the choice. Motia's case is strongest when the backend orchestration complexity is the differentiated part of your product.
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.