Skip to main content

Building Scalable Video Generation with Remotion and Docker: A Developer's Complete Guide

· 7 min read
Scott Havird
Engineer

If you've ever wanted to programmatically generate videos at scale, you've probably discovered that traditional video editing tools don't cut it for automated workflows. Enter Remotion—a React-based video generation framework that lets you create videos using familiar web technologies. But here's the kicker: when you combine Remotion with Docker and GitHub Actions, you get a production-ready video generation pipeline that can scale from your laptop to the cloud.

I recently built a Remotion Docker template that demonstrates exactly this workflow, and I want to share what I learned about creating a developer-friendly experience for programmatic video generation.

The Developer Experience Problem

Most video generation solutions force you into one of two camps: either you're stuck with GUI-based tools that don't scale, or you're wrestling with complex FFmpeg commands that make your eyes bleed. Remotion solves this by letting you write video compositions in React, but the local development story can still be painful.

Here's what I wanted to achieve:

  • Local development that "just works" with hot reload
  • Containerized rendering that's consistent across environments
  • GitHub Actions integration for automated video generation
  • Parameterized videos that can be customized without code changes

The Architecture: Atomic Design Meets Video

The template follows atomic design principles, which turns out to be perfect for video compositions:

src/
├── components/
│ ├── atoms/ # Basic building blocks
│ │ ├── AnimatedText/
│ │ ├── AnimatedCircle/
│ │ └── ScrollingPage/
│ ├── molecules/ # Groups of atoms
│ │ ├── IntroSection/
│ │ ├── ContentSection/
│ │ └── OutroSection/
│ └── organisms/ # Complex compositions
│ └── HelloWorldComposition/
└── index.tsx # Composition registration

This structure makes it incredibly easy for LLMs (or humans) to understand and modify video components. Each component is self-contained with its own types, tests, and documentation.

Local Development: The Magic of remotion-dev

The best part about this setup is how smooth the local development experience is. With Docker Compose, getting started is literally two commands:

# Start the development server with hot reload
docker-compose up remotion-dev

# Open http://localhost:3000 for Remotion Studio

The remotion-dev service mounts your source code into the container, so changes are reflected immediately. No more "it works on my machine" problems—if it works in the container, it works everywhere.

Here's the Docker Compose configuration that makes this possible:

services:
remotion-dev:
build: .
container_name: remotion-dev
volumes:
- ./src:/usr/src/app/src
- ./out:/usr/src/app/out
- ./package.json:/usr/src/app/package.json
- ./tsconfig.json:/usr/src/app/tsconfig.json
ports:
- "3000:3000"
environment:
- NODE_ENV=development
command: ["npm", "run", "dev"]

The volume mounts ensure that your code changes are immediately available inside the container, while the port mapping gives you access to Remotion Studio in your browser.

Visual Editing with Zod Schemas

One of Remotion's killer features is visual editing with Zod schemas. You can edit video properties in real-time without touching code:

export const HelloWorldSchema = z.object({
title: z.string().default('Hello World'),
subtitle: z.string().default('Welcome to Remotion'),
contentHeader: z.string().default('Discover More'),
outroMessage: z.string().default('Thank You!')
});

In Remotion Studio, these show up as editable form fields. Change the title, and you immediately see the update in the preview. Hit the save button, and Remotion writes the changes back to your code. It's magical.

Production Rendering: remotion-render

When you're ready to render, the production service strips away the development overhead:

# Render video and exit
docker-compose up remotion-render

# Video outputs to ./out/HelloWorld.mp4

The render script (render.mjs) is where the magic happens:

// Get input props from environment variables or use defaults
const inputProps = {
title: process.env.TITLE || 'Hello World',
subtitle: process.env.SUBTITLE || 'Welcome to Remotion',
contentHeader: process.env.CONTENT_HEADER || 'Discover More',
outroMessage: process.env.OUTRO_MESSAGE || 'Thank You!'
};

await renderMedia({
codec: 'h264',
composition,
serveUrl: bundled,
outputLocation: outputPath,
chromiumOptions: {
enableMultiProcessOnLinux: true,
},
inputProps,
});

This approach means you can customize videos entirely through environment variables—perfect for automation.

GitHub Actions: The Production Pipeline

The real power comes from the GitHub Actions integration. The template includes three workflows that create a complete CI/CD pipeline:

1. Build and Publish Docker Image

Every push to main triggers a Docker image build and publishes it to GitHub Container Registry:

name: Build and Publish Docker Image

on:
push:
branches: [ main ]
tags: [ 'v*' ]

The images are tagged with semantic versioning and SHA hashes, so you always know exactly what you're running.

2. Render Video Workflow

This is where it gets interesting. You can trigger video rendering manually with custom parameters:

on:
workflow_dispatch:
inputs:
title:
description: 'Video title'
required: false
default: 'Hello World'
type: string
# ... more parameters

Or set it to run automatically on a schedule:

schedule:
# Run daily at 2 AM UTC
- cron: '0 2 * * *'

The workflow pulls your Docker image and runs it with the specified parameters:

docker run --rm \
-v $(pwd)/output:/usr/src/app/out \
-e TITLE="${{ github.event.inputs.title || 'Hello World' }}" \
-e SUBTITLE="${{ github.event.inputs.subtitle || 'Welcome to Remotion' }}" \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:main

3. Release Management

The third workflow automatically creates GitHub releases with the rendered videos attached. This gives you permanent storage and direct download links for all your generated content.

Parameterized Video Generation

Here's where things get really powerful. You can generate different videos by passing environment variables:

# Local custom render
docker run --rm \
-v $(pwd)/output:/usr/src/app/out \
-e TITLE="My Custom Video" \
-e SUBTITLE="Built with Remotion" \
-e CONTENT_HEADER="Check This Out" \
-e OUTRO_MESSAGE="Thanks for Watching!" \
ghcr.io/scotthavird/remotion-docker-template:main

This makes it trivial to generate personalized videos, A/B test different messaging, or create variations for different audiences—all without changing a single line of code.

The Container Setup: Chrome in Docker

One of the trickiest parts of containerizing Remotion is getting Chrome to run reliably in Docker. The Dockerfile handles all the necessary dependencies:

# Install Chrome dependencies
RUN apt install -y \
libnss3 \
libdbus-1-3 \
libatk1.0-0 \
libgbm-dev \
libasound2 \
# ... more dependencies

# Install Chrome Headless Shell
RUN npx remotion browser ensure

The template also includes proper user management and permissions to ensure the container runs securely in production environments.

Real-World Applications

This setup opens up some compelling use cases:

  • Marketing Automation: Generate personalized video ads based on user data
  • Social Media Content: Create daily posts with dynamic content
  • Educational Content: Build course videos with different examples
  • Product Demos: Showcase features with current screenshots
  • Data Visualizations: Turn analytics into animated reports

Performance Considerations

Video rendering is CPU-intensive, so the template includes several optimizations:

  • Multi-process Chrome for better performance on multi-core systems
  • Docker layer caching to speed up builds
  • Efficient volume mounts to minimize I/O overhead
  • Non-root user for security without sacrificing performance

For production workloads, you'll want to run this on machines with plenty of CPU cores and RAM.

What's Next?

The template provides a solid foundation, but there's room for enhancement:

  • Multiple video formats (WebM, different resolutions)
  • Batch processing for generating multiple videos
  • Cloud deployment patterns (AWS ECS, Google Cloud Run)
  • Webhook integrations for triggering renders

Getting Started

The remotion-docker-template is available on GitHub with complete documentation. Clone it, run docker-compose up remotion-dev, and you'll have a working video generation environment in minutes.

The combination of Remotion's React-based approach, Docker's consistency, and GitHub Actions' automation creates a developer experience that actually makes programmatic video generation enjoyable. No more fighting with complex video editing APIs or worrying about environment differences.

Give it a try, and let me know what you build with it. The future of video generation is programmatic, and the developer experience is finally catching up to the possibilities.


Want to learn more about building scalable developer tools? Follow me on Twitter or check out my other projects on GitHub.