Motia Icon
Deployment Guide

Docker

Deploy Motia applications using Docker containers

Docker is the foundation for all Motia production deployments. This guide covers containerizing your Motia app with the iii engine for local testing and production use.


Build Your Project

Before creating a Docker image, build your Motia project:

motia build

This produces optimized production files:

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

Dockerfile

Create a Dockerfile in your project root. This uses a multi-stage build to install the iii engine binary and run your Motia app with Bun:

Dockerfile
FROM debian:bookworm-slim AS builder
 
RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates && \
    rm -rf /var/lib/apt/lists/*
 
RUN curl -fsSL https://install.iii.dev/iii/main/install.sh | sh
 
FROM oven/bun:1.1-slim
 
WORKDIR /app
 
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"]

.dockerignore

Create a .dockerignore to keep the image small:

.dockerignore
node_modules
.git
.env
data/
src/
*.md

Production config.yaml

Create a config-production.yaml that uses Redis adapters for production:

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}
 
  - class: modules::state::StateModule
    config:
      adapter:
        class: modules::state::adapters::RedisAdapter
        config:
          redis_url: ${REDIS_URL:redis://localhost:6379}
 
  - class: modules::api::RestApiModule
    config:
      port: ${PORT:3111}
      host: 0.0.0.0
      default_timeout: 30000
      concurrency_request_limit: 1024
 
  - class: modules::queue::QueueModule
    config:
      adapter:
        class: modules::queue::BuiltinQueueAdapter
 
  - class: modules::observability::OtelModule
    config:
      enabled: ${OTEL_ENABLED:true}
      service_name: ${OTEL_SERVICE_NAME:my-app}
      exporter: ${OTEL_EXPORTER_TYPE:memory}
 
  - class: modules::pubsub::PubSubModule
    config:
      adapter:
        class: modules::pubsub::RedisAdapter
        config:
          redis_url: ${REDIS_URL:redis://localhost:6379}
 
  - 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 Compose

For local development with Redis:

docker-compose.yml
services:
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
 
  app:
    build: .
    ports:
      - "3111:3111"
      - "3112:3112"
    environment:
      - REDIS_URL=redis://redis:6379
    depends_on:
      - redis

Run with:

docker compose up --build

Python Steps

Make sure you have the pyproject.toml at your project and the steps folder

pyproject
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
 
[project]
name = "python-test"
version = "0.1.0"
description = "Minimal Motia Python test project"
requires-python = ">=3.10"
dependencies = [
  "motia[otel]",
  "iii-sdk==0.2.0",
]
 
[tool.hatch.build.targets.wheel]
packages = ["steps"]

Include this dockerfile

Dockerfile (with Python)
# syntax=docker/dockerfile:1
 
FROM debian:bookworm-slim AS iii-builder
 
RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates && \
    rm -rf /var/lib/apt/lists/*
 
RUN curl -fsSL https://install.iii.dev/iii/main/install.sh | sh
 
FROM python:3.11-slim
 
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates && \
    rm -rf /var/lib/apt/lists/*
 
WORKDIR /app
 
COPY --from=iii-builder /root/.local/bin/iii /usr/local/bin/iii
 
COPY pyproject.toml ./
RUN pip install --no-cache-dir uv && \
    uv pip install --system -r pyproject.toml
 
COPY steps ./steps
COPY config.yaml ./config.yaml
 
ENV III_URL=ws://127.0.0.1:49134
 
EXPOSE 3111 3112
 
CMD ["iii", "-c", "config.yaml"]

Add a second ExecModule entry in your config-production.yaml for the Python runtime:

  - class: modules::shell::ExecModule
    config:
      watch:
        - steps/**/*_step.py
      exec:
        - uv run motia run --dir steps

Ports

PortService
3111REST API (HTTP endpoints)
3112Stream API (WebSocket)

What's Next?

On this page