Remotion Best Practices
Composition Setup
- Always define
width, height, durationInFrames, and fps explicitly on <Composition>.
- Use
fps: 30 for most content; fps: 60 for motion-heavy or gaming content.
- Keep compositions focused — split long videos into multiple compositions and stitch with
<Series> or <Sequence>.
<Composition
id="MyVideo"
component={MyVideo}
durationInFrames={150}
fps={30}
width={1920}
height={1080}
/>
Timing & Animation
- Use
useCurrentFrame() and interpolate() for all animations — never use CSS transitions or setTimeout.
- Clamp
interpolate() output with extrapolateLeft: "clamp" and extrapolateRight: "clamp" to avoid runaway values.
- Use
<Sequence from={} durationInFrames={}> to offset and scope child timing.
const frame = useCurrentFrame();
const opacity = interpolate(frame, [0, 20], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
Assets
- Wrap all static assets with
staticFile() — never use raw relative paths.
- Preload audio and video with
prefetch() or <Preload> to avoid rendering gaps.
- Use
<OffthreadVideo> instead of <Video> for better frame-accurate rendering during export.
import { staticFile } from "remotion";
<Img src={staticFile("logo.png")} />
<OffthreadVideo src={staticFile("clip.mp4")} />
Audio
- Use
<Audio> with startFrom and endAt (in frames) to trim clips.
- Set
volume as a function of frame for fades: volume={(f) => interpolate(f, [0, 10], [0, 1])}.
- Use
<Sequence> to offset audio start time rather than manipulating startFrom with manual offsets.
Performance
- Avoid expensive computations inside render — memoize with
useMemo.
- Don't load or fetch data at render time; pass all data as composition
defaultProps.
- Use
delayRender / continueRender for async data fetching before rendering starts.
const handle = delayRender();
useEffect(() => {
fetchData().then((data) => {
setData(data);
continueRender(handle);
});
}, []);
Props & Schema
- Define a Zod schema for composition props and pass it via the
schema prop on <Composition>.
- This enables type-safe props in the Remotion Studio UI and CLI.
import { z } from "zod";
const schema = z.object({ title: z.string(), color: z.string() });
<Composition schema={schema} defaultProps={{ title: "Hello", color: "#fff" }} />
Rendering
- Use
npx remotion render for single renders; use Lambda (@remotion/lambda) for parallel/cloud rendering.
- Pass
--concurrency to tune CPU usage for local renders.
- For programmatic rendering, use
renderMedia() from @remotion/renderer.
Common Pitfalls
- Non-determinism: never use
Math.random(), Date.now(), or new Date() — output must be frame-deterministic.
- Font loading: use
loadFont() from @remotion/google-fonts or call delayRender until custom fonts are ready.
- Spring animations: use
spring() from Remotion, not from react-spring or framer-motion — those are not frame-deterministic.
- Missing continueRender: always pair every
delayRender() with a continueRender(), or rendering will hang.
1---2name: remotion-best-practices3description: Best practices for building videos with Remotion (React-based video framework)4---56# Remotion Best Practices78## Composition Setup910- Always define `width`, `height`, `durationInFrames`, and `fps` explicitly on `<Composition>`.11- Use `fps: 30` for most content; `fps: 60` for motion-heavy or gaming content.12- Keep compositions focused — split long videos into multiple compositions and stitch with `<Series>` or `<Sequence>`.1314```tsx15<Composition16 id="MyVideo"17 component={MyVideo}18 durationInFrames={150}19 fps={30}20 width={1920}21 height={1080}22/>23```2425## Timing & Animation2627- Use `useCurrentFrame()` and `interpolate()` for all animations — never use CSS transitions or `setTimeout`.28- Clamp `interpolate()` output with `extrapolateLeft: "clamp"` and `extrapolateRight: "clamp"` to avoid runaway values.29- Use `<Sequence from={} durationInFrames={}>` to offset and scope child timing.3031```tsx32const frame = useCurrentFrame();33const opacity = interpolate(frame, [0, 20], [0, 1], {34 extrapolateLeft: "clamp",35 extrapolateRight: "clamp",36});37```3839## Assets4041- Wrap all static assets with `staticFile()` — never use raw relative paths.42- Preload audio and video with `prefetch()` or `<Preload>` to avoid rendering gaps.43- Use `<OffthreadVideo>` instead of `<Video>` for better frame-accurate rendering during export.4445```tsx46import { staticFile } from "remotion";47<Img src={staticFile("logo.png")} />48<OffthreadVideo src={staticFile("clip.mp4")} />49```5051## Audio5253- Use `<Audio>` with `startFrom` and `endAt` (in frames) to trim clips.54- Set `volume` as a function of frame for fades: `volume={(f) => interpolate(f, [0, 10], [0, 1])}`.55- Use `<Sequence>` to offset audio start time rather than manipulating `startFrom` with manual offsets.5657## Performance5859- Avoid expensive computations inside render — memoize with `useMemo`.60- Don't load or fetch data at render time; pass all data as composition `defaultProps`.61- Use `delayRender` / `continueRender` for async data fetching before rendering starts.6263```tsx64const handle = delayRender();65useEffect(() => {66 fetchData().then((data) => {67 setData(data);68 continueRender(handle);69 });70}, []);71```7273## Props & Schema7475- Define a Zod schema for composition props and pass it via the `schema` prop on `<Composition>`.76- This enables type-safe props in the Remotion Studio UI and CLI.7778```tsx79import { z } from "zod";80const schema = z.object({ title: z.string(), color: z.string() });81<Composition schema={schema} defaultProps={{ title: "Hello", color: "#fff" }} />82```8384## Rendering8586- Use `npx remotion render` for single renders; use Lambda (`@remotion/lambda`) for parallel/cloud rendering.87- Pass `--concurrency` to tune CPU usage for local renders.88- For programmatic rendering, use `renderMedia()` from `@remotion/renderer`.8990## Common Pitfalls9192- **Non-determinism**: never use `Math.random()`, `Date.now()`, or `new Date()` — output must be frame-deterministic.93- **Font loading**: use `loadFont()` from `@remotion/google-fonts` or call `delayRender` until custom fonts are ready.94- **Spring animations**: use `spring()` from Remotion, not from `react-spring` or `framer-motion` — those are not frame-deterministic.95- **Missing continueRender**: always pair every `delayRender()` with a `continueRender()`, or rendering will hang.