← Back to Home

How to Register Compositions in Remotion Root.tsx

Updated January 14, 2026
remotionroot.tsxcomposition registrationauto-generation

Registering Compositions in Remotion Root.tsx

Remotion requires all compositions to be registered in Root.tsx using the <Composition> component.

Manual Registration

// src/Root.tsx
import { Composition } from 'remotion';
import { Article6564191 } from './compositions/6564191';
import { Article6564192 } from './compositions/6564192';

export const RemotionRoot: React.FC = () => {
  return (
    <>
      <Composition
        id="Article6564191"
        component={Article6564191}
        durationInFrames={1446}
        fps={30}
        size={{ width: 1080, height: 1920 }}
      />
      <Composition
        id="Article6564192"
        component={Article6564192}
        durationInFrames={1200}
        fps={30}
        size={{ width: 1080, height: 1920 }}
      />
    </>
  );
};

Auto-Generation (Recommended)

Scan for all composition files and generate Root.tsx automatically:

import fs from 'fs';
import path from 'path';

interface ArticleMetadata {
  id: string;
  compositionPath: string;
  durationInFrames: number;
}

function findAllCompositionFiles(): ArticleMetadata[] {
  const compositionsDir = 'src/compositions';
  const files = fs.readdirSync(compositionsDir);

  return files
    .filter(file => file.endsWith('.tsx'))
    .map(file => {
      const articleId = path.basename(file, '.tsx');
      const filePath = path.join(compositionsDir, file);
      const content = fs.readFileSync(filePath, 'utf-8');

      // Extract duration from config export
      const durationMatch = content.match(/durationInFrames:\s*(\d+)/);
      const durationInFrames = durationMatch ? parseInt(durationMatch[1], 10) : 0;

      return {
        id: articleId,
        compositionPath: `./compositions/${file}`,
        durationInFrames,
      };
    });
}

Generate Root.tsx

export function generateRootFile(): void {
  const articles = findAllCompositionFiles();

  const imports = articles.map(a =>
    `import { Article${a.id} } from './compositions/${a.id}';`
  ).join('\n');

  const compositions = articles.map(a =>
    `  <Composition
    id="Article${a.id}"
    component={Article${a.id}}
    durationInFrames={a.durationInFrames}
    fps={30}
    size={{ width: 1080, height: 1920 }}
  />`
  ).join('\n');

  const rootContent = `
import { Composition } from 'remotion';
${imports}

export const RemotionRoot: React.FC = () => {
  return (
    <>
${compositions}
    </>
  );
};
`;

  fs.writeFileSync('src/Root.tsx', rootContent);
}

Complete Root Generator

export class RootGenerator {
  generateRoot(articles: Array<{ id: string; durationInFrames: number }>): void {
    const imports = articles.map(article =>
      `import { Article${article.id} } from './compositions/${article.id}';`
    ).join('\n');

    const compositions = articles.map(article =>
      `  <Composition
    id="Article${article.id}"
    component={Article${article.id}}
    durationInFrames={article.durationInFrames}
    fps={30}
    size={{ width: 1080, height: 1920 }}
  />`
    ).join('\n');

    const content = `
import { Composition } from 'remotion';
${imports}

export const RemotionRoot: React.FC = () => {
  return (
    <>
${compositions}
    </>
  );
};
`;

    fs.writeFileSync('src/Root.tsx', content);
  }
}

Usage

const rootGenerator = new RootGenerator();

// After generating a new composition
rootGenerator.generateRoot([
  { id: '6564191', durationInFrames: 1446 },
  { id: '6564192', durationInFrames: 1200 },
  // ... all articles with compositions
]);

Video Format

Standard configuration for vertical video (YouTube Shorts):

{
  fps: 30,
  size: { width: 1080, height: 1920 },  // 9:16 aspect ratio
}