damianociarla/node-ffmpeg

ffmpeg module for nodejs

What it is

node-ffmpeg is a JavaScript/TypeScript library that lets you control the command-line tools ffmpeg and ffprobe from your code. Instead of typing shell commands, you call methods like setVideoCodec('libx264') or save('/output.mp4'). It wraps the older, widely used ffmpeg package’s API but modernises it: native Promises, TypeScript types, and supports both ESM and CommonJS.

Requirements

  • Node.js 24 or newer.
  • ffmpeg and ffprobe must be installed and available on your system’s PATH, or you must provide their exact paths.
  • The library intentionally does not download its own FFmpeg binaries — this keeps the package small and lets you pick the FFmpeg build and codecs you need.

Installation

npm install ffmpeg

Quick start (TypeScript)

import ffmpeg from 'ffmpeg';

const video = await ffmpeg('/media/input.mp4');

video.on('progress', ({ percent, time }) => {
  console.log(percent === undefined ? `${time}s` : `${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');

The methods are chainable — you can call one after another. The operation starts only when you call a terminal method like save(). There’s also a callback-style API from the original package, and a named factory create() that supports options like timeout and overwrite.

For services processing many files, you can create a client once with createClient() to reuse FFmpeg settings.

Executable paths

You can set the paths to ffmpeg and ffprobe globally (for legacy apps) or per operation. If you give an absolute ffmpegPath but no ffprobePath, the library guesses that ffprobe sits next to it.

Settings (table from README)

Setting Default Meaning
encoding utf8 Process output encoding
timeout 0 Max operation time in ms; 0 = no timeout
maxBuffer 16 MiB How much conversion output to keep; also max probe output
overwrite false Use -y to overwrite; otherwise -n prevents interactive prompts
ffmpegPath ffmpeg FFmpeg executable
ffprobePath ffprobe ffprobe executable
signal — AbortSignal to cancel an operation
cwd, env inherited Child‑process working directory and environment

Long-running conversions only keep the last maxBuffer bytes of output. Probe output must fit completely inside maxBuffer or the operation fails with error 119.

API highlights

  • Setters (all chainable): video setters like setDisableVideo, setVideoCodec, setVideoBitRate, etc.; audio setters like setDisableAudio, setAudioCodec, setAudioBitRate; general setters like setMetadata, setThreads, setWatermark, addInput, addCommand, addOutputOption, addFilterComplex, and getCommand (returns the built command).
  • Terminal methods: save, fnExtractSoundToMP3, fnExtractFrameToJPG, fnAddWatermark. These start the actual process.
  • copy is accepted as a codec value, meaning “copy the stream without re‑encoding”.
  • Repeated custom options (e.g. multiple -map or -metadata entries) are allowed.

Validation inside terminal methods gives errors through Promise rejection or the optional callback. Setter validation remains synchronous. Concurrent operations on one video object use isolated option snapshots.

Metadata and events

  • video.metadata keeps the original shape (duration, video, audio, tags) and also exposes the full ffprobe response at video.metadata.raw.
  • You can listen to lifecycle events: 'start', 'progress' (with percent/time), 'stderr', 'end', and 'error'.
  • An 'error' listener is optional — failed Promises reject normally without needing it.

Frame extraction

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 only include files matching the extraction pattern.

Custom FFmpeg options

Use addCommand to pass raw arguments. They are passed directly to spawn without shell interpretation, so do not add shell quotes. These methods are trusted escape hatches — never pass unvalidated user input. Output destinations starting with - are rejected; use ./-name.ext instead.

Migration from 0.0.4

  • Node.js 24+ and ffprobe are now required.
  • Native Promises replace the old when library; await works as before.
  • Errors are now FfmpegError instances with the historical numeric code and msg fields.
  • Watermark compass positions now follow conventional meaning (NE = top‑right, fixing the old inversion).
  • Bitrates use -b:v / -b:a; numeric values are treated as kbit/s.
  • Existing outputs are protected with -n; set overwrite: true to use -y.
  • The package now ships its own TypeScript declarations, so @types/ffmpeg is unnecessary.

Security

FFmpeg processes untrusted and complex media. Keep your system FFmpeg patched, apply resource limits, and read SECURITY.md before accepting untrusted input.

License

MIT © Damiano Ciarla.

Related

  • Project
  • Project
  • Project
  • Project