Documentation · API reference · Migration guide
A small, typed Node.js wrapper around the FFmpeg and ffprobe command-line tools. It keeps the
original ffmpeg package API—Promise or callback construction, chainable setters, conversion,
frame extraction, audio extraction, and watermarks—while using modern Node.js primitives.
- Node.js 24 or newer
ffmpegandffprobeonPATH, or explicit executable paths
The package intentionally does not download binaries. This keeps installation small and lets the application choose the FFmpeg build and codecs it needs.
npm install ffmpegimport ffmpeg from 'ffmpeg';
const video = await ffmpeg('/media/input.mp4');
video.on('progress', ({ percent, time }) => {
console.log(`${percent?.toFixed(1)}% (${time}s)`);
});
await video
.setVideoCodec('libx264')
.setVideoBitRate(2_000)
.setAudioCodec('aac')
.setAudioBitRate(192)
.setVideoSize('1280x?', true, true, 'black')
.save('/media/output.mp4');CommonJS remains callable, as in 0.0.4:
const ffmpeg = require('ffmpeg');
const video = await new ffmpeg('/media/input.mp4');
await video.setVideoCodec('copy').setAudioCodec('copy').save('/media/copy.mp4');The legacy callback API also remains available:
new ffmpeg('/media/input.mp4', (error, video) => {
if (error) return console.error(error);
video.save('/media/output.mp4', (saveError, output) => {
if (saveError) console.error(saveError);
else console.log(output);
});
});For new TypeScript code, the named factory is the clearest form:
import { create } from 'ffmpeg';
const video = await create('/media/input.mp4', {
timeout: 120_000,
overwrite: true,
});Set paths globally for legacy applications:
ffmpeg.bin = '/opt/ffmpeg/bin/ffmpeg';
ffmpeg.ffprobeBin = '/opt/ffmpeg/bin/ffprobe';Or per operation:
await ffmpeg('/media/input.mp4', {
ffmpegPath: '/opt/ffmpeg/bin/ffmpeg',
ffprobePath: '/opt/ffmpeg/bin/ffprobe',
});When an absolute ffmpegPath is supplied and ffprobePath is omitted, a sibling ffprobe
executable is inferred. URLs such as HTTP, HTTPS, RTSP, and other protocols supported by the
installed FFmpeg build are accepted as inputs.
| Setting | Default | Meaning |
|---|---|---|
encoding |
utf8 |
Process output encoding |
timeout |
0 |
Maximum operation time in milliseconds; 0 disables it |
maxBuffer |
16 MiB | Retained stdout/stderr tail; reaching it does not kill FFmpeg |
overwrite |
false |
Use -y; otherwise -n prevents interactive hangs |
ffmpegPath |
ffmpeg |
FFmpeg executable |
ffprobePath |
ffprobe |
ffprobe executable |
signal |
— | AbortSignal used to cancel an operation |
cwd, env |
inherited | Child-process working directory and environment |
All setters are chainable:
- Video:
setDisableVideo,setVideoFormat,setVideoCodec,setVideoBitRate,setVideoFrameRate,setVideoStartTime,setVideoDuration,setVideoAspectRatio,setVideoSize,setVideoQuality - Audio:
setDisableAudio,setAudioCodec,setAudioFrequency,setAudioChannels,setAudioBitRate,setAudioQuality - General:
setMetadata,setThreads,setWatermark,addInput,addCommand,addOutputOption,addFilterComplex,getCommand - Execution:
save,fnExtractSoundToMP3,fnExtractFrameToJPG,fnAddWatermark
copy is accepted by both codec setters. Repeated custom options such as multiple -map or
-metadata entries are supported.
video.metadata preserves the original package shape (duration, video, audio, and common
tags) and adds the complete ffprobe response at video.metadata.raw. Available formats and
encoders are exposed at video.info_configuration.
video.on('start', (command) => console.log(command));
video.on('progress', (progress) => console.log(progress.percent));
video.on('stderr', (chunk) => process.stderr.write(chunk));
video.on('end', (result) => console.log(result.code));
video.on('error', (error) => console.error(error)); // optionalAn error listener is optional: failed Promise operations reject normally instead of causing an
unhandled EventEmitter error.
const files = await video.fnExtractFrameToJPG('/media/frames', {
start_time: '00:00:10',
every_n_seconds: 5,
number: 10,
size: '640x?',
quality: 2,
file_name: 'preview_%s',
});Only one of every_n_frames, every_n_seconds, or every_n_percentage may be set. Returned paths
are limited to files matching the extraction pattern, rather than every file in the directory.
await video
.addCommand('-movflags', '+faststart')
.addCommand('-map', '0:v:0')
.addCommand('-map', '0:a:0?')
.save('/media/output.mp4');Arguments are passed directly to spawn with shell: false; do not add shell quotes.
- Node.js 24+ and ffprobe are now required.
- Native Promises replace
when; normalawaitand.then()usage is unchanged. - Errors are
FfmpegErrorinstances with the historical numericcodeandmsgfields. - Watermark compass positions now follow their conventional meaning (for example,
NEis top-right). This fixes the old east/west inversion. - Bitrates use modern stream-specific flags (
-b:vand-b:a); numeric values are interpreted as kbit/s. - Existing outputs are protected with
-n. Setoverwrite: trueto use-y. - The project publishes both ESM and CommonJS and includes its own TypeScript declarations;
@types/ffmpegis no longer needed.
See AUDIT.md for the code and issue audit and CHANGELOG.md for the release summary.
FFmpeg processes untrusted and highly complex media. Keep the system FFmpeg build patched, apply resource limits appropriate to your service, and see SECURITY.md before accepting untrusted input.
MIT © Damiano Ciarla