How to Define Video Configurations with Remotion's Composition Component: Props, Validation, and Dynamic Metadata

Define video configurations in Remotion by rendering the <Composition> component with required props (id, component or lazyComponent, width, height, fps, durationInFrames) and optional props like defaultProps, schema, or calculateMetadata for dynamic resolution.

Remotion is a React framework for programmatic video generation that uses the <Composition> component as the central registry for video metadata. When you define video configurations with Remotion's Composition component, you create a declarative contract that the Studio, CLI, and Player use to understand dimensions, duration, and component structure.

Core Props for Defining Video Configurations

The <Composition> component accepts a mix of required and optional props that together form the complete video configuration.

Required Configuration Props

Every composition must define these core properties:

  • id – A unique string identifier consisting only of letters, numbers, and hyphens. This appears in the Remotion Studio sidebar and is used by the CLI and Player to target specific videos.
  • component or lazyComponent – The React component that renders the video frames. Use component for static imports or lazyComponent with () => import('./Component') for code-splitting and React Suspense.
  • width – Horizontal resolution in pixels (positive integer).
  • height – Vertical resolution in pixels (positive integer).
  • fps – Frames per second (positive number).
  • durationInFrames – Total length of the video in frames (non-negative integer).

Optional Configuration Props

Enhance compositions with these advanced options:

  • defaultProps – JSON-serializable default values for the component's props. Overridable via the Studio's Props editor or CLI input props.
  • schema – A Zod object schema (z.object({...})) that validates defaultProps and enables visual editing controls in Remotion Studio.
  • calculateMetadata – An async function (CalculateMetadataFunction) that computes width, height, fps, and durationInFrames at runtime. When provided, Remotion defers rendering until this function resolves.

How the Composition Component Registers Video Configurations

When a <Composition> mounts, the InnerComposition component (located in packages/core/src/Composition.tsx) executes a registration effect. Between lines 87 and 104, it calls registerComposition from the CompositionManagerContext to add the video to the internal registry.

This registration serves three critical functions:

  1. Registry Population – The CompositionManager maintains a list of all available videos, powering the Studio sidebar and CLI discovery.
  2. Validation Trigger – During registration, the component invokes validation helpers to ensure the configuration is renderable.
  3. Portal Preparation – The registration data enables the useResolvedVideoConfig hook to later resolve and render the component inside a React portal.

Validation Flow for Video Configurations

Remotion enforces strict validation to prevent runtime rendering errors. The validation sequence occurs inside the registration effect in Composition.tsx (lines 84-92) and utilizes helpers located in packages/core/src/validation/.

The validation flow proceeds as follows:

  1. ID Validation – validateCompositionId(id) ensures the identifier contains only alphanumeric characters and hyphens.
  2. Props Validation – validateDefaultAndInputProps(defaultProps, ...) verifies that default props are JSON-serializable or satisfy a provided Zod schema.
  3. Dimension Validation – validateDimension(width, 'width', ...) and validateDimension(height, 'height', ...) enforce positive integer dimensions.
  4. FPS Validation – validateFps(fps, ...) confirms a positive frame rate. If calculateMetadata is present, null values are permitted during the async resolution phase.
  5. Duration Validation – validateDurationInFrames(durationInFrames, ...) checks for non-negative integer frame counts.

If any validation fails, Remotion throws an error immediately, preventing the composition from appearing in the Studio or being rendered by the CLI.

Resolving Dynamic Video Configurations with calculateMetadata

When a composition uses the calculateMetadata prop, Remotion defers final configuration resolution until runtime. This process is managed by the useResolvedVideoConfig hook in packages/core/src/ResolveCompositionConfig.tsx.

The resolution workflow:

  1. Detection – The needsResolution(composition) function (line 42) checks if calculateMetadata is defined.
  2. Async Execution – Remotion invokes the calculateMetadata function, which returns a promise resolving to the final width, height, fps, and durationInFrames.
  3. State Management – The ResolveCompositionContext stores a VideoConfigState object that transitions from 'loading' to 'success' or 'error'.
  4. Consumption – The InnerComposition component reads the resolved config via useResolvedVideoConfig(id). If the state is 'loading', it returns null to prevent premature rendering. Once 'success', the component renders inside a portal with the resolved dimensions.

This mechanism enables data-driven videos where dimensions or duration depend on external APIs, databases, or asset analysis.

Practical Examples

Basic Static Configuration

Define a fixed-resolution video with explicit dimensions and duration:

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

export const RemotionRoot: React.FC = () => (
  <>
    <Composition
      id="my-video"
      component={MyVideo}
      width={1920}
      height={1080}
      fps={30}
      durationInFrames={150}
      defaultProps={{title: 'Hello world'}}
    />
  </>
);

This registers a video named my-video that renders at 1920 × 1080, 30 fps, for 5 seconds (150 frames).

Lazy-Loaded Component for Code Splitting

Reduce initial bundle size by deferring component loading:

import {Composition} from 'remotion';

export const RemotionRoot: React.FC = () => (
  <>
    <Composition
      id="lazy-video"
      lazyComponent={() => import('./LazyVideo')}
      width={1080}
      height={1080}
      fps={60}
      durationInFrames={180}
    />
  </>
);

The actual video component imports only when the composition renders, enabling React Suspense boundaries and smaller startup payloads.

Schema-Validated Props for Visual Editing

Enforce type safety and enable Studio visual controls with Zod:

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

const PropsSchema = z.object({
  title: z.string(),
  count: z.number().int().min(0),
});

export const RemotionRoot: React.FC = () => (
  <>
    <Composition
      id="schema-video"
      component={MyComp}
      width={720}
      height={720}
      fps={24}
      durationInFrames={240}
      schema={PropsSchema}
      defaultProps={{title: 'Demo', count: 0}}
    />
  </>
);

The schema guarantees that the Props editor only offers valid JSON values and provides end-to-end type safety.

Dynamic Metadata Resolution

Compute dimensions at runtime based on external data:

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

export const calculateMetadata = async () => ({
  width: 1280,
  height: 720,
  fps: 30,
  durationInFrames: 300,
});

export const RemotionRoot: React.FC = () => (
  <>
    <Composition
      id="dynamic-video"
      component={MyComp}
      calculateMetadata={calculateMetadata}
    />
  </>
);

Because width, height, fps, and durationInFrames are omitted, Remotion calls calculateMetadata before the first render to fill them in.

Organizing Compositions with Folders

Group related videos in the Studio sidebar:

import {Composition, Folder} from 'remotion';
import {CompA} from './CompA';
import {CompB} from './CompB';

export const RemotionRoot: React.FC = () => (
  <>
    <Folder name="Scenes">
      <Composition id="scene-a" component={CompA} width={1080} height={1080} fps={30} durationInFrames={120} />
      <Composition id="scene-b" component={CompB} width={1080} height={1080} fps={30} durationInFrames={120} />
    </Folder>

    <Composition id="credits" component={CompA} width={1080} height={1080} fps={30} durationInFrames={60} />
  </>
);

The Folder component only affects the Studio UI; the underlying video configs remain identical to ungrouped compositions.

Key Implementation Files

File Purpose Link
packages/core/src/Composition.tsx Core <Composition> implementation, registration, validation, and portal rendering. View on GitHub
packages/core/src/ResolveCompositionConfig.tsx Resolves a composition’s video configuration, runs validation, and provides async metadata handling. View on GitHub
packages/core/src/validation/* Helper functions (validateDimension, validateFps, validateDurationInFrames, validateCompositionId, etc.) that enforce correct video config values. Directory listing
packages/docs/docs/composition.mdx User-facing documentation for <Composition>, including prop table and examples. View on GitHub
packages/core/src/CompositionManagerContext.tsx Stores the list of registered compositions and provides the registerComposition/unregisterComposition API used by <Composition>. View on GitHub

These files together explain how video configurations are defined, validated, stored, and finally consumed by Remotion’s rendering engine.

Summary

  • Registration: The <Composition> component registers video metadata with the internal CompositionManager via the InnerComposition component in packages/core/src/Composition.tsx (lines 87-104).
  • Validation: Remotion enforces strict constraints on id, dimensions, fps, and durationInFrames using helpers in packages/core/src/validation/ before any rendering occurs.
  • Dynamic Resolution: The calculateMetadata prop enables asynchronous configuration resolution, handled by useResolvedVideoConfig in packages/core/src/ResolveCompositionConfig.tsx.
  • Consumption: Resolved configurations power the Remotion Studio sidebar, CLI rendering, and the <Player> component through the ResolveCompositionContext.

Frequently Asked Questions

What is the difference between the component and lazyComponent props?

The component prop accepts a statically imported React component, while lazyComponent accepts a function that returns a dynamic import promise (e.g., () => import('./Video')). Use lazyComponent to enable code-splitting and reduce initial bundle size, as Remotion only loads the component when the composition is rendered.

How does Remotion validate video configurations before rendering?

Remotion runs a validation sequence inside the registration effect in packages/core/src/Composition.tsx (lines 84-92). It invokes validateCompositionId for ID formatting, validateDimension for width/height, validateFps for frame rate, and validateDurationInFrames for length. If any check fails, Remotion throws immediately, preventing invalid compositions from appearing in the Studio or CLI.

Can I change video dimensions or duration based on external data?

Yes. Omit the static width, height, fps, and durationInFrames props and provide a calculateMetadata function instead. Remotion calls this async function before rendering to resolve the final configuration. The useResolvedVideoConfig hook in packages/core/src/ResolveCompositionConfig.tsx manages the loading state, ensuring the component only renders after the metadata resolves.

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 →