Skip to main content
The Template Builder provides a fluent API for defining custom templates with specific dependencies, files, and configuration.

Basic Structure

from moru import Template

template = (
    Template()
    .from_python_image("3.11")           # Base image
    .pip_install(["requests", "flask"])  # Install packages
    .copy("./app", "/app")               # Copy files
    .set_workdir("/app")                 # Set working directory
    .set_start_cmd("python app.py")      # Startup command
)

# Build the template
info = Template.build(template, alias="my-flask-app")

Base Images

Official Language Images

# Python
Template().from_python_image("3.11")
Template().from_python_image("3.10")
Template().from_python_image()  # Default: Python 3

# Node.js
Template().from_node_image("lts")
Template().from_node_image("20")
Template().from_node_image()  # Default: LTS

# Bun
Template().from_bun_image("latest")
Template().from_bun_image("1.0")

OS Images

Template().from_ubuntu_image("22.04")
Template().from_debian_image("bookworm")
Template().from_base_image()  # Moru's optimized base

Custom Images

# Public Docker Hub image
Template().from_image("nginx:alpine")

# Private image with credentials
Template().from_image(
    "myregistry.com/myimage:tag",
    username="user",
    password="pass"
)

# Existing Moru template
Template().from_template("my-base-template")

Package Installation

Python (pip)

Template().pip_install(["numpy", "pandas", "scikit-learn"])
Template().pip_install("requests")  # Single package
Template().pip_install(["mypackage"], g=True)  # Global install

Node.js (npm)

Template().npm_install(["express", "typescript"])
Template().npm_install(["eslint"], g=True)  # Global install
Template().npm_install(["jest"], dev=True)  # Dev dependency

Bun

Template().bun_install(["hono", "drizzle-orm"])
Template().bun_install(["typescript"], g=True)

System (apt)

Template().apt_install(["curl", "git", "build-essential"])
Template().apt_install(["chromium"], no_install_recommends=True)

File Operations

Copy Files

# Single file
Template().copy("./config.json", "/app/config.json")

# Directory
Template().copy("./src", "/app/src")

# Multiple sources
Template().copy(["./src", "./lib"], "/app")

# With options
Template().copy(
    "./scripts",
    "/app/scripts",
    user="root",
    mode=0o755
)

Create Directories

Template().make_dir("/app/data")
Template().make_dir("/app/logs", mode=0o755)

Commands

# Run a command during build
Template().run_cmd("echo 'Building...'")

# Multiple commands
Template().run_cmd(["apt-get update", "apt-get upgrade -y"])

# As specific user
Template().run_cmd("npm install", user="node")

Configuration

Environment Variables

Template().set_envs({
    "NODE_ENV": "production",
    "PORT": "3000",
    "DATABASE_URL": "postgres://..."
})

Working Directory

Template().set_workdir("/app")

Default User

Template().set_user("node")

Startup Commands

Start Command

# Simple start command
Template().set_start_cmd("node server.js")

# With ready command (waits for this to succeed)
Template().set_start_cmd(
    "node server.js",
    "curl -s localhost:3000/health"
)

Ready Commands

Use helper functions for common readiness checks:
from moru.template import wait_for_port, wait_for_url

# Wait for port
Template().set_start_cmd(
    "python server.py",
    wait_for_port(8080)
)

# Wait for URL
Template().set_start_cmd(
    "npm start",
    wait_for_url("http://localhost:3000/health")
)

Building Templates

Synchronous Build

from moru import Template

template = Template().from_python_image().pip_install(["flask"])

# Build and wait for completion
info = Template.build(
    template,
    alias="my-template",
    cpu_count=2,
    memory_mb=1024
)

print(f"Template ID: {info.template_id}")
print(f"Build ID: {info.build_id}")

Background Build

# Start build in background
info = Template.build_in_background(
    template,
    alias="my-template"
)

# Check status later
status = Template.get_build_status(info)
print(f"Status: {status.status}")  # building, success, failed

Build Logs

def log_handler(entry):
    print(f"[{entry.level}] {entry.message}")

Template.build(
    template,
    alias="my-template",
    on_build_logs=log_handler
)

Build Options

OptionTypeDefaultDescription
aliasstringrequiredTemplate name
cpu_count / cpuCountnumber2Build CPU cores
memory_mb / memoryMBnumber1024Build memory (MB)
skip_cache / skipCachebooleanfalseSkip build cache
on_build_logs / onBuildLogsfunction-Log callback

Next Steps