Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

Remotion Admin & Architecture Guide

Generated June 2026 from remotion-dev/remotion at 26d3e03

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

This guide is for the engineers, architects, and operators who deploy, configure, extend, and operate Remotion — not just author videos with it. It covers the monorepo architecture, the rendering pipeline internals, the complete configuration reference, server-side and cloud rendering APIs, deployment (AWS Lambda, Google Cloud Run, Docker), security, and the contributor-level structure of the codebase.

For day-to-day authoring (components, hooks, the Studio), see the companion User Guide.

Note

Reference baseline: remotion and @remotion/* at 4.0.472, React 19, packaged as a Bun workspace monorepo. The native renderer is a Rust binary that embeds FFmpeg.


Table of Contents

  1. Executive Summary
  2. System Architecture
  3. The Rendering Pipeline
  4. Requirements & Environments
  5. Configuration Mastery
  6. Server-Side Rendering API
  7. AWS Lambda Deployment
  8. Google Cloud Run Deployment
  9. Containerized & Self-Hosted Rendering
  10. Security
  11. Operations
  12. Repository Structure (Contributor Reference)
  13. Internals Deep Dive
  14. Testing Strategy
  15. Potential Improvements & Tech Debt
  16. Quick Reference

1. Executive Summary

Remotion is a framework for programmatic video creation using React. It is distributed as the remotion package plus a large family of @remotion/* packages, all developed in a single monorepo and released in lockstep.

What it does, operationally:

  • Renders React components to MP4/WebM/ProRes/GIF/stills by driving a headless Chrome browser frame-by-frame and stitching frames into a video with an embedded FFmpeg (compiled into a Rust compositor binary).
  • Provides a browser-based Studio for preview/editing and a @remotion/player for embedding live playback in apps.
  • Offers three rendering surfaces: local CLI, Node SSR APIs, and cloud (AWS Lambda, Google Cloud Run, or your own containers).

Key architectural properties an operator should know:

Property Implication
Deterministic, frame-indexed rendering Renders are reproducible and trivially parallelizable (split frames across workers).
Self-contained binaries Chrome (Headless Shell) is auto-downloaded; FFmpeg is embedded in the Rust compositor. No system FFmpeg/Chrome required.
Platform-specific native packages @remotion/compositor-{platform} optional deps deliver the right Rust binary per OS/arch.
Lockstep versioning Every remotion/@remotion/* must match exactly; mismatches are a top support issue.
Source-available, two-tier license Not MIT — larger for-profits need a paid company license (see Security/Licensing).

2. System Architecture

2.1 High-level component map

┌──────────────────────────────────────────────────────────────────────┐
│                         AUTHORING SURFACE                              │
│  remotion (core)  ──  React components, hooks, interpolate/spring      │
│  @remotion/cli    ──  studio / render / still / lambda / cloudrun ...  │
│  @remotion/studio ──  browser Studio UI (+ @remotion/studio-server)   │
│  @remotion/player ──  embeddable live playback                        │
└───────────────┬──────────────────────────────────────────────────────┘
                │  bundles the project with…
                ▼
┌──────────────────────────────────────────────────────────────────────┐
│                          BUILD SURFACE                                 │
│  @remotion/bundler  ──  Webpack (or Rspack, experimental) bundle       │
│  @remotion/babel-loader ── transforms project code                    │
└───────────────┬──────────────────────────────────────────────────────┘
                │  serves the bundle to…
                ▼
┌──────────────────────────────────────────────────────────────────────┐
│                         RENDER SURFACE                                 │
│  @remotion/renderer ── orchestrates headless Chrome (frame capture)   │
│         │                                                              │
│         ├─ Chrome Headless Shell (auto-downloaded)                     │
│         └─ @remotion/compositor-<platform>  (Rust binary, embeds FFmpeg)│
│              → extracts video frames, encodes/stitches output          │
└───────────────┬──────────────────────────────────────────────────────┘
                │  scale-out variants:
                ▼
┌──────────────────────────────────────────────────────────────────────┐
│  @remotion/lambda  +  @remotion/lambda-client  +  @remotion/serverless │
│  @remotion/cloudrun                                                    │
│  → split frames across many serverless workers; output to S3 / GCS     │
└──────────────────────────────────────────────────────────────────────┘

2.2 Package layering

The monorepo (remotion-monorepo, Bun workspaces under packages/**, ~250 packages) organizes into layers:

Layer Packages Role
Core runtime remotion (packages/core) Components, hooks, animation math, the frame model. Browser-safe.
Build @remotion/bundler, @remotion/babel-loader Bundle the user project (Webpack; Rspack experimental).
Render @remotion/renderer, @remotion/compositor-* Orchestrate Chrome + the Rust/FFmpeg compositor.
Studio @remotion/studio, @remotion/studio-server, @remotion/studio-shared The local editing app and its dev server.
Player @remotion/player, @remotion/player-a11y Embeddable playback.
Cloud @remotion/lambda, @remotion/lambda-client, @remotion/cloudrun, @remotion/serverless, @remotion/serverless-client Distributed rendering on AWS/GCP.
CLI @remotion/cli, create-video Command-line entry + scaffolder.
Media @remotion/media-parser, @remotion/webcodecs, @remotion/media, @remotion/media-utils, @remotion/convert Media parsing/encoding/analysis.
Feature/helper transitions, shapes, paths, noise, three, skia, lottie, gif, motion-blur, effects, google-fonts, fonts, layout-utils, preload, captions, rive, … Optional capabilities.
Cross-language clients lambda-go, lambda-python, lambda-ruby, lambda-php (+ examples) Trigger Lambda renders from non-JS backends.
Tooling/internal eslint-config*, eslint-plugin, docusaurus-plugin, docs, it-tests, skills, mcp Linting, docs, integration tests, AI tooling.

2.3 The Rust compositor

The most important non-JS component. @remotion/renderer declares the platform binaries as optional dependencies, so npm installs only the one matching the host:

@remotion/compositor-darwin-arm64    @remotion/compositor-linux-x64-gnu
@remotion/compositor-darwin-x64      @remotion/compositor-linux-x64-musl
@remotion/compositor-linux-arm64-gnu @remotion/compositor-win32-x64-msvc
@remotion/compositor-linux-arm64-musl

The compositor source lives in packages/compositor/rust (entry main.rs, with command modules under rust/commands). It embeds FFmpeg and is responsible for extracting exact video frames (used by <OffthreadVideo>), encoding, and stitching frames into the final container. Communication between the Node renderer and the compositor is over a long-running child process. Memory behavior is informed by the Lambda environment (compositor/rust/memory.rs reads AWS_LAMBDA_FUNCTION_MEMORY_SIZE).

Note

Because the binary is native and platform-specific, an operator's environment must match a supported (os, libc, arch) triple — notably gnu vs musl on Linux. Docker base images must provide a compatible libc.


3. The Rendering Pipeline

A render — local or cloud — follows the same conceptual stages:

1. BUNDLE      bundle() builds the project with Webpack → a "serve URL"
                  (a static bundle directory served over HTTP).
2. SELECT      selectComposition()/getCompositions() loads the bundle in
                  Chrome, runs calculateMetadata(), resolves dimensions/
                  fps/duration/props for the target composition.
3. RENDER      renderFrames()/renderMedia() opens Chrome tab(s), advances
                  the frame, waits for delayRender() handles to clear,
                  screenshots each frame (JPEG/PNG).
4. EXTRACT     For <OffthreadVideo>, the Rust compositor extracts exact
                  source frames off the main thread.
5. STITCH      stitchFramesToVideo() pipes frames + audio to the embedded
                  FFmpeg with the chosen codec/pixel format/bitrate.
6. OUTPUT      Final file written locally, or uploaded (S3/GCS) in cloud.

Concurrency model: renderMedia opens multiple Chrome tabs (concurrency, default ≈ half the CPU threads) and renders frames in parallel, encoding as it goes unless disallowParallelEncoding is set. In the cloud, frames are additionally split across many serverless invocations (framesPerLambda), each producing a chunk that is concatenated.

Determinism guarantees make this safe: each frame is a pure function of its index, so splitting frames across tabs/workers always reconstructs the same video.


4. Requirements & Environments

4.1 Runtime requirements

Component Requirement / Notes
Node.js / Bun Node 18+ or Bun. The monorepo itself uses bun@1.3.3.
Chrome Chrome Headless Shell auto-downloaded by Remotion; manage with npx remotion browser ensure.
FFmpeg Embedded in the compositor; do not install separately.
libc On Linux, match gnu or musl to the installed compositor binary.
GPU (optional) Hardware acceleration / specific OpenGL backends available via config.

4.2 Linux shared libraries

Headless Chrome on minimal Linux needs system libraries (fonts, GTK, NSS, etc.). On Debian/Ubuntu the typical set includes libnss3, libdbus-1-3, libatk1.0-0, libgbm1, libasound2, libxkbcommon0, libpango-1.0-0, and font packages. The official Dockerfiles in packages/dockerfiles encode a known-good set — use them as the source of truth.

4.3 Multi-process on Linux

By default Remotion passes --single-process to Chromium on Linux for stability. Removing it (faster, multi-process) is opt-in via Config.setChromiumMultiProcessOnLinux(true) but may fail on some distros or when window-server libraries are missing.


5. Configuration Mastery

Configuration is supplied two ways, with CLI flags taking precedence over the config file:

  1. remotion.config.ts — calls on the Config object (affects the Studio and CLI renders).
  2. CLI flags — per-invocation overrides.
  3. SSR/Lambda options — explicit parameters to renderMedia, renderMediaOnLambda, etc.
// remotion.config.ts
import {Config} from '@remotion/cli/config';

Config.setVideoImageFormat('jpeg');
Config.setConcurrency(8);
Config.setCodec('h264');
Config.setCrf(18);

Important

The config format is flat since Remotion 4. The old grouped namespaces (Config.Bundling.*, Config.Rendering.*, Config.Output.*, Config.Log.*, Config.Preview.*, Config.Puppeteer.*) now throw an error directing you to the flat equivalents. Several setters were also renamed: setQuality → setJpegQuality, setImageFormat → setStillImageFormat/setVideoImageFormat, setLevel → setLogLevel, setTimeoutInMilliseconds → setDelayRenderTimeoutInMilliseconds.

5.1 Output & encoding

Setter Default Purpose
setCodec(c) h264 h264, h265, vp8, vp9 (or set gif via image format/codec).
setVideoImageFormat(f) jpeg jpeg or png (png = transparency, slower).
setStillImageFormat(f) png Still output format.
setJpegQuality(q) 80 0–100.
setCrf(n) codec-dependent Constant Rate Factor (lower = higher quality).
setPixelFormat(f) yuv420p Incl. yuva420p (alpha), 10-bit variants.
setProResProfile(p) hq 4444-xq,4444,hq,standard,light,proxy.
setX264Preset(p) — ultrafast…placebo.
setAudioCodec(c) codec-dependent pcm-16,aac,mp3,opus.
setAudioBitrate(b) / setVideoBitrate(b) — Target bitrates (video bitrate mutually exclusive with CRF).
setEncodingMaxRate / setEncodingBufferSize — FFmpeg -maxrate / -bufsize.
setColorSpace(cs) default Opt into bt709.
setMuted(b) false Drop audio.
setEnforceAudioTrack(b) true Add silent track if needed.
setForSeamlessAacConcatenation(b) false Prepare AAC for seamless concat (Lambda chunking).
setNumberOfGifLoops(n) null (infinite) GIF loop count.
setEveryNthFrame(n) 1 GIF frame sampling.
setImageSequence(b) / setImageSequencePattern(p) false Output image sequence; filename pattern with [frame]/[ext].
setOutputLocation(s) out/{composition}.{codec} Output path.
setOverwriteOutput(b) true Overwrite existing output.
setMetadata(obj) — Embed metadata into the file.
setPreferLosslessAudio(b) false Prefer lossless audio.
setSampleRate(n) 48000 Output audio sample rate.

5.2 Render behavior & quality of frames

Setter Default Purpose
setConcurrency(n|"50%") half CPU threads Parallel render tabs.
setScale(n) 1 Scale output dimensions.
setFrameRange([a,b]|n) all Subset of frames (single number = a still).
setDelayRenderTimeoutInMilliseconds(ms) 30000 Per-frame async timeout.
overrideHeight/Width/Fps/Duration(n) — Override composition metadata.
setDisallowParallelEncoding(b) false More memory-efficient, possibly slower.
setHardwareAcceleration(opt) — GPU-accelerated encoding option.
setOffthreadVideoCacheSizeInBytes(n) — Cache for OffthreadVideo frame extraction.
setBeepOnFinish(b) — Studio beep when render completes.

5.3 Chromium

Setter Default Purpose
setBrowserExecutable(path) auto Use a specific browser binary.
setChromeMode(mode) — Chrome Headless Shell vs Chrome for Testing.
setChromiumHeadlessMode(b) true Show a real browser to observe rendering.
setChromiumDisableWebSecurity(b) false Disable CORS/security (only if you must).
setChromiumIgnoreCertificateErrors(b) false Accept self-signed certs.
setChromiumOpenGlRenderer(r) swangle on Lambda, else null egl,angle,swiftshader,swangle,vulkan,angle-egl.
setChromiumUserAgent(s) default Custom UA (render only).
setChromiumDarkMode(b) false Force dark mode.
setChromiumMultiProcessOnLinux(b) false Remove --single-process on Linux.
setEnableCrossSiteIsolation(b) false COOP/COEP headers in the Studio.

5.4 Bundling & Studio

Setter Default Purpose
setEntryPoint(src) — Default entry so you needn't pass it on the CLI.
setPublicDir(dir) public Location of static assets.
setPublicPath(path) — Public path for the bundle.
setCachingEnabled(b) true Webpack bundle cache.
overrideWebpackConfig(fn) identity Customize the Webpack config.
setExperimentalRspackEnabled(b) false Use Rspack instead of Webpack.
setStudioPort(n) / setRendererPort(n) auto HTTP ports (setPort deprecated).
setShouldOpenBrowser(b) true Open a browser when the Studio starts.
setMaxTimelineTracks(n) 15 Studio timeline track cap.
setKeyboardShortcutsEnabled(b) true Studio shortcuts.
setWebpackPollingInMilliseconds(n) null Polling for HMR on VMs/remote dirs.
setNumberOfSharedAudioTags(n) 0 Shared audio tags (Player autoplay).
setBufferStateDelayInMilliseconds(n) — Delay before buffering UI shows.
setIPv4(b) false Bind Studio to IPv4.
setBundleOutDir(dir) build Output of npx remotion bundle.
setAskAIEnabled(b) — Studio "Ask AI" modal.
setExperimentalClientSideRenderingEnabled(b) false WIP client-side rendering.
setAllowHtmlInCanvasEnabled(b) false HTML-in-canvas capture path.

5.5 Logging, diagnostics & licensing

Setter Default Purpose
setLogLevel('trace'|'verbose'|'info'|'warn'|'error') info Verbosity (verbose = browser logs + IO).
setRepro(b) — Collect a reproduction bundle for bug reports.
setBinariesDirectory(dir) — Where platform binaries/libs live.
setDotEnvLocation(file) .env Custom env file.
setPublicLicenseKey(key) — Company license key (or 'free-license').
setBenchmarkRuns(n) / setBenchmarkConcurrencies(s) 3 / null benchmark command tuning.

5.6 Lambda-specific config

Setter Purpose
setDeleteAfter(day) Auto-expire S3 output after a period.
setEnableFolderExpiry(b) Allow S3 bucket lifecycle expiry.
setLambdaInsights(b) Enable Lambda Insights on deploy.

6. Server-Side Rendering API

@remotion/bundler + @remotion/renderer expose the rendering pipeline as Node functions for use in CI, queues, and web backends.

6.1 Core functions

Function Package Purpose
bundle(options) bundler Bundle the project; returns a serve URL (bundle directory).
getCompositions(serveUrl, opts) renderer List all compositions (after running their calculateMetadata).
selectComposition({serveUrl, id, inputProps}) renderer Resolve a single composition's metadata.
renderMedia({...}) renderer Render a video/audio to a file.
renderStill({...}) renderer Render a single image.
renderFrames({...}) renderer Render frames only (advanced/custom stitching).
stitchFramesToVideo({...}) renderer Encode frames into a container.
ensureBrowser(opts?) renderer Pre-download/verify Chrome.
openBrowser(...) renderer Open a reusable browser instance.
makeCancelSignal() renderer Create a cancel token to abort a render.
getVideoMetadata(...) renderer Inspect a media file.

6.2 bundle() options

const serveUrl = await bundle({
  entryPoint: './src/index.ts',
  webpackOverride: (config) => config, // optional
  publicPath: null,                    // optional
  onProgress: (p) => console.log(`${p}%`),
});

6.3 Full SSR example

import {bundle} from '@remotion/bundler';
import {selectComposition, renderMedia, makeCancelSignal} from '@remotion/renderer';

const serveUrl = await bundle({entryPoint: './src/index.ts'});
const inputProps = {title: 'Quarterly Report'};

const composition = await selectComposition({serveUrl, id: 'Report', inputProps});

const {cancel, cancelSignal} = makeCancelSignal();

await renderMedia({
  serveUrl,
  composition,
  codec: 'h264',
  outputLocation: `out/${composition.id}.mp4`,
  inputProps,
  concurrency: 8,
  crf: 18,
  cancelSignal,
  onProgress: ({progress}) => console.log(`${Math.round(progress * 100)}%`),
});

Tip

In a long-running server, call bundle() once at startup (or per deploy) and reuse the serve URL across many renders. Bundling is the slowest stage; resolving and rendering per request against a cached bundle is far faster. Use ensureBrowser() at boot to avoid a cold download on the first request.


7. AWS Lambda Deployment

@remotion/lambda renders at massive scale by fanning a single render out across many Lambda invocations, each rendering a slice of frames. @remotion/lambda-client is the lighter client used to trigger/poll renders (e.g. from a backend or another language's bindings).

7.1 Setup sequence

1. Configure AWS credentials & IAM (user policy + role policy).
2. deployFunction()  → creates the Lambda render function.
3. deploySite()      → bundles your project and uploads it to S3 (serve URL).
4. renderMediaOnLambda() → triggers a distributed render.
5. getRenderProgress()   → poll until done; output lands in S3.

7.2 Function defaults & limits

From @remotion/lambda-client constants:

Setting Min Default Max
Memory (MB) 512 2048 10240
Timeout (s) — 120 (AWS max 900)
Ephemeral storage / disk (MB) 512 2048 10240

Tune memory/timeout/disk at deployFunction time; the function name encodes its memory/disk/timeout so multiple sized functions can coexist.

7.3 Triggering a render

import {renderMediaOnLambda, getRenderProgress} from '@remotion/lambda/client';

const {renderId, bucketName} = await renderMediaOnLambda({
  region: 'us-east-1',
  functionName: 'remotion-render-4-0-472-mem2048mb-disk2048mb-120sec',
  serveUrl: 'https://remotionlambda-...s3...amazonaws.com/sites/my-site/index.html',
  composition: 'MyComp',
  codec: 'h264',
  inputProps: {title: 'Hello'},
  framesPerLambda: 20,       // chunk size; affects parallelism
  privacy: 'public',         // 'public' | 'private' | 'no-acl'
  downloadBehavior: {type: 'download', fileName: 'video.mp4'},
});

let done = false;
while (!done) {
  const p = await getRenderProgress({renderId, bucketName, functionName, region: 'us-east-1'});
  if (p.fatalErrorEncountered) throw new Error(p.errors[0]?.message);
  done = p.done;
}

Selected renderMediaOnLambda inputs: region, functionName, serveUrl, composition, codec, inputProps, imageFormat, crf, jpegQuality, pixelFormat, proResProfile, privacy, framesPerLambda, concurrency/concurrencyPerLambda, frameRange, scale, everyNthFrame, maxRetries, outName, chromiumOptions, downloadBehavior, overwrite, webhook, forceWidth/Height/Fps/DurationInFrames, audioCodec, metadata, storageClass, envVariables, and licenseKey. The output includes renderId, bucketName, and several CloudWatch log URLs.

7.4 Other Lambda APIs

renderStillOnLambda, getCompositionsOnLambda, getRenderProgress, getFunctions/deleteFunction, getSites/deleteSite, getOrCreateBucket, presignUrl, speculateFunctionName, and estimatePrice. Webhooks (webhook option) notify your endpoint on completion/error.

Warning

framesPerLambda controls the parallelism/cost trade-off: smaller chunks = more invocations (faster, more overhead), larger chunks = fewer invocations (cheaper, slower). For seamless audio across chunks, enable setForSeamlessAacConcatenation. Validate against Lambda's concurrency quotas — large fan-outs can hit account limits.

7.5 Cross-language clients

@remotion/lambda-go, @remotion/lambda-python, @remotion/lambda-ruby, and @remotion/lambda-php let non-JS backends trigger renders by calling the deployed function directly (using REMOTION_AWS_* credentials and the function/region/serve-URL).


8. Google Cloud Run Deployment

@remotion/cloudrun is the GCP analog (offered by the Remotion team as an alpha). The model mirrors Lambda: deploy a Cloud Run service and a site, then render against them, with output to a Cloud Storage bucket.

8.1 GCP permissions

The installer (packages/cloudrun/src/gcpInstaller) provisions a service account whose role needs Cloud Run + Cloud Storage permissions, including: run.services.create/update/list, run.routes.invoke, run.operations.get, storage.buckets.create/get/list, storage.objects.create/list/delete, and run.services.get/setIamPolicy (to toggle authenticated/unauthenticated invocation). APIs to enable: run.googleapis.com and cloudresourcemanager.googleapis.com.

8.2 CLI

npx remotion cloudrun services deploy
npx remotion cloudrun sites create src/index.ts
npx remotion cloudrun render <serve-url> <composition>

Region is read from REMOTION_GCP_REGION; project/credentials from REMOTION_GCP_PROJECT_ID, REMOTION_GCP_CLIENT_EMAIL, and the private key.


9. Containerized & Self-Hosted Rendering

For predictable, isolated rendering on your own infrastructure, run the SSR APIs inside a container.

  • Dockerfiles: packages/dockerfiles holds reference images with the correct Chrome shared libraries and a compatible libc — start from these rather than hand-rolling.
  • libc match: use a base image whose libc (gnu/glibc vs musl/Alpine) matches the installed @remotion/compositor-linux-* binary. Alpine requires the musl variant.
  • Fonts: install font packages in the image or load fonts at runtime via @remotion/fonts/@remotion/google-fonts, or rendered text may fall back/clip.
  • Ensure binaries at build time: run npx remotion browser ensure during image build so the first render doesn't download Chrome.
  • Resources: headless Chrome is memory-hungry; size containers per concurrency. Use setDisallowParallelEncoding(true) to trade speed for lower peak memory.

A minimal pattern:

# Use a base with glibc; install Chrome deps (see packages/dockerfiles for the full list)
RUN apt-get update && apt-get install -y libnss3 libdbus-1-3 libatk1.0-0 \
    libgbm1 libasound2 libxkbcommon0 libpango-1.0-0 libcairo2 fonts-liberation
COPY . /app
WORKDIR /app
RUN npm ci && npx remotion browser ensure
CMD ["node", "render-server.js"]

10. Security

10.1 Threat surface

Surface Risk Mitigation
Arbitrary input props Props are serialized into the bundle and rendered; untrusted HTML/strings could enable XSS-like injection in the rendered DOM. Validate with Zod schema; treat input props as untrusted; sanitize any user-supplied HTML.
Remote assets <Img>/<OffthreadVideo>/fetch pull arbitrary URLs during render. Allowlist domains; run renders in a sandboxed network/container.
setChromiumDisableWebSecurity Disables CORS and Chrome security. Keep false unless strictly necessary; never combine with untrusted content.
setChromiumIgnoreCertificateErrors Accepts invalid TLS. Avoid in production.
Cloud credentials REMOTION_AWS_* / REMOTION_GCP_* grant render + storage access. Use least-privilege IAM (the deploy tooling generates scoped policies); store secrets in a secret manager, not in the bundle.
S3/GCS output privacy privacy: 'public' makes renders world-readable. Default to private and serve via presigned URLs (presignUrl).
Code execution in the bundle The project bundle runs in Chrome with full JS. Only render trusted project code; isolate per-tenant renders.

10.2 Network isolation

Renders execute untrusted-ish web content in headless Chrome. For multi-tenant or user-submitted compositions, run each render in an isolated container/VM with restricted egress, and avoid mounting host credentials into the render environment.

10.3 IAM (Lambda)

The Lambda tooling distinguishes a user policy (what your deploying principal may do) from a role policy (what the function may do at runtime). Use the generated, scoped policies rather than broad admin credentials; simulatePermissions/validation helpers exist to verify setup.

10.4 Licensing as a compliance concern

Remotion is source-available, not MIT. Larger for-profit organizations must hold a paid company license; eligibility for the free license is limited to individuals, for-profits with ≤3 employees, non-profits, and evaluators. Set Config.setPublicLicenseKey() accordingly and track this as a procurement/compliance item. The terms change slightly in Remotion 5.0; the authoritative text is LICENSE.md.


11. Operations

11.1 Upgrades

Because of lockstep versioning, never bump packages individually:

npx remotion upgrade            # upgrades all remotion packages together
npx remotion versions           # verify alignment

npx remotion versions reports installed versions and flags mismatches — wire it into CI to fail builds with drift.

11.2 Monitoring renders

  • Local/SSR: use onProgress callbacks; set setLogLevel('verbose') to surface browser logs and IO.
  • Lambda: getRenderProgress returns progress, errors, and CloudWatch log URLs (main + per-render + Lambda Insights). Poll it; alert on fatalErrorEncountered.
  • Benchmarking: npx remotion benchmark measures render time across concurrency settings to right-size hardware.

11.3 Cost & cleanup (cloud)

  • Set setDeleteAfter / setEnableFolderExpiry to auto-expire S3 output and control storage cost.
  • estimatePrice projects Lambda render cost from memory/disk/duration.
  • Periodically deleteSite/deleteFunction for stale deployments.

11.4 Performance levers

Lever Effect
concurrency More tabs = faster, more memory.
framesPerLambda (cloud) Smaller = more parallel, more overhead.
setHardwareAcceleration / --gl GPU encoding/rendering where available.
premountFor on data-heavy sequences Avoids per-frame stalls.
setOffthreadVideoCacheSizeInBytes Reduces repeated frame extraction.
setDisallowParallelEncoding Lower peak memory, slower.
setScale/setJpegQuality/setCrf Trade quality for speed/size.

12. Repository Structure (Contributor Reference)

remotion-monorepo/                 (private root; Bun workspaces; packages/**)
├── package.json                   bun@1.3.3, catalog of pinned deps, ci scripts
├── LICENSE.md                     two-tier license terms
└── packages/
    ├── core/                      → `remotion` (components, hooks, math)
    ├── cli/                       → `@remotion/cli` (commands, config, flags)
    ├── bundler/                   → Webpack bundling, esbuild-loader, fast-refresh
    ├── babel-loader/              → project code transforms
    ├── renderer/                  → headless Chrome orchestration, FFmpeg bridge
    ├── compositor/rust/           → Rust binary (embeds FFmpeg); main.rs + commands/
    ├── compositor-<platform>/     → prebuilt native binaries (optional deps)
    ├── studio/ studio-server/ studio-shared/  → the Studio app + dev server
    ├── player/ player-a11y/       → embeddable Player
    ├── lambda/ lambda-client/ serverless/ serverless-client/  → AWS rendering
    ├── cloudrun/                  → GCP Cloud Run rendering (+ gcpInstaller)
    ├── lambda-go/ -python/ -ruby/ -php/        → non-JS clients
    ├── media-parser/ webcodecs/ media/ media-utils/ convert/  → media stack
    ├── transitions/ shapes/ paths/ noise/ three/ skia/ lottie/
    │   gif/ motion-blur/ effects/ svg-3d-engine/ rive/        → feature packages
    ├── google-fonts/ fonts/ layout-utils/ preload/ captions/  → assets/text/audio
    ├── install-whisper-cpp/ openai-whisper/ elevenlabs/        → speech/captions
    ├── create-video/              → project scaffolder
    ├── template-*/                → starter templates (helloworld, tiktok, next, …)
    ├── docs/                      → Docusaurus documentation site
    ├── it-tests/                  → cross-package integration tests
    ├── eslint-config*/ eslint-plugin/  → linting
    └── skills/ mcp/ codex-plugin/      → AI/agent integrations

12.1 Build & dev scripts (root)

Script Purpose
bun run build Build all packages.
bun run watch Watch-build during development.
bun run test Run the test suite.
bun run ci Full CI pipeline.
bun run ts-build TypeScript build.
bun run stylecheck / formatting / format Lint/format (uses oxfmt/eslint).
bun run testssr / testlambda / teste2e / testtemplates / testwebcodecs / testwebrenderer Targeted test groups.

Dependencies are centralized via the Bun catalog in the root package.json (e.g. react, zod, @aws-sdk/*, three, mediabunny), so versions are pinned once and referenced as catalog: in each package.


13. Internals Deep Dive

13.1 The frame model (packages/core)

  • useCurrentFrame reads from a timeline context; in the Studio/Player it's driven by playback, during render it's set per captured frame.
  • <Sequence> shifts the frame for its subtree by adjusting the timeline context (from, with cumulative offsets for nesting and negative-offset handling). premountFor/postmountFor mount children early/late while frozen and hidden (opacity:0, pointer-events:none) so async work warms up.
  • interpolate validates ranges (strictly increasing input, equal lengths), supports per-segment easing arrays, posterize, and string/tuple output ranges (CSS scale/translate/rotate and numeric tuples).
  • spring integrates a damped harmonic oscillator (damping/mass/stiffness), caches advancement, supports from/to/delay/reverse/durationInFrames, and uses measureSpring for natural duration.
  • delayRender/continueRender maintain a set of handles on window; rendering proceeds only when all handles clear. During render, each handle arms a timeout (timeoutInMilliseconds, default 30s, minus a 2s safety margin) and supports retries.
  • staticFile rejects remote/relative/absolute/public/-prefixed paths and URL-encodes safely.

13.2 The render orchestrator (packages/renderer, 143 files)

Coordinates: opening/pooling Chrome, navigating to the served bundle, advancing frames, screenshotting, and bridging to the Rust compositor for video-frame extraction and FFmpeg encoding. Notable areas: compositor/ (binary bridge), browser/ (Chrome control), assets/ (asset collection), options/ (the browser-safe option definitions surfaced as CLI flags and config setters via BrowserSafeApis), and serve-handler/.

Note

The single source of truth for render options is BrowserSafeApis.options in the renderer's client. The CLI flags, the Config.* setters, and the SSR/Lambda option objects are all generated from these definitions — which is why a flag, a config setter, and an API field for the same option always behave identically.

13.3 Media stack

  • @remotion/media-parser (parseMedia) is a pure-JS parser for many containers (ISO-BMFF/MP4, WebM/Matroska, RIFF/WAV, transport streams, MP3, AAC, FLAC, M3U/HLS) used to read metadata and frames without FFmpeg.
  • @remotion/webcodecs (convertMedia, encoders/decoders) does in-browser conversion via the WebCodecs API.
  • <OffthreadVideo> relies on the Rust compositor for exact frame extraction during render; <Video> (HTML5) is preview-oriented.

13.4 Studio (packages/studio, studio-server)

A React app served by @remotion/studio-server's preview server (routes under preview-server/routes, hot-middleware for HMR, codemods for editing user code from the UI). It talks to the same bundler/renderer used by the CLI, so what you preview matches what you render.


14. Testing Strategy

Layer Where Notes
Unit tests src/test inside each package Co-located with source; run via bun test.
Integration tests packages/it-tests Cross-package flows: rendering, SSR, templates, Lambda/Cloud Run, codemods, monorepo wiring.
Visual regression packages/web-renderer/src/test/__screenshots__, packages/effects/src/visual-test Screenshot baselines for rendering fidelity.
Targeted suites root scripts testssr, testlambda, teste2e, testtemplates, testwebcodecs, testwebrenderer, testlayoututils, testeffectsvisual.
Skill evals packages/skills-evals Evaluate AI agent skills against Remotion tasks.

When contributing: build (bun run build), run the relevant targeted suite, run stylecheck/formatting, and verify version alignment. New options should be added to the renderer's option definitions so they propagate to CLI/config/SSR consistently.


15. Potential Improvements & Tech Debt

These are observations from the codebase and its issue tracker, useful for maintainers and downstream operators.

  • V5 license change. LICENSE.md notes the terms change in Remotion 5.0 — track this for compliance and update setPublicLicenseKey workflows accordingly.
  • Deprecated-but-live APIs. startFrom/endAt (→ trimBefore/trimAfter), grouped Config.* namespaces, setQuality/setImageFormat/setLevel/setTimeoutInMilliseconds, and setPort remain as deprecated shims. A future major could remove them; downstream code should migrate.
  • Native-binary surface. The platform-matrix of @remotion/compositor-* binaries (gnu/musl × arch × OS) is a recurring source of environment mismatches. Operators should pin and verify the correct variant in CI/Docker.
  • Experimental features. Rspack bundling, client-side rendering, HTML-in-canvas, and the new @remotion/media (experimental_Audio/experimental_Video) are behind flags — treat as unstable in production.
  • Open issues of operational interest (from the tracker at the documented commit): a frame-cache bug with non-monotonic video PTS (#8167) — relevant when rendering sources with irregular timestamps; the remainder are Studio UX items.
  • Cloud Run alpha. GCP support is explicitly alpha; AWS Lambda is the more battle-tested distributed path.

16. Quick Reference

Deployment commands

# Local / SSR
npx remotion render [entry] [comp] [out]
npx remotion still [comp] [out] --frame=N
npx remotion bundle                      # produce a deployable bundle

# AWS Lambda
npx remotion lambda functions deploy
npx remotion lambda sites create src/index.ts
npx remotion lambda render <serve-url> <comp>
npx remotion lambda functions ls / rm

# Google Cloud Run
npx remotion cloudrun services deploy
npx remotion cloudrun sites create src/index.ts
npx remotion cloudrun render <serve-url> <comp>

# Maintenance
npx remotion upgrade
npx remotion versions
npx remotion browser ensure
npx remotion benchmark
npx remotion gpu

Lambda function defaults

Setting Min Default Max
Memory (MB) 512 2048 10240
Timeout (s) — 120 900 (AWS)
Disk/ephemeral (MB) 512 2048 10240

Operational environment variables

Variable Use
REMOTION_AWS_ACCESS_KEY_ID / REMOTION_AWS_SECRET_ACCESS_KEY Lambda credentials (preferred over generic AWS vars).
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY Standard AWS credentials (fallback).
REMOTION_GCP_PROJECT_ID / REMOTION_GCP_CLIENT_EMAIL / REMOTION_GCP_REGION Cloud Run config.
REMOTION_VERSION Reported by the studio server / used in routing.
REMOTION_PARTITIONED_RENDERING Renderer parallel-encoding control.
AWS_LAMBDA_FUNCTION_MEMORY_SIZE Read by the compositor to tune memory behavior.
__RESERVED_IS_INSIDE_REMOTION_LAMBDA Internal marker for the Lambda routine (do not set).

Render option ↔ surface mapping

Concept CLI flag Config setter SSR/Lambda field
Codec --codec setCodec codec
Concurrency --concurrency setConcurrency concurrency
CRF --crf setCrf crf
Scale --scale setScale scale
Frame range --frames setFrameRange frameRange
Image format --image-format setVideoImageFormat imageFormat
Timeout --timeout setDelayRenderTimeoutInMilliseconds timeoutInMilliseconds
Pixel format --pixel-format setPixelFormat pixelFormat
Muted --muted setMuted muted

All three surfaces are generated from the same option definitions, so behavior is consistent across them.