# How Remotion's Composition Lifecycle Works: From Registration to Render

> Understand Remotion's Composition lifecycle: registration, state management, config resolution, and rendering. Learn how Remotion creates your videos efficiently.

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

---

**Remotion's Composition lifecycle involves four main phases: registration with the CompositionManager, state management through React context, video configuration resolution via useResolvedVideoConfig, and conditional rendering through portals for Studio or production renders.**

The `<Composition>` component in the `remotion-dev/remotion` repository serves as the entry point that tells the rendering engine which React component should become a video and how it should be configured. Understanding this lifecycle is essential for debugging registration issues, optimizing render performance, and building custom tooling around Remotion.

## The Four Phases of the Remotion Composition Lifecycle

### Phase 1: Mount and Registration

When a `<Composition>` element renders, the internal `InnerComposition` component (located in [`packages/core/src/Composition.tsx`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/Composition.tsx)) executes a `useEffect` hook that registers the composition with the global `CompositionManager`.

The registration process stores critical metadata including:

- Unique `id` for the composition
- Dimensions (`width`, `height`)
- Frame rate (`fps`)
- Duration in frames
- Default props
- Lazy-loaded component reference

```typescript
// From Composition.tsx - registration effect
useEffect(() => {
  registerComposition({
    id,
    width,
    height,
    fps,
    durationInFrames,
    defaultProps,
    component: lazyComponent
  });
}, [id, width, height, fps, durationInFrames, defaultProps, lazyComponent]);

```

### Phase 2: State Management

The `CompositionManagerProvider` (in [`packages/core/src/CompositionManagerProvider.tsx`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/CompositionManagerProvider.tsx)) maintains the list of registered compositions in React state. This provider exposes setter functions through the `CompositionSetters` context, allowing runtime registration and unregistration.

Key capabilities include:

- **Dynamic registration**: Studio UI can add compositions at runtime
- **State synchronization**: Shared state between Studio and render pipeline
- **Validation**: Ensures unique IDs and valid video configurations

```typescript
// CompositionManagerProvider.tsx structure
const [compositions, setCompositions] = useState<CompositionState[]>([]);

const registerComposition = useCallback((composition: CompositionState) => {
  setCompositions(prev => [...prev, composition]);
}, []);

const unregisterComposition = useCallback((id: string) => {
  setCompositions(prev => prev.filter(c => c.id !== id));
}, []);

```

### Phase 3: Video Configuration Resolution

Before rendering begins, the engine must resolve and validate the video configuration. The `useResolvedVideoConfig` hook (in [`packages/core/src/ResolveCompositionConfig.tsx`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/ResolveCompositionConfig.tsx)) performs this resolution.

This hook:

1. Retrieves the selected composition from the manager
2. Validates dimensions, fps, and duration
3. Merges default props with editor-provided overrides
4. Returns a `VideoConfigState` object indicating `success`, `loading`, or `error`

```typescript
// Using the resolution hook
import {useResolvedVideoConfig} from 'remotion';

const MyComponent = () => {
  const config = useResolvedVideoConfig('MyComposition');
  
  if (config.type === 'success') {
    console.log(config.result.durationInFrames);
  }
};

```

### Phase 4: Render Execution

The final phase differs based on the execution environment. The `InnerComposition` component checks `environment.isStudio` and `environment.isRendering` to determine the render path.

**Studio Mode** (`environment.isStudio === true`):
- Renders inside a portal (`portalNode()`)
- Displays a `<Loading />` fallback while the component initializes
- Enables hot reloading and interactive editing

**Production Render** (`environment.isRendering === true`):
- Uses the same portal mechanism but with a `<Fallback />` component
- Delays rendering until the lazy component is fully loaded
- Optimizes for headless rendering performance

```typescript
// Conditional rendering logic from Composition.tsx
if (environment.isStudio) {
  return createPortal(
    <Suspense fallback={<Loading />}>
      <ActualComponent {...resolvedProps} />
    </Suspense>,
    portalNode()
  );
}

if (environment.isRendering) {
  return createPortal(
    <Suspense fallback={<Fallback />}>
      <ActualComponent {...resolvedProps} />
    </Suspense>,
    portalNode()
  );
}

```

## Cleanup and Unmounting

When a `<Composition>` unmounts—whether through hot module replacement, navigation changes, or component tree updates—the cleanup function returned from the registration `useEffect` executes `unregisterComposition`.

This process:

- Removes the composition entry from the manager's state array
- Frees memory associated with the component reference
- Prevents stale configurations from affecting subsequent renders

```typescript
// Cleanup from Composition.tsx
useEffect(() => {
  registerComposition(compositionData);
  
  return () => {
    unregisterComposition(id);
  };
}, [id, /* other deps */]);

```

## Key Files in the Composition Lifecycle

Understanding the source structure helps when debugging registration issues or extending Remotion's functionality:

| File | Role |
|------|------|
| [`packages/core/src/Composition.tsx`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/Composition.tsx) | Exported `<Composition>` component; handles registration, unregistration, and conditional portal rendering |
| [`packages/core/src/CompositionManagerProvider.tsx`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/CompositionManagerProvider.tsx) | Global state provider for composition registry; exposes setter functions |
| [`packages/core/src/CompositionManagerContext.tsx`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/CompositionManagerContext.tsx) | Context definitions for read-only manager access and mutable setters |
| [`packages/core/src/ResolveCompositionConfig.tsx`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/ResolveCompositionConfig.tsx) | Validates and resolves video configurations via `useResolvedVideoConfig` |
| [`packages/core/src/CompositionManager.tsx`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/CompositionManager.tsx) | Type definitions and refs used by the manager (e.g., `compositionsRef`) |

## Practical Implementation Example

Here's a complete example showing how the lifecycle works in practice:

```tsx
// MyVideo.tsx
import {Composition} from 'remotion';
import {MyScene} from './MyScene';

export const MyVideo = () => {
  return (
    <Composition
      id="MainVideo"
      component={MyScene}
      width={1920}
      height={1080}
      fps={30}
      durationInFrames={300}
      defaultProps={{title: 'Hello World'}}
    />
  );
};

```

When this JSX executes:

1. **Mount**: `InnerComposition` registers "MainVideo" with the `CompositionManager`
2. **Resolution**: When rendering starts, `useResolvedVideoConfig("MainVideo")` validates the 1920x1080 configuration and merges props
3. **Render**: The engine creates a portal containing `<MyScene title="Hello World" />` using the appropriate fallback for the current environment
4. **Cleanup**: If the component unmounts, `unregisterComposition("MainVideo")` removes it from the global registry

## Summary

- **Registration Phase**: The `<Composition>` component registers itself with the global `CompositionManager` via `registerComposition` in [`packages/core/src/Composition.tsx`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/Composition.tsx), storing metadata like dimensions, fps, and the component reference.

- **State Management**: The `CompositionManagerProvider` maintains the registry in React state and exposes mutation functions through the `CompositionSetters` context, enabling dynamic composition management in the Studio UI.

- **Configuration Resolution**: Before rendering, `useResolvedVideoConfig` in [`packages/core/src/ResolveCompositionConfig.tsx`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/ResolveCompositionConfig.tsx) validates video parameters and merges default props with overrides, returning a structured `VideoConfigState`.

- **Environment-Specific Rendering**: The system uses React portals to render compositions differently in Studio mode (with `<Loading />` fallback) versus production rendering (with `<Fallback />`), ensuring proper initialization before the actual component executes.

- **Cleanup**: Unmounting triggers `unregisterComposition` to remove the composition from global state, preventing memory leaks and stale configuration issues.

## Frequently Asked Questions

### How does Remotion handle composition registration during fast refresh?

During development with React Fast Refresh, components may remount frequently. The `useEffect` hook in `InnerComposition` handles this by calling `unregisterComposition` in its cleanup function and immediately re-registering with the same ID. This ensures the `CompositionManager` always has the latest component reference and props without duplicate entries.

### Can I dynamically add or remove compositions at runtime?

Yes, through the `CompositionSetters` context exposed by `CompositionManagerProvider`. The Studio UI uses these setters to manage compositions dynamically. You can import `useContext(CompositionSetters)` and call `registerComposition` or `unregisterComposition` programmatically, though this is primarily intended for advanced tooling rather than typical video components.

### What happens if video configuration validation fails?

The `useResolvedVideoConfig` hook returns a `VideoConfigState` with a `type` property indicating `success`, `loading`, or `error`. If validation fails (for example, if dimensions are invalid or the composition ID doesn't exist), the hook returns an error state with a descriptive message. The rendering engine checks this state and prevents invalid configurations from reaching the render pipeline.

### How does Remotion differentiate between Studio and production rendering environments?

The system checks `environment.isStudio` and `environment.isRendering` boolean flags. In Studio mode (`isStudio`), compositions render with a `<Loading />` fallback that supports hot reloading and interactive editing. In production rendering (`isRendering`), the same portal mechanism uses a `<Fallback />` component optimized for headless execution, ensuring the component is fully loaded before the render begins.