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.componentorlazyComponent– The React component that renders the video frames. Usecomponentfor static imports orlazyComponentwith() => 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 validatesdefaultPropsand enables visual editing controls in Remotion Studio.calculateMetadata– An async function (CalculateMetadataFunction) that computeswidth,height,fps, anddurationInFramesat 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:
- Registry Population – The
CompositionManagermaintains a list of all available videos, powering the Studio sidebar and CLI discovery. - Validation Trigger – During registration, the component invokes validation helpers to ensure the configuration is renderable.
- Portal Preparation – The registration data enables the
useResolvedVideoConfighook 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:
- ID Validation –
validateCompositionId(id)ensures the identifier contains only alphanumeric characters and hyphens. - Props Validation –
validateDefaultAndInputProps(defaultProps, ...)verifies that default props are JSON-serializable or satisfy a provided Zod schema. - Dimension Validation –
validateDimension(width, 'width', ...)andvalidateDimension(height, 'height', ...)enforce positive integer dimensions. - FPS Validation –
validateFps(fps, ...)confirms a positive frame rate. IfcalculateMetadatais present,nullvalues are permitted during the async resolution phase. - 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:
- Detection – The
needsResolution(composition)function (line 42) checks ifcalculateMetadatais defined. - Async Execution – Remotion invokes the
calculateMetadatafunction, which returns a promise resolving to the finalwidth,height,fps, anddurationInFrames. - State Management – The
ResolveCompositionContextstores aVideoConfigStateobject that transitions from'loading'to'success'or'error'. - Consumption – The
InnerCompositioncomponent reads the resolved config viauseResolvedVideoConfig(id). If the state is'loading', it returnsnullto 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 internalCompositionManagervia theInnerCompositioncomponent inpackages/core/src/Composition.tsx(lines 87-104). - Validation: Remotion enforces strict constraints on
id, dimensions,fps, anddurationInFramesusing helpers inpackages/core/src/validation/before any rendering occurs. - Dynamic Resolution: The
calculateMetadataprop enables asynchronous configuration resolution, handled byuseResolvedVideoConfiginpackages/core/src/ResolveCompositionConfig.tsx. - Consumption: Resolved configurations power the Remotion Studio sidebar, CLI rendering, and the
<Player>component through theResolveCompositionContext.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →