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

> Master Remotion video configurations using the Composition component. Learn to set props like id, component, width, height, fps, and durationInFrames for dynamic video creation.

- Repository: [Remotion/remotion](https://github.com/remotion-dev/remotion)
- Tags: how-to-guide
- Published: 2026-02-15

---

**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`](https://github.com/remotion-dev/remotion/blob/main/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`](https://github.com/remotion-dev/remotion/blob/main/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`](https://github.com/remotion-dev/remotion/blob/main/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:

```tsx
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:

```tsx
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:

```tsx
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:

```tsx
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:

```tsx
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`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/Composition.tsx) | Core `<Composition>` implementation, registration, validation, and portal rendering. | [View on GitHub](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/Composition.tsx) |
| [`packages/core/src/ResolveCompositionConfig.tsx`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/ResolveCompositionConfig.tsx) | Resolves a composition’s video configuration, runs validation, and provides async metadata handling. | [View on GitHub](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/ResolveCompositionConfig.tsx) |
| `packages/core/src/validation/*` | Helper functions (`validateDimension`, `validateFps`, `validateDurationInFrames`, `validateCompositionId`, etc.) that enforce correct video config values. | [Directory listing](https://github.com/remotion-dev/remotion/tree/main/packages/core/src/validation) |
| `packages/docs/docs/composition.mdx` | User-facing documentation for `<Composition>`, including prop table and examples. | [View on GitHub](https://github.com/remotion-dev/remotion/blob/main/packages/docs/docs/composition.mdx) |
| [`packages/core/src/CompositionManagerContext.tsx`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/CompositionManagerContext.tsx) | Stores the list of registered compositions and provides the `registerComposition`/`unregisterComposition` API used by `<Composition>`. | [View on GitHub](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/CompositionManagerContext.tsx) |

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`](https://github.com/remotion-dev/remotion/blob/main/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`](https://github.com/remotion-dev/remotion/blob/main/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`](https://github.com/remotion-dev/remotion/blob/main/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`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/ResolveCompositionConfig.tsx) manages the loading state, ensuring the component only renders after the metadata resolves.