Pick the right method before you run anything
FFmpeg has three separate mechanisms for concatenating videos, and choosing the wrong one wastes time. Here's the decision table:
| Situation | Method | Re-encodes? |
| Same codec, resolution, frame rate | Concat demuxer | No |
| Different codecs or resolutions | Concat filter | Yes |
Existing .ts / HLS segments | Concat protocol | No |
| Variable frame rate clips (phone video) | Concat filter | Yes |
| Audio files only | Concat demuxer or filter | Depends |
If your clips came from the same source (same camera, same export preset), start with the demuxer. It's fast because it copies bytes instead of re-encoding. If anything doesn't match, switch to the filter.
The FFmpeg merge videos guide covers the full workflow for combining clips. This guide goes deeper on the concat mechanisms themselves and how to diagnose when things break.
The concat demuxer
The demuxer reads a list of files and joins them without touching the encoded data. It's the fastest option when it applies.
-f concat tells FFmpeg to use the concat demuxer. -safe 0 allows paths outside the current directory. -c copy skips re-encoding.
Generate the file list with a script instead of typing it:
Common demuxer errors:
DTS ... out of order: Your clips have inconsistent timestamps. Fix by regenerating them:
Not strictly monotonically increasing: Same root cause. Same fix.
Invalid data found when processing input: The clips actually have different codecs and the demuxer can't handle them. Switch to the concat filter.
Unsafe file name: Remove the -safe 0 flag and move your files to a path without special characters, or add -safe 0 if it's missing.
The concat filter
When your clips have different codecs, resolutions, or frame rates, you need the concat filter. It re-encodes everything to a common format.
The filter syntax breaks down like this:
[0:v][0:a]: video and audio from the first input[1:v][1:a]: video and audio from the second inputconcat=n=3:v=1:a=1: join 3 inputs, each contributing 1 video stream and 1 audio stream[outv][outa]: name the output streams so-mapcan reference them
When resolutions don't match:
FFmpeg refuses to concat clips with different dimensions. Pad them to a common size first:
When frame rates don't match:
Add fps=30 (or whatever target rate) to each input's filter chain:
Common filter errors:
Input link ... parameters do not match: The resolutions are different. Add the scale + pad block shown above.
[Parsed_concat] Input streams must have the same timebase: Different time bases between inputs. Add -vsync vfr before the output flags, or normalize the frame rate first.
Audio stream has no pts: Usually happens with variable-bitrate audio. Add -async 1 or convert the audio to a fixed format first.
The concat protocol
The protocol is the oldest method and the most limited. It concatenates at the byte level using a pipe-separated list of files.
It only works reliably with MPEG-TS (.ts) files. MP4, MOV, and MKV store header data in ways the protocol can't handle across file boundaries.
If you have .ts segments from an HLS stream or a live recording, this is the fastest way to rejoin them:
The -bsf:a aac_adtstoasc flag converts the ADTS-formatted AAC headers that MPEG-TS uses into the MPEG-4 format that MP4 containers expect. Skip it and the audio won't play.
For anything other than .ts files, use the demuxer instead.
Audio-only concat
Audio files work with either mechanism. If you're joining MP3 files that are identical in format:
If the bitrates or sample rates differ:
Note v=0:a=1 in the concat filter: no video streams, just audio. The rest of the syntax is the same.
Building concat commands in scripts
For anything beyond a handful of files, you want to generate the command programmatically.
Bash: merge all clips in a directory:
Usage: ./merge.sh output.mp4 clip1.mp4 clip2.mp4 clip3.mp4
Python: build the filter_complex dynamically:
Running concat via the RenderIO API
Local FFmpeg works fine for one-off tasks. For production workloads (merging user uploads, building automated video pipelines, batch processing hundreds of clips), running FFmpeg on your own server means sizing for peak load and managing the binary yourself.
The RenderIO FFmpeg API accepts the same FFmpeg commands you'd run locally and handles the compute remotely. No binary to install, no server to scale.
Concat demuxer via API (curl):
Concat filter via API (curl):
The API returns a command_id. Poll until it's done:
When status is SUCCESS, the response includes a download URL for the merged file.
Node.js: concat filter with submit-poll pattern:
For a deeper walkthrough of the Node.js patterns, including webhooks so you don't need to poll, the FFmpeg API Node.js guide has the full setup.
Concat for specific platforms
Platform delivery often needs a particular resolution and codec, not just "merged."
TikTok / Instagram Reels (9:16, 1080x1920, H.264):
YouTube (16:9, 1920x1080):
For the full scale filter reference, see the FFmpeg cheat sheet.
FAQ
What's the difference between concat demuxer and concat filter?
The demuxer reads a list of files and joins them at the container level without decoding. The filter decodes each input, processes it through the filter graph, and re-encodes. Demuxer: fast, lossless, requires matching formats. Filter: slower, re-encodes, handles anything.
Can I concat MP4 and MOV files?
Yes, as long as they use the same codecs internally (H.264 + AAC is common to both). The demuxer handles it with -c copy. If the internal codecs differ, use the concat filter.
Why does the concat demuxer produce corrupted output?
Usually a format mismatch: the clips look compatible but have subtly different parameters (different audio sample rates, different video profiles). Run ffprobe clip1.mp4 and ffprobe clip2.mp4 and compare the output. Any difference in codec, resolution, frame rate, or sample rate will cause problems.
How do I concat videos without losing quality?
Use the concat demuxer with -c copy when formats match. This copies bytes directly with no quality loss. If you have to use the concat filter (formats differ), use a lower CRF value like 18-20 for near-lossless output. It'll be a larger file but visually indistinguishable from the source.
Is there a limit on how many files I can concat?
The demuxer reads from a text file, so there's no practical limit (thousands of entries work fine). The filter requires all inputs on the command line, which runs into OS argument limits somewhere around a few hundred inputs. For large batches, use the demuxer.
Does ffmpeg concat preserve audio sync?
Yes if the source material has correct timestamps. Problems happen when clips were trimmed improperly (cut mid-GOP without re-encoding) or come from variable-frame-rate sources like phone recordings. The fix is to re-encode with the concat filter and add -vsync cfr to force constant frame rate.
How do I concat videos with different audio tracks or no audio?
If only some clips have audio, FFmpeg will error out when building the concat filter. Add a silent audio track to clips that have none:
Then concat all clips normally via the filter.