R RenderComp
remotion audio music voice-over tutorial

Remotion Audio Component: The Complete Guide

Remotion Audio Component: The Complete Guide

Adding audio to a Remotion composition lifts it from a silent animation to a complete video production. Whether you are laying down a background music track, syncing a voice-over narration to animated slides, or adding sound effects timed to specific moments, Remotion’s <Audio> component handles all of it with the same React declarative model you use for visuals.

This guide covers everything: loading audio with staticFile and external URLs, constant and frame-driven volume, trimming with startFrom and endAt, looping, layering multiple tracks, supported formats, and the common pitfalls that cause audio sync issues in rendered output.


The <Audio> Component

<Audio> is imported from the remotion package. No additional installation is needed.

import { Audio } from 'remotion';

At its most basic, you point it at an audio file and it plays from the composition’s beginning:

import { Audio, staticFile } from 'remotion';

export const MyComposition: React.FC = () => {
  return (
    <>
      <Audio src={staticFile('bgm.mp3')} />
      {/* rest of your composition */}
    </>
  );
};

<Audio> is invisible — it renders no DOM element. You can place it anywhere in your component tree; its position in the JSX has no visual effect.


The src Prop: staticFile vs URLs

staticFile

staticFile() is the recommended way to reference audio files bundled with your Remotion project. Place the file in the public/ directory of your Remotion project and reference it with the filename:

your-project/
  public/
    bgm.mp3
    voiceover.mp3
    sfx-pop.wav
  src/
    Root.tsx
    MyComposition.tsx
<Audio src={staticFile('bgm.mp3')} />
<Audio src={staticFile('voiceover.mp3')} />

Files in public/ are served during the development preview and bundled correctly for rendering. This is the correct approach for production compositions.

Remote URLs

You can also pass an HTTPS URL directly:

<Audio src="https://example.com/audio/bgm.mp3" />

During development this works fine. During rendering, Remotion fetches the URL, which means rendering requires network access and the URL must be stable. For production renders, prefer staticFile to avoid dependency on external services.

Dynamic src with inputProps

Because src is just a prop, you can make it dynamic:

interface Props {
  audioFile: string;
}

export const DynamicAudioComp: React.FC<Props> = ({ audioFile }) => {
  return (
    <>
      <Audio src={staticFile(audioFile)} />
    </>
  );
};

This is useful for template systems where the audio track is chosen by the user.


The volume Prop: Constant and Frame-Driven

Constant Volume

Pass a number between 0 (silent) and 1 (full volume):

<Audio src={staticFile('bgm.mp3')} volume={0.4} />

This sets a fixed volume for the entire duration of the audio.

Frame-Driven Volume (Volume Keyframing)

The volume prop also accepts a function: (frame: number) => number. This function is called for every rendered frame and allows you to modulate volume dynamically — fade-ins, fade-outs, ducking under voice-over, or any shape you need.

import { Audio, staticFile, interpolate } from 'remotion';

export const FadeInAudio: React.FC = () => {
  return (
    <Audio
      src={staticFile('bgm.mp3')}
      volume={(frame) =>
        interpolate(frame, [0, 30], [0, 0.5], {
          extrapolateLeft: 'clamp',
          extrapolateRight: 'clamp',
        })
      }
    />
  );
};

Here the volume fades from 0 to 0.5 over the first 30 frames (1 second at 30fps), then stays at 0.5. The extrapolateRight: 'clamp' ensures the volume does not keep rising beyond frame 30.

Volume Fade Out at End

To fade out in the last two seconds of a 150-frame composition:

<Audio
  src={staticFile('bgm.mp3')}
  volume={(frame) =>
    interpolate(frame, [120, 150], [0.5, 0], {
      extrapolateLeft: 'clamp',
      extrapolateRight: 'clamp',
    })
  }
/>

Audio Ducking (Lower Music During Voice-Over)

A classic broadcast technique: reduce the background music when voice-over is present. Here, voice-over runs from frame 30 to frame 120, and the music ducks to 20% during that window:

<Audio
  src={staticFile('bgm.mp3')}
  volume={(frame) =>
    interpolate(
      frame,
      [25, 30, 120, 130],
      [0.6, 0.15, 0.15, 0.6],
      { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }
    )
  }
/>
<Audio src={staticFile('voiceover.mp3')} startFrom={30} />

The four keypoints [25, 30, 120, 130] create a smooth ramp down, a sustain at 15%, and a ramp back up.


Trimming Audio: startFrom and endAt

startFrom

startFrom specifies the frame of the audio file to begin playback from. It trims the beginning of the audio. The value is in frames at the composition’s fps, not milliseconds.

// Skip the first second of audio (at 30fps)
<Audio src={staticFile('bgm.mp3')} startFrom={30} />

This is useful when a music track has a few seconds of intro silence, or when you want to start from a specific beat.

endAt

endAt specifies the frame at which to stop playing the audio. It trims the end.

// Only play the first 3 seconds of audio (frames 0–90 at 30fps)
<Audio src={staticFile('bgm.mp3')} endAt={90} />

Combining Both

// Play from second 2 to second 5 of the audio file
<Audio
  src={staticFile('bgm.mp3')}
  startFrom={60}   // start at 2 seconds (2 × 30fps)
  endAt={150}      // end at 5 seconds (5 × 30fps)
/>

This cuts a 3-second segment from the middle of the audio file, perfect for extracting a specific phrase or musical phrase.

Timing Audio with <Sequence>

To play audio starting at a specific moment in the composition (not just trimming the audio file), wrap <Audio> in a <Sequence>:

<Sequence from={60}>
  <Audio src={staticFile('sfx-pop.wav')} />
</Sequence>

This plays sfx-pop.wav starting at frame 60 of the composition. Inside the sequence, startFrom on <Audio> would be relative to the sequence’s start, not the composition’s global frame.


Looping Audio with <Loop>

The <Loop> component repeats its children for a specified number of iterations, or indefinitely. Wrap <Audio> with <Loop> to create a repeating audio track:

import { Loop, Audio, staticFile } from 'remotion';

export const LoopingBgm: React.FC = () => {
  return (
    // Loop a 6-second track (180 frames at 30fps) 10 times
    <Loop durationInFrames={180} times={10}>
      <Audio src={staticFile('loop-bgm.mp3')} />
    </Loop>
  );
};

If you omit times, the loop runs for the duration of the composition:

<Loop durationInFrames={180}>
  <Audio src={staticFile('loop-bgm.mp3')} />
</Loop>

The durationInFrames prop on <Loop> must match the actual duration of your audio file. If the value is shorter than the file, the audio will be cut off; if it is longer, there will be silence before the next loop starts. For best results, use an audio file that is designed to loop seamlessly (the end flows into the beginning without a click or gap).


Layering Multiple Audio Tracks

You can render as many <Audio> components as you need simultaneously. They mix together in the final render:

export const FullMixComposition: React.FC = () => {
  return (
    <>
      {/* Background music — quiet */}
      <Audio src={staticFile('bgm.mp3')} volume={0.3} />

      {/* Voice-over — full volume, starts at 1 second */}
      <Sequence from={30}>
        <Audio src={staticFile('narration.mp3')} volume={1} />
      </Sequence>

      {/* Sound effect at a specific moment */}
      <Sequence from={90}>
        <Audio src={staticFile('sfx-ding.wav')} volume={0.8} />
      </Sequence>

      {/* Visual layers below */}
      <MySlides />
    </>
  );
};

There is no dedicated mixer component — the mixing is done automatically by the browser’s audio engine during preview and by the underlying audio processing during rendering. Ensure combined volumes do not exceed 1.0 total to avoid clipping artifacts.


The muted Prop

Pass muted={true} to silence an audio track without removing it from the component tree. This is useful during development when you want to temporarily disable audio, or in a player embed where muting is controlled by user preference:

<Audio src={staticFile('bgm.mp3')} volume={0.4} muted={isMuted} />

Supported Audio Formats

Remotion uses a Chromium-based headless browser for rendering. The supported formats are those Chromium supports:

FormatExtensionNotes
MP3.mp3Most widely compatible. Recommended for music and voice-over.
WAV.wavUncompressed. Large file size but no encoding artifacts. Good for short SFX.
AAC.aac / .m4aHigh quality at smaller file size than MP3.
OGG Vorbis.oggOpen format. Fully supported in Chromium.
FLAC.flacLossless. Large files; avoid for web delivery but fine for local renders.
WebM Audio.webmSupported but rarely necessary.

Recommendation: Use .mp3 for music and voice-over (broad compatibility, good quality at 128–320 kbps). Use .wav for short sound effects where precise timing matters.

Avoid: Format-specific features like gapless looping headers, which may behave unexpectedly. Test your loops manually in the Remotion Studio preview before rendering.


<Audio> vs <OffthreadVideo> for Audio

<OffthreadVideo> is Remotion’s component for embedding video files. It renders the video off-thread (using a separate process) to avoid frame-rate issues with the main composition. It also carries an audio track.

If you have a video file whose audio you want to include, use <OffthreadVideo> — it handles both the visual frames and the audio. You do not need a separate <Audio> component for the same file.

// Good: use OffthreadVideo for a video file's audio+video
<OffthreadVideo src={staticFile('intro-clip.mp4')} volume={0.8} />

// Avoid: do not add a separate Audio for the same video file
// (you would get doubled audio)

Use <Audio> for standalone audio files: music tracks, voice-overs, and sound effects.


Avoiding Audio Sync Issues

Sync problems — where audio and visuals are out of time in the rendered output even though they look correct in the preview — are the most common audio complaint in Remotion projects. Here are the causes and solutions.

Issue 1: Frame Rate Mismatch

If your composition is configured at one fps but you calculate timing at a different fps, the audio will be placed at the wrong absolute time.

Solution: Always calculate frame offsets using useVideoConfig().fps, never a hardcoded number.

const { fps } = useVideoConfig();
const voiceoverStart = fps * 2; // 2 seconds in, regardless of fps setting

<Sequence from={voiceoverStart}>
  <Audio src={staticFile('narration.mp3')} />
</Sequence>

Issue 2: Variable Bitrate (VBR) Audio

VBR MP3 files can cause sync drift over long durations because the decoder’s internal time estimation diverges from the actual sample position. This is a known Chromium limitation.

Solution: Convert audio to Constant Bitrate (CBR) before using it in Remotion:

ffmpeg -i input.mp3 -codec:a libmp3lame -b:a 192k -ar 44100 output-cbr.mp3

For WAV files this is not an issue — WAV is inherently CBR (PCM).

Issue 3: Audio Longer Than the Composition

If an <Audio> component’s file is longer than the composition’s durationInFrames and you do not use endAt, the audio will be cut at the composition’s end. This is expected behavior, but if you intend to fade out, you must do it explicitly with a volume callback.

Issue 4: <Audio> Outside Its Parent <Sequence>

When <Audio> is placed inside a <Sequence>, the audio’s start time in the final video is the sequence’s from value plus any startFrom offset. Do not confuse these two: <Sequence from> controls when in the composition the audio begins; startFrom on <Audio> controls where in the audio file playback starts.

Issue 5: Missing pauseWhenBuffering in Player Embeds

In the <Player> component, if audio needs to buffer before playback, the player may proceed visually while the audio lags. Pass pauseWhenBuffering to the <Player> to prevent this:

<Player
  component={MyComposition}
  durationInFrames={300}
  fps={30}
  compositionWidth={1920}
  compositionHeight={1080}
  pauseWhenBuffering
  acknowledgeRemotionLicense
/>

Practical Example: Complete Voice-Over Video

import {
  Audio,
  staticFile,
  Sequence,
  Loop,
  interpolate,
  useVideoConfig,
} from 'remotion';
import { MySlide } from './MySlide';

export const VoiceOverVideo: React.FC = () => {
  const { durationInFrames, fps } = useVideoConfig();

  return (
    <>
      {/* Background music: loop a 4-second track, fade in and out */}
      <Loop durationInFrames={fps * 4}>
        <Audio
          src={staticFile('bgm-loop.mp3')}
          volume={(frame) => {
            const fadeIn = interpolate(frame, [0, fps], [0, 0.25], {
              extrapolateLeft: 'clamp',
              extrapolateRight: 'clamp',
            });
            const fadeOut = interpolate(
              frame,
              [durationInFrames - fps, durationInFrames],
              [0.25, 0],
              { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }
            );
            return Math.min(fadeIn, fadeOut === 0.25 ? Infinity : fadeOut);
          }}
        />
      </Loop>

      {/* Voice-over: starts at 1 second, full volume */}
      <Sequence from={fps}>
        <Audio src={staticFile('narration.mp3')} volume={1} />
      </Sequence>

      {/* Visual slides */}
      <Sequence from={0} durationInFrames={fps * 5}>
        <MySlide title="Introduction" />
      </Sequence>
      <Sequence from={fps * 5} durationInFrames={fps * 5}>
        <MySlide title="Main Point" />
      </Sequence>
    </>
  );
};

FAQ

Q: Can I use <Audio> for audio that starts before the composition begins?

No. <Audio> can only play audio that starts at or after frame 0. If you want to exclude the beginning of an audio file, use the startFrom prop to skip ahead within the file. You cannot make audio start at a negative frame.

Q: What happens if the audio file is shorter than the composition?

The audio plays and then stops. There is no automatic looping — use <Loop> explicitly if you want the track to repeat.

Q: Does Remotion mix audio to stereo automatically?

Yes. The final rendered video’s audio track is mixed to stereo (or the source channel layout) by the encoding pipeline. You do not need to handle downmixing yourself.

Q: How do I sync audio to a specific visual event?

Calculate the frame at which the visual event occurs and place the <Audio> (or its wrapping <Sequence>) at that frame. If the visual event is driven by a spring animation, use measureSpring() to calculate the exact frame at which the animation settles, and use that as the audio’s start frame.

Q: Can I use volume to create a sidechain/pump effect (EDM-style)?

Yes. A pump effect alternates volume rapidly in sync with a beat. Calculate the beat frequency in frames (const beatFrames = fps * (60 / bpm)) and use a modulo-based volume function:

volume={(frame) => {
  const beatPosition = frame % beatFrames;
  return interpolate(beatPosition, [0, beatFrames * 0.1, beatFrames], [0.2, 0.8, 0.2], {
    extrapolateLeft: 'clamp',
    extrapolateRight: 'clamp',
  });
}}

Q: Is there a way to visualize the audio waveform in the composition?

Remotion does not provide built-in waveform visualization. However, you can pre-process an audio file to extract amplitude data (using FFmpeg or a Web Audio API analysis tool), store the data as a JSON array, import it into your composition, and map the values to visual elements. This is a manual process but fully achievable within Remotion’s React model.

Q: Can I record microphone audio and use it directly in Remotion?

Not directly in a composition. Remotion compositions are rendered server-side; they do not have access to browser APIs like getUserMedia. You would record the audio separately, export it as a file, and then use staticFile() to include it in the composition.


Summary

The <Audio> component is Remotion’s clean, declarative interface for adding sound to programmatic video. The key points:

  1. Use staticFile('filename.mp3') for bundled audio files; put them in public/
  2. volume accepts a number (constant) or a function (frame: number) => number (dynamic)
  3. startFrom and endAt trim the audio file (in frames); combine with <Sequence from> to control placement in the composition
  4. Wrap in <Loop durationInFrames={...}> to repeat a track
  5. Layer multiple <Audio> components for music, voice-over, and SFX — they mix automatically
  6. Use CBR-encoded MP3 files to avoid long-form audio sync drift

Explore Remotion video templates with pre-built audio mixing at RenderComp

RenderComp’s library includes templates with professionally structured audio layers — background music with fade-ins, voice-over sync slots, and sound effect placeholders — so you can swap in your own audio files and get a polished result without building the audio timing from scratch.

Now available

Get 1,000+ Remotion Templates

Pay once — no subscription. Lifetime updates. TypeScript-first.

View pricing →