# Using continueRender for Async Operations in Remotion Compositions

> Master async operations in Remotion using continueRender. Learn how to delay rendering and gracefully resume your compositions after async tasks finish for smoother video production.

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

---

**Call `delayRender()` before starting asynchronous work to generate a unique handle, then invoke `continueRender(handle)` when the operation completes to unblock the Remotion render pipeline.**

When building video compositions with the remotion-dev/remotion framework, components often need to pause rendering while fetching data, loading fonts, or processing media. The `continueRender` function works in tandem with `delayRender` to manage these asynchronous operations by signaling exactly when the composition is ready to proceed.

## How delayRender and continueRender Work Under the Hood

The mechanism relies on a handle-based tracking system implemented in [`packages/core/src/delay-render.ts`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/delay-render.ts). When you call `delayRender()`, the internal `delayRenderInternal` function generates a random numeric handle, stores it in `window.remotion_delayRenderHandles`, and sets `remotion_renderReady` to `false` (lines 71-78). This signals the Remotion engine to pause frame rendering.

When the asynchronous work completes, calling `continueRender(handle)` triggers `continueRenderInternal` (lines 62-94). This function removes the handle from the collection, clears any pending timeout, and—crucially—sets `remotion_renderReady` to `true` only when no handles remain. The renderer then proceeds to the next frame.

## Implementing Async Operations with continueRender

### Creating a Delay Handle

Before initiating any asynchronous work, generate a handle by calling `delayRender()`. Optionally pass a descriptive label and timeout configuration:

```typescript
import { delayRender } from 'remotion';

const handle = delayRender('loading-font', {
  timeoutInMilliseconds: 60000
});

```

### Resolving with continueRender

Once the async operation completes, pass the handle to `continueRender()` to unblock the renderer:

```typescript
import { continueRender } from 'remotion';

await fetch('https://example.com/data.json');
continueRender(handle);

```

### Handling Timeouts and Errors

If `continueRender()` is never called, a default 30-second timeout triggers `cancelRenderInternal`, aborting the render with an error. Handle failures explicitly using `cancelRender()`:

```typescript
import { cancelRender } from 'remotion';

try {
  await riskyAsyncOperation();
  continueRender(handle);
} catch (error) {
  cancelRender(error);
}

```

## Using the useDelayRender Hook for Scoped Operations

For cleaner component integration, Remotion provides the `useDelayRender()` hook in [`packages/core/src/use-delay-render.tsx`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/use-delay-render.tsx) (lines 28-56). This hook returns scoped versions of the delay and continue functions that automatically manage the handle lifecycle within your component's React tree:

```tsx
import { useDelayRender } from 'remotion';
import React from 'react';

export const MyComp: React.FC = () => {
  const { delayRender, continueRender, cancelRender } = useDelayRender();
  const handle = delayRender('load-font');

  React.useEffect(() => {
    const loadFont = async () => {
      try {
        await fetch('https://example.com/font.woff2');
        continueRender(handle);
      } catch (e) {
        cancelRender(e);
      }
    };
    loadFont();
  }, [handle, continueRender, cancelRender]);

  return <div>Content</div>;
};

```

## Common Use Cases for Async Operations in Remotion

**Fetching Remote Data**: Pause rendering while retrieving JSON configuration or dynamic content from APIs before the first frame renders.

**Loading Custom Fonts**: Ensure web fonts or local font files referenced via `staticFile()` are fully loaded before text appears in the composition.

**Decoding Video Frames**: Wait for off-thread video processing or WebGL texture initialization to complete before continuing the render pipeline.

## Summary

- **`delayRender()`** generates a unique numeric handle and pauses the Remotion render pipeline by setting internal readiness flags in [`packages/core/src/delay-render.ts`](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/delay-render.ts).
- **`continueRender(handle)`** removes the specific handle from the tracking collection and resumes rendering only when all handles are cleared.
- The **`useDelayRender()`** hook provides a scoped, React-friendly alternative to the global API for component-level async management.
- Default timeouts (30 seconds) protect against infinite stalls, customizable via the `timeoutInMilliseconds` option.

## Frequently Asked Questions

### What happens if continueRender is never called?

If `continueRender()` is not invoked within the default 30-second timeout window, Remotion automatically calls the internal `cancelRenderInternal` function, aborting the render and throwing an error indicating which handle failed to resolve. You can extend this timeout using the `timeoutInMilliseconds` option in `delayRender()`.

### Can I use multiple delayRender handles simultaneously?

Yes. Remotion supports multiple concurrent handles. The render pipeline only resumes when `continueRender()` has been called for every active handle and the `window.remotion_delayRenderHandles` collection is empty. This allows parallel async operations across different components or resources.

### How do I customize the timeout duration?

Pass a configuration object as the second argument to `delayRender()` with the `timeoutInMilliseconds` property. For example: `delayRender('slow-api', { timeoutInMilliseconds: 120000 })` sets a 2-minute timeout instead of the default 30 seconds.

### Should I use the hook or the global functions?

Prefer **`useDelayRender()`** for React components because it scopes handle management to your component lifecycle and automatically cleans up resources. Use the global **`delayRender()`** and **`continueRender()`** functions only when working outside React components or in utility modules where hook context is unavailable.