Motia Icon
Deployment Guide

Self-Hosted Deployment

Learn how to deploy your Motia project to production using motia-docker

Motia v1.0 migration: Upgrading from 0.17? Follow the 0.17 to 1.0 migration guide and handler migration guide.

Prerequisites

Before you build your Docker image, first make sure you run motia build to build your project.

motia build

This will build your project and create a dist directory with your production-ready code. It should be just two files: index-production.js and index-production.js.map.

dist/
├── index-production.js
└── index-production.js.map

iii Production Config

Make sure you have a config-production.yaml file in your project.

config-production.yaml
modules:
  - class: modules::stream::StreamModule
    config:
      port: ${STREAM_PORT:3112}
      host: 0.0.0.0
      adapter:
        class: modules::stream::adapters::RedisAdapter
        config:
          redis_url: ${REDIS_URL:redis://localhost:6379} # make sure the redis url is correct
 
  - class: modules::state::StateModule
    config:
      adapter:
        class: modules::state::adapters::RedisAdapter
        config:
          redis_url: ${REDIS_URL:redis://localhost:6379} # make sure the redis url is correct
 
  # Add CORS
  - class: modules::api::RestApiModule
    config:
      port: 3111 # make sure the port meets your load balancer's requirements
      host: 0.0.0.0 # make sure it has access to the internet
      default_timeout: 30000
      concurrency_request_limit: 1024
      cors:
        allowed_origins:
          - https://app.example.com
        allowed_methods:
          - GET
          - POST
          - PUT
          - DELETE
          - OPTIONS
 
  # Optional: Configure an OTEL server to send telemetry to
  - class: modules::observability::OtelModule
    config:
      enabled: ${OTEL_ENABLED:true}
      service_name: ${OTEL_SERVICE_NAME:iii-engine}
      service_version: ${SERVICE_VERSION:0.2.0}
      service_namespace: ${SERVICE_NAMESPACE:production}
      exporter: ${OTEL_EXPORTER_TYPE:memory}
      endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4317}
      sampling_ratio: 1.0
      memory_max_spans: ${OTEL_MEMORY_MAX_SPANS:10000}
      metrics_enabled: true
      metrics_exporter: ${OTEL_METRICS_EXPORTER:memory}
      metrics_retention_seconds: 3600
      metrics_max_count: 10000
      logs_enabled: ${OTEL_LOGS_ENABLED:true}
      logs_exporter: ${OTEL_LOGS_EXPORTER:memory}
      logs_max_count: ${OTEL_LOGS_MAX_COUNT:1000}
      logs_retention_seconds: ${OTEL_LOGS_RETENTION_SECONDS:3600}
      logs_sampling_ratio: ${OTEL_LOGS_SAMPLING_RATIO:1.0}
 
  - class: modules::queue::QueueModule
    config:
      adapter:
        # We have a binary that has RabbitMQ adapter, but is not published yet
        # This built-in adapter is for 1 single instance
        class: modules::queue::BuiltinQueueAdapter
 
  - class: modules::pubsub::PubSubModule
    config:
      adapter:
        class: modules::pubsub::RedisAdapter
        config:
          redis_url: ${REDIS_URL:redis://localhost:6379} # make sure the redis url is correct
 
  - class: modules::cron::CronModule
    config:
      adapter:
        class: modules::cron::KvCronAdapter
 
  - class: modules::shell::ExecModule
    config:
      exec:
        - bun run --enable-source-maps dist/index-production.js

Docker Setup

Dockerfile
FROM debian:bookworm-slim AS builder
 
# Install curl and ca-certificates
RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates && \
    rm -rf /var/lib/apt/lists/*
 
# Install iii
RUN curl -fsSL https://install.iii.dev/iii/main/install.sh | sh
 
FROM oven/bun:1.1-slim
 
WORKDIR /app
 
# Copy iii binary
COPY --from=builder /root/.local/bin/iii /usr/local/bin/iii
 
COPY package.json .
COPY dist/index-production.js dist/
COPY dist/index-production.js.map dist/
COPY config-production.yaml config.yaml
 
EXPOSE 3111
EXPOSE 3112
 
CMD ["iii", "--config", "config.yaml"]

Python Steps?

Use the Dockerfile setup documented in Docker guide - Python Steps.


Deploy to Cloud

Once you have Docker working locally, deploy to any cloud platform:

Railway

The easiest option. Railway detects your Dockerfile automatically and provides managed Redis.

👉 Full Railway deployment guide →

Fly.io

Global edge deployment with Upstash Redis. Great for low-latency worldwide.

👉 Full Fly.io deployment guide →

On this page