ffmpegvideo-compositionapi

Concatenate clips programmatically: a composition API primer

·Javid Jamae·7 min read
Concatenate clips programmatically: a composition API primer

Stitching two clips into one sounds like the easiest video task there is. Then you run FFmpeg's concat demuxer on a phone clip and a screen recording, and you get a garbled output, an audio drift, or a hard crash. The join isn't the hard part. Making mismatched clips agree on codec, resolution, and frame rate is.

Quick answer: To concatenate clips programmatically with an API, POST the ordered list of source URLs to a video composition API and it re-encodes them to a common format before joining, so mixed inputs merge cleanly in one call with no servers to run. Locally, use FFmpeg's concat demuxer for identical clips or the concat filter for mixed ones.

Why naive video concatenation breaks

The common belief is that concatenation is a copy operation. Grab two MP4s, glue the bytes, done. That works exactly once: when both clips share the same codec, resolution, pixel format, frame rate, and audio sample rate.

The moment inputs differ, and in any real pipeline they always differ, a byte-level join produces broken output. A 1080p30 camera clip followed by a 720p60 screen capture doesn't have a valid single-stream representation. So the problem isn't "join videos programmatically." It's "normalize, then join." Every reliable video merge API does the normalize step for you, which is the whole reason a composition API exists.

You can prove the mismatch before you concatenate anything with ffprobe (see ffprobe: How to Inspect Video Metadata Before Processing). If codec_name, width, height, or r_frame_rate disagree across your clips, plan on a re-encode.

Concatenate videos with FFmpeg: the two real methods

FFmpeg gives you two paths, and picking the wrong one is the number-one cause of failed merges.

The concat demuxer (fast, same format only)

Use this when every clip is already identical in codec and parameters. It copies streams with no re-encode, so it's near-instant.

# files.txt
file 'clip1.mp4'
file 'clip2.mp4'
file 'clip3.mp4'
ffmpeg -f concat -safe 0 -i files.txt -c copy output.mp4

The -c copy is what makes it fast. It's also what makes it fail on mixed inputs, because there's no re-encode to reconcile the differences.

The concat filter (slower, handles mixed inputs)

Use this when clips differ. The concat filter decodes and re-encodes, so you can scale everything to a shared size first.

ffmpeg -i a.mp4 -i b.mp4 \
  -filter_complex "[0:v]scale=1920:1080,fps=30[v0]; \
    [1:v]scale=1920:1080,fps=30[v1]; \
    [v0][0:a][v1][1:a]concat=n=2:v=1:a=1[v][a]" \
  -map "[v]" -map "[a]" output.mp4

If you get "Stream specifier ':a' matches no streams," one input has no audio track. The concat filter needs every input to carry the same stream layout, which is where the FFmpeg -map flag earns its keep. This is the part people underestimate: correct concatenation of real-world clips is a filtergraph problem, not a one-liner.

The one-call version: a video composition API

A composition API collapses both methods into a single request. You send an ordered list of clips, and the service inspects, normalizes, and joins them, then hands back one file. No FFmpeg to install, no filtergraph to debug, no server to keep warm for long jobs.

curl -X POST https://api.ffmpeg-micro.com/v1/jobs \
  -H "Authorization: Bearer $FFMPEG_MICRO_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "operation": "concat",
    "inputs": [
      "https://cdn.example.com/intro.mp4",
      "https://cdn.example.com/body.mp4",
      "https://cdn.example.com/outro.mp4"
    ],
    "output": { "format": "mp4", "resolution": "1920x1080", "fps": 30 }
  }'

You get a job ID back, then poll or receive a webhook when the output is ready. Check the exact request schema in the docs before you wire it in.

Here's the trade-off in plain terms.

FFmpeg on your machineComposition API
Mixed codecs/resolutionsManual filtergraphHandled automatically
SetupInstall and version FFmpegOne API call
Long jobsYou babysit the processRuns managed, webhook on done
Scaling to 200 clips/nightYour queue, your serversRuns in parallel, no servers to run
CostYour computeUsage-based, free tier to start

Concatenate videos in n8n, Make, and Zapier

No-code builders don't need FFmpeg at all. The composition API works with n8n, Make, and Zapier as an HTTP request node.

  1. Collect your clip URLs in an earlier step (a Google Drive folder, an S3 prefix, a database query).
  2. Add an HTTP Request node pointing at the jobs endpoint with the ordered inputs array.
  3. Wait for the webhook, then push the finished video to YouTube, a CDN, or the next step.

This is the exact pattern behind assembling faceless-channel videos from stock clips, voiceover, and B-roll. The full build is in Faceless YouTube channel automation: assemble videos from assets.

Common pitfalls when you concatenate clips

  • Using -c copy on mismatched clips. The output plays the first clip fine, then glitches or freezes. Switch to the concat filter or let the API re-encode.
  • Different frame rates. A 24fps clip joined to a 60fps clip causes audio-video drift that grows over the timeline. Force one fps for all inputs.
  • Missing audio on one clip. The concat filter errors out. Add a silent track with anullsrc, or use an API that pads it for you.
  • Relative paths with the demuxer. Without -safe 0, FFmpeg rejects paths outside the current directory. Use absolute paths or the flag.
  • Variable frame rate (VFR) source. Phone recordings are often VFR and drift after concatenation. Convert to constant frame rate first with fps=30.

When not to use a composition API

If every clip already comes off the same encoder with identical settings, and you're merging a handful of files on a machine you control, the local concat demuxer with -c copy is faster and free. There's no re-encode, so quality stays untouched and the job finishes in seconds. Reach for a hosted API when inputs vary, volume is high, or you don't want to run and scale a media service. If you need a full timeline editor with a UI, that's a different tool. FFmpeg Micro is an API, not an editor.

FAQ

How do I concatenate videos with different resolutions?

Scale every clip to a shared resolution before joining. With FFmpeg, chain scale=1920:1080 into the concat filter. With a composition API, set the output resolution and it normalizes each input for you.

Can I merge videos without installing FFmpeg?

Yes. A cloud video merge API runs FFmpeg on managed infrastructure, so you send clip URLs over HTTP and download one output. That's how you concatenate videos without a server, from code, n8n, Make, Zapier, or an AI agent.

What's the difference between the concat demuxer and the concat filter?

The demuxer copies streams without re-encoding, so it's fast but requires identical inputs. The filter decodes and re-encodes, so it handles mixed codecs, resolutions, and frame rates at the cost of processing time.

How do I concatenate videos at scale?

Submit each merge as an independent job and let them run in parallel instead of queuing on one machine. A composition API with webhooks lets you fire hundreds of concat jobs a night without managing servers or worrying about long-running process timeouts.

Wire the concat step into your pipeline and stop debugging filtergraphs at 2 a.m. Sign up free and send your first ordered clip list in one API call.

About Javid Jamae

Founder & CEO at FFmpeg Micro

Javid is a software engineer, author, and entrepreneur with over 25 years of professional software development experience across enterprise, startup, and consulting environments. He founded FFmpeg Micro to make video processing accessible to developers through a simple, automation-first REST API.

Software EngineeringVideo ProcessingFFmpegCloud ArchitectureAPI DesignAutomation

Ready to process videos at scale?

Start using FFmpeg Micro's simple API today. No infrastructure required.

Get Started Free