# Optimizing OffthreadVideo Performance in Remotion for Long Videos

> Boost Remotion OffthreadVideo performance for long videos. Optimize frame cache and compositor threads to eliminate rendering bottlenecks and ensure smooth playback.

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

---

**Increase the frame cache size to 30–50% of available RAM and allocate 1–4 compositor threads per CPU core to prevent frame extraction bottlenecks when rendering long videos with Remotion's OffthreadVideo component.**

The `OffthreadVideo` component in the remotion-dev/remotion repository renders video frames on a separate process to keep the main thread responsive. For long videos, this off-thread architecture can become a bottleneck when extracting thousands of frames on-the-fly, requiring specific tuning of cache sizes and worker threads to maintain smooth rendering performance.

## How OffthreadVideo Processes Long Videos

Remotion's off-thread architecture moves heavy video decoding work away from the main React render thread. Understanding this pipeline is essential for diagnosing performance issues in long renders.

### Step 1: Proxy URL Generation

During server-side rendering, `OffthreadVideoForRendering` constructs a proxy URL pointing to a local HTTP server. This URL includes `src`, `time`, `transparent`, and `toneMapped` query parameters that tell the compositor exactly how to extract the frame.

In [`packages/core/src/video/offthread-video-source.ts`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/video/offthread-video-source.ts), the `getOffthreadVideoSource` function generates these URLs:

```typescript
// packages/core/src/video/offthread-video-source.ts
export const getOffthreadVideoSource = (options: {
  src: string;
  time: number;
  transparent: boolean;
  toneMapped: boolean;
}) => {
  // Returns: http://localhost:<port>/proxy?src=...&time=...&transparent=...
};

```

### Step 2: Asset Download and Caching

Before extracting frames, the server ensures the video file is cached locally. The `downloadAsset` function in [`packages/renderer/src/assets/download-and-map-assets-to-file.ts`](https://github.com/remotion-dev/remotion/blob/main/packages/renderer/src/assets/download-and-map-assets-to-file.ts) downloads the source video once per render run, storing it on disk for the compositor to access.

### Step 3: Frame Extraction and Parallel Processing

The `startOffthreadVideoServer` in [`packages/renderer/src/offthread-video-server.ts`](https://github.com/remotion-dev/remotion/blob/main/packages/renderer/src/offthread-video-server.ts) receives proxy requests and forwards them to the compositor. The compositor executes the `ExtractFrame` command, which can run across multiple parallel workers controlled by the `offthreadVideoThreads` option.

```typescript
// Inside offthread-video-server.ts
compositor.executeCommand('ExtractFrame', {
  src: localAssetPath,
  time: requestedTime,
  transparent: query.transparent,
});

```

### Step 4: Frame Cache Management

The compositor maintains an in-memory frame cache whose size is controlled by the `offthreadVideoCacheSizeInBytes` option. By default, this cache uses half of available system memory, but for long videos you should tune this explicitly via the `--offthreadvideo-cache-size-in-bytes` CLI flag or `setOffthreadVideoCacheSizeInBytes` API.

## Identifying Performance Bottlenecks in Long Video Renders

Long videos amplify specific architectural constraints. Recognizing these symptoms helps you apply the correct optimization.

| Symptom | Root Cause | Solution |
|---------|------------|----------|
| **Long initial pause before first frame** | Compositor cache is cold; initial asset download is slow | Pre-warm cache or increase `delayRenderTimeoutInMilliseconds` |
| **Frequent "Server returned status 500" errors** | Cache too small causing frame eviction and recomputation | Increase `offthreadVideoCacheSizeInBytes` to 30-50% of RAM |
| **High CPU usage with low throughput** | Insufficient parallel workers for frame extraction | Increase `offthreadVideoThreads` to 1-4 per CPU core |
| **"Failed to fetch... low disk space"** | Temporary asset storage exhausted | Clean CI runner disk or reduce concurrent renders |
| **Out-of-memory crashes** | Cache size exceeds available RAM | Set cache size explicitly below system memory limits |

## Tuning OffthreadVideo for Maximum Performance

Remotion exposes several configuration options to optimize the off-thread rendering pipeline. Adjust these based on your hardware and video length.

### Frame Cache Size

The `offthreadVideoCacheSizeInBytes` option controls how many extracted frames remain in memory. For long videos, set this to **30–50% of available RAM** to minimize recomputation without causing swapping.

```typescript
// remotion.config.ts
import {setOffthreadVideoCacheSizeInBytes} from 'remotion';

// 12 GB cache for a 32 GB machine
setOffthreadVideoCacheSizeInBytes(12 * 1024 * 1024 * 1024);

```

CLI override:

```bash
bunx remotion render MyComp.tsx --offthreadvideo-cache-size-in-bytes=12884901888

```

### Compositor Worker Threads

The `offthreadVideoThreads` option sets the number of parallel workers extracting frames. The optimal range is **1–4 threads per CPU core**, depending on other system load.

```typescript
// remotion.config.ts
import {setOffthreadVideoThreads} from 'remotion';

setOffthreadVideoThreads(8);

```

CLI usage:

```bash
bunx remotion render MyComp.tsx --offthreadvideo-threads=8

```

### Component-Level Optimizations

Use the `pauseWhenBuffering` prop to prevent CPU saturation when the cache empties. Keep this **enabled** for long renders.

```tsx
<OffthreadVideo
  src="long-video.mp4"
  pauseWhenBuffering  // Prevents busy-waiting when cache is cold
/>

```

Disable `transparent` unless you need an alpha channel. This switches output from PNG (RGBA) to BMP (RGB), reducing memory pressure and CPU overhead.

```tsx
<OffthreadVideo
  src="long-video.mp4"
  transparent={false}  // Uses faster BMP format
/>

```

### Network and Timeout Settings

For CI environments with limited bandwidth, increase `delayRenderTimeoutInMilliseconds` and `delayRenderRetries`:

```tsx
<OffthreadVideo
  src="https://example.com/long-video.mp4"
  delayRenderTimeoutInMilliseconds={60000}  // 60 seconds
  delayRenderRetries={3}
/>

```

## Practical Implementation Guide

Follow these steps to optimize a long video render:

1. **Configure the frame cache** in [`remotion.config.ts`](https://github.com/remotion-dev/remotion/blob/main/remotion.config.ts):

   ```typescript
   import {setOffthreadVideoCacheSizeInBytes} from 'remotion';
   
   // Allocate 8GB for a 16GB machine
   setOffthreadVideoCacheSizeInBytes(8 * 1024 * 1024 * 1024);
   ```

2. **Set worker threads** based on your CPU:

   ```typescript
   import {setOffthreadVideoThreads} from 'remotion';
   
   setOffthreadVideoThreads(4);
   ```

3. **Render with CLI overrides** for one-off tuning:

   ```bash
   bunx remotion render MyVideo.tsx \
     --offthreadvideo-cache-size-in-bytes=10737418240 \
     --offthreadvideo-threads=6 \
     out/optimized.mp4
   ```

4. **Optimize the component** by disabling transparency and enabling buffering:

   ```tsx
   <OffthreadVideo
     src="file:///assets/long-movie.mp4"
     transparent={false}
     pauseWhenBuffering
   />
   ```

## Common Pitfalls When Optimizing OffthreadVideo

Avoid these mistakes that degrade performance or cause failures:

* **Never set cache size to 0** – The validator in [`packages/renderer/src/options/offthreadvideo-cache-size.tsx`](https://github.com/remotion-dev/remotion/blob/main/packages/renderer/src/options/offthreadvideo-cache-size.tsx) throws `Expected a positive number`.
* **Do not use OffthreadVideo in client-side rendering** – The component checks `environment.isClientSideRendering` in [`packages/core/src/video/OffthreadVideoForRendering.tsx`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/video/OffthreadVideoForRendering.tsx) and throws an error. Use `<Video>` from `@remotion/media` for preview mode.
* **Avoid large transparent videos** – PNG frames with alpha channels can exceed 10 MiB each, causing excessive memory pressure and cache thrashing.
* **Don't ignore disk space** – The asset download in [`packages/renderer/src/assets/download-and-map-assets-to-file.ts`](https://github.com/remotion-dev/remotion/blob/main/packages/renderer/src/assets/download-and-map-assets-to-file.ts) requires sufficient local storage. CI runners often fail with "low disk space" errors on long videos.

## Summary

Optimizing OffthreadVideo performance in Remotion for long videos requires tuning the frame cache, parallel worker threads, and component props:

* **Set `offthreadVideoCacheSizeInBytes` to 30–50% of RAM** to minimize frame recomputation without causing out-of-memory crashes.
* **Configure `offthreadVideoThreads` to 1–4 per CPU core** to maximize parallel frame extraction throughput.
* **Disable `transparent` when alpha channels are unnecessary** to switch from PNG to faster BMP rendering.
* **Keep `pauseWhenBuffering` enabled** to prevent CPU saturation when the cache empties during long renders.
* **Monitor disk space and network timeouts** to prevent asset download failures on CI systems.

## Frequently Asked Questions

### How does OffthreadVideo differ from the standard Video component in Remotion?

The standard `<Video>` component from `@remotion/media` runs in the browser environment and decodes frames on the main thread, which causes UI freezing during long renders. `OffthreadVideo` delegates frame extraction to a separate compositor process via an HTTP proxy server, enabling parallel decoding and caching while keeping the React render thread responsive.

### What is the optimal cache size for rendering videos longer than 30 minutes?

For videos longer than 30 minutes, set `offthreadVideoCacheSizeInBytes` to approximately **30–50% of your system's RAM**. For example, on a 32 GB machine, allocate 12–16 GB to the cache. This prevents the compositor from evicting frequently used frames while leaving sufficient memory for the operating system and Remotion's renderer.

### Why does my render fail with "Server returned status 500" when using OffthreadVideo?

HTTP 500 errors from the offthread video server typically indicate that the **frame cache is too small** for your video length, causing the compositor to evict frames and fail to recompute them under memory pressure. Increase `--offthreadvideo-cache-size-in-bytes` to at least 30% of your RAM, or check that your disk has sufficient space for the asset download cache in [`packages/renderer/src/assets/download-and-map-assets-to-file.ts`](https://github.com/remotion-dev/remotion/blob/main/packages/renderer/src/assets/download-and-map-assets-to-file.ts).

### Can I use OffthreadVideo during preview development in the browser?

No, `OffthreadVideo` is **strictly for server-side rendering** and will throw an error if used in client-side rendering environments. The component explicitly checks `environment.isClientSideRendering` in [`packages/core/src/video/OffthreadVideoForRendering.tsx`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/video/OffthreadVideoForRendering.tsx). For browser previews, use the standard `<Video>` component from `@remotion/media`, which renders on the main thread but is suitable for development workflows.