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

> Learn how to define a video composition in Remotion using the Composition component. Configure width, height, FPS, and duration for your video project.

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

---

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

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

```

*Source: [`packages/core/src/Composition.tsx`](https://github.com/remotion-dev/remotion/blob/main/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:

- **[`packages/core/src/Composition.tsx`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/Composition.tsx)**: Main component handling registration, validation, lazy loading, and portal rendering.
- **[`packages/core/src/CompositionManagerContext.tsx`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/CompositionManagerContext.tsx)**: Provides the `registerComposition` and `unregisterComposition` functions.
- **[`packages/core/src/CompositionManager.tsx`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/CompositionManager.tsx)**: Stores the registry of all compositions and resolves them during rendering.
- **[`packages/core/src/ResolveCompositionConfig.tsx`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/ResolveCompositionConfig.tsx)**: Merges calculated metadata with explicit configuration.
- **[`packages/core/src/validation/validate-composition-id.ts`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/validation/validate-composition-id.ts)**: Ensures the `id` prop is URL-safe.
- **[`packages/core/src/validation/validate-default-props.ts`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/validation/validate-default-props.ts)**: Validates `defaultProps` against optional Zod schemas.

## 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:

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

```tsx
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`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/validation/validate-default-props.ts) validates props against this schema before registration:

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

```tsx
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`](https://github.com/remotion-dev/remotion/blob/main/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`](https://github.com/remotion-dev/remotion/blob/main/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`](https://github.com/remotion-dev/remotion/blob/main/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`](https://github.com/remotion-dev/remotion/blob/main/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`](https://github.com/remotion-dev/remotion/blob/main/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`](https://github.com/remotion-dev/remotion/blob/main/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`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/validation/validate-default-props.ts). Without a schema, you lose runtime type checking but gain flexibility for rapid prototyping.