How to Define a Video Composition in Remotion: A Complete Guide

Use the <Composition> component from the remotion core package to register your video with a unique ID, a React component reference, and essential configuration including width, height, fps, and durationInFrames.

Defining a video composition is the foundational step in any Remotion project. In the remotion-dev/remotion repository, you declare these compositions using a declarative React API that bridges your component code with the rendering pipeline. This guide explains how to define a video composition in Remotion using the <Composition> component, from basic registration to advanced dynamic metadata.

Understanding the Composition Architecture

The <Composition> component in packages/core/src/Composition.tsx serves as a registration façade rather than a rendering container. It does not directly output video frames; instead, it registers your component with the Composition Manager, validates configuration, and supplies the runtime with rendering instructions.

The Registration Façade Pattern

Internally, <Composition> wraps an InnerComposition component. The outer layer handles conditional rendering based on the onlyRenderComposition context, while InnerComposition manages the actual registration lifecycle:

export const Composition = <...>(props) => {
  const {onlyRenderComposition} = useContext(CompositionSetters);
  if (onlyRenderComposition && onlyRenderComposition !== props.id) {
    return null;
  }
  return <InnerComposition {...props} />;
};

Source: packages/core/src/Composition.tsx (lines 1-20)

Core Files and Responsibilities

Several modules in the remotion core package collaborate to define and manage compositions:

How to Define a Basic Video Composition

At minimum, a composition requires an id, a component, and video configuration parameters. Here is the simplest valid definition:

// src/Root.tsx
import {Composition} from 'remotion';
import {MyComponent} from './MyComponent';

export const RemotionRoot = () => {
  return (
    <Composition
      id="MyVideo"
      component={MyComponent}
      width={1080}
      height={1920}
      fps={30}
      durationInFrames={150}
    />
  );
};

This registers a composition named MyVideo with a portrait resolution of 1080×1920, running at 30 frames per second for 150 frames (5 seconds).

Advanced Composition Configuration

Beyond basic parameters, Remotion supports dynamic props, runtime validation, and calculated metadata.

Adding Default Props

Use defaultProps to provide initial values that merge with runtime inputs from the Player or CLI:

import {Composition} from 'remotion';
import {Greeting} from './Greeting';

export const GreetingVideo = () => {
  return (
    <Composition
      id="Greeting"
      component={Greeting}
      width={1280}
      height={720}
      fps={60}
      durationInFrames={180}
      defaultProps={{name: 'Remotion'}}
    />
  );
};

Type-Safe Props with Zod Schema

For runtime type safety, pass a Zod schema via the schema prop. The validateDefaultAndInputProps function in packages/core/src/validation/validate-default-props.ts validates props against this schema before registration:

import {z} from 'zod';
import {Composition} from 'remotion';
import {Chart} from './Chart';

const ChartSchema = z.object({
  data: z.array(z.number()),
  title: z.string(),
});

export const ChartVideo = () => {
  return (
    <Composition
      id="Chart"
      component={Chart}
      width={1920}
      height={1080}
      fps={30}
      durationInFrames={300}
      schema={ChartSchema}
      defaultProps={{data: [10, 20, 30], title: 'Demo'}}
    />
  );
};

Dynamic Metadata with calculateMetadata

Supply a calculateMetadata function to compute video dimensions or duration dynamically based on props or external data. This runs once per render before the frame loop begins:

import {Composition, type CalcMetadataReturnType} from 'remotion';
import {DynamicScene} from './DynamicScene';

export const DynamicVideo = () => {
  return (
    <Composition
      id="Dynamic"
      component={DynamicScene}
      calculateMetadata={async ({props}) => {
        const duration = props.title.length * 5;
        return {
          durationInFrames: duration,
          fps: 30,
          width: 1280,
          height: 720,
        } as CalcMetadataReturnType<typeof props>;
      }}
      defaultProps={{title: 'Hello world'}}
    />
  );
};

Validation and Registration Lifecycle

When you define a video composition in Remotion, the component undergoes strict validation and registration before becoming available to the renderer.

First, the id prop is validated for URL safety by validateCompositionId in packages/core/src/validation/validate-composition-id.ts. This ensures the composition can be safely referenced in URLs and CLI commands.

Next, validateDefaultAndInputProps (from packages/core/src/validation/validate-default-props.ts) checks that defaultProps conform to the provided Zod schema if one exists.

Finally, InnerComposition registers the composition with the CompositionManager via the context provided in packages/core/src/CompositionManagerContext.tsx. The registration includes the component reference, resolved configuration, and validation results. When the component unmounts, unregisterComposition removes it from the manager to prevent memory leaks.

Summary

  • Use the <Composition> component from remotion to register video definitions declaratively in React.
  • Minimum required props include id, component, width, height, fps, and durationInFrames.
  • The component acts as a registration façade that validates configuration and supplies metadata to the Composition Manager without rendering video frames itself.
  • Support for type safety comes via optional Zod schemas validated at runtime in packages/core/src/validation/validate-default-props.ts.
  • Dynamic metadata can be computed using calculateMetadata for scenarios where video dimensions or duration depend on external data or props.

Frequently Asked Questions

What is the difference between a Composition and a Remotion component?

A Composition is the registration wrapper that defines video metadata (dimensions, duration, fps) and maps to a component ID. A Remotion component is the actual React component that renders frames using Remotion hooks like useCurrentFrame. The Composition tells Remotion how to render; the component defines what to render.

Can I use lazy loading for composition components?

Yes. The <Composition> component supports lazy loading through the useLazyComponent hook implemented in packages/core/src/Composition.tsx. You can pass a lazily loaded component using React.lazy() or dynamic imports, and Remotion will suspend rendering until the component is available.

How does Remotion validate composition IDs?

Remotion validates composition IDs using the validateCompositionId function in packages/core/src/validation/validate-composition-id.ts. This ensures IDs are URL-safe and contain only valid characters, preventing errors when referencing compositions via the CLI or Studio URL parameters.

What happens if I don't provide a Zod schema?

Providing a Zod schema is optional. If omitted, Remotion will still register the composition but will only perform basic validation on defaultProps via validateDefaultAndInputProps in packages/core/src/validation/validate-default-props.ts. Without a schema, you lose runtime type checking but gain flexibility for rapid prototyping.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →