Skip to main content Skip to navigation
Convert Video to GIF with FFmpeg

Convert Video to GIF with FFmpeg

··Updated ·5 min readFresh·Updated Sep 29, 2026

TL;DR: FFmpeg is a powerful multimedia processing tool, and thanks to WebAssembly, you can now run it entirely in the browser with no server-side processing needed. This post shows how to integrate @ffmpeg/ffmpeg (the WASM build) into a Vue.js app to convert video files to GIFs client-side. It covers importing the library, loading the WASM script, running native FFmpeg commands in the browser, and handling the file input/output flow.

This post describes how to use Ffmpeg directly in browser, and use native commands. Ffmpeg loads web assembly script in browser, and gives APIs that we can consume.

What is Ffmpeg ?

FFmpeg is a free and open-source software project consisting of a large suite of libraries and programs for handling video, audio, and other multimedia files and streams.

"A complete, cross-platform solution to record, convert and stream audio and video." — ffmpeg.org

How do I add ffmpeg.wasm to a Vue app?

# Use npm
npm  install @ffmpeg/ffmpeg
# Use yarn
yarn  add @ffmpeg/ffmpeg

or you can use CDN directly, read more on the ffmpeg.wasm site.

Version note: this post uses the 0.11 API (createFFmpeg, ffmpeg.run, ffmpeg.FS). Version 0.12 replaced it with new FFmpeg(), ffmpeg.exec() and ffmpeg.writeFile(). To follow this post as written, install @ffmpeg/[email protected].

How do I convert a video to GIF in the browser?

  1. Import ffmpeg as below
const { createFFmpeg, fetchFile } = FFmpeg
const ffmpeg = createFFmpeg({ log: true })
  1. Load Load ffmpeg.wasm-core script in browser environment
await ffmpeg.load()
  1. Use following file command to do file operations in browser, all data is bound to browser and will be lost on page refresh
// ffmpeg.FS(method, ...args)

// Write file using below command
ffmpeg.FS('writeFile', 'test.mp4', await fetchFile(this.video))

// Read file (already available in FS memory)
ffmpeg.FS('readFile', 'out.gif')
  1. Run ffmpeg command, as ffmpeg native cli.
await ffmpeg.run(
  '-i',
  'test.mp4',
  '-t',
  '5',
  '-ss',
  '5',
  '-f',
  'gif',
  'out.gif'
)
// -t ==> total time of gif
// -ss ⇒ starting seconds or offset

Read more on ffmpeg commands in the FFmpeg documentation.

How do I do the same with ffmpeg.wasm 0.12?

The code below follows the 0.12 API from the ffmpeg.wasm documentation. I originally tested the 0.11 code above, so treat this newer example as a starting point and check it against the docs for your version.

import { FFmpeg } from '@ffmpeg/ffmpeg'
import { fetchFile, toBlobURL } from '@ffmpeg/util'

const ffmpeg = new FFmpeg()
const baseURL = 'https://unpkg.com/@ffmpeg/[email protected]/dist/umd'

await ffmpeg.load({
  coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),
  wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),
})

await ffmpeg.writeFile('test.mp4', await fetchFile(videoFile))
await ffmpeg.exec(['-ss', '5', '-t', '5', '-i', 'test.mp4', '-vf', 'fps=10,scale=480:-1:flags=lanczos', 'out.gif'])
const data = await ffmpeg.readFile('out.gif')
const gifUrl = URL.createObjectURL(new Blob([data.buffer], { type: 'image/gif' }))

fps=10,scale=480:-1 makes the GIF smaller: 10 frames per second and 480 pixels wide, with the height kept in proportion. The default single-thread 0.12 core doesn't need SharedArrayBuffer; only the multi-thread core does.

What does the finished app look like?

Vue app converting an MP4 video to a GIF with ffmpeg.wasm

Conclusion

I found ffmpeg-wasm was really helpful, I have explored just one use case, that's like exploring tip of iceberg. I will try out more use cases and keep updating in my GitHub repo.

Frequently Asked Questions

Is my video uploaded to a server?

No. ffmpeg.wasm runs inside the browser tab. The file is written to an in-memory file system and never leaves the device.

Why do I get a SharedArrayBuffer error?

ffmpeg.wasm 0.11 needs SharedArrayBuffer, which browsers only allow on cross-origin isolated pages. Serve your app with Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp.

What do the -t and -ss options do?

-ss 5 starts reading the video at 5 seconds, and -t 5 keeps 5 seconds of output. Together they make a 5-second GIF from seconds 5 to 10.

References