Originally published at ffmpeg-micro.com
Flutter's go-to FFmpeg library just died. ffmpeg-kit was archived on July 2, 2026, and the repo is now read-only. If you were relying on it to handle video in your Flutter app, you need a replacement.
The problem with ffmpeg-kit was always the native layer. Platform channels, binary bundling per architecture, xcframework linking on iOS, NDK configuration on Android. It worked, but every Flutter upgrade risked breaking the bridge. Now that it's abandoned, those problems won't get fixed.
A cloud API sidesteps all of that. Send an HTTP request from Dart, get processed video back. No native code, no binary management, no platform-specific build steps.
Why ffmpeg-kit Became a Liability
ffmpeg-kit bundled FFmpeg binaries directly into your app. On iOS, that meant an xcframework adding 15-40MB to your IPA. On Android, separate .so files per ABI (arm64-v8a, armeabi-v7a, x86_64). Every codec you enabled increased the binary size.
Beyond size, there was maintenance risk. Codec vulnerabilities in bundled FFmpeg binaries required rebuilding and resubmitting your app. And since July 2, 2026, no one is shipping those patches.
Cloud-based processing removes this entire category of problems. Your Flutter app stays thin. Video processing runs on servers with the latest FFmpeg build. You ship a Dart HTTP call, not a native binary.
Processing Video from Dart with FFmpeg Micro
FFmpeg Micro exposes FFmpeg as a REST API. You send a video URL, specify the output format and settings, and poll for results. The Dart code is standard http package usage.
First, add the dependency:
dependencies:
http: ^1.2.0
Then create a transcode job:
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<String> createTranscodeJob({
required String inputUrl,
required String apiKey,
String outputFormat = 'mp4',
}) async {
final response = await http.post(
Uri.parse('https://api.ffmpeg-micro.com/v1/transcodes'),
headers: {
'Authorization': 'Bearer $apiKey',
'Content-Type': 'application/json',
},
body: jsonEncode({
'inputs': [{'url': inputUrl}],
'outputFormat': outputFormat,
'preset': {'quality': 'high', 'resolution': '1080p'},
}),
);
if (response.statusCode != 201) {
throw Exception('Transcode failed: ${response.body}');
}
final job = jsonDecode(response.body);
return job['id'] as String;
}
This works identically on iOS, Android, web, macOS, Windows, and Linux. Same Dart code, no platform channels.
Polling for Completion
Transcode jobs run asynchronously. After creating a job, poll the status endpoint until it completes:
Future<Map<String, dynamic>> waitForCompletion({
required String jobId,
required String apiKey,
}) async {
while (true) {
final response = await http.get(
Uri.parse('https://api.ffmpeg-micro.com/v1/transcodes/$jobId'),
headers: {'Authorization': 'Bearer $apiKey'},
);
final job = jsonDecode(response.body) as Map<String, dynamic>;
final status = job['status'] as String;
if (status == 'completed') return job;
if (status == 'failed') throw Exception('Job failed: ${job['error']}');
await Future.delayed(const Duration(seconds: 2));
}
}
Once the job completes, grab the download URL:
Future<String> getDownloadUrl({
required String jobId,
required String apiKey,
}) async {
final response = await http.get(
Uri.parse('https://api.ffmpeg-micro.com/v1/transcodes/$jobId/download'),
headers: {'Authorization': 'Bearer $apiKey'},
);
final data = jsonDecode(response.body);
return data['url'] as String;
}
Full Example: Compress and Download
Putting it together in a complete function:
Future<String> processVideo(String inputUrl) async {
const apiKey = String.fromEnvironment('FFMPEG_MICRO_API_KEY');
// 1. Create the job
final jobId = await createTranscodeJob(
inputUrl: inputUrl,
apiKey: apiKey,
);
print('Job created: $jobId');
// 2. Wait for processing
await waitForCompletion(jobId: jobId, apiKey: apiKey);
print('Processing complete');
// 3. Get the download URL
final downloadUrl = await getDownloadUrl(jobId: jobId, apiKey: apiKey);
print('Download: $downloadUrl');
return downloadUrl;
}
Call it from anywhere in your Flutter app. In a button handler, in a background isolate, in a Dart CLI tool. The API doesn't care what platform you're running on.
Advanced: Raw FFmpeg Options
Presets cover common operations (compress, resize, change format). For anything specific, pass raw FFmpeg flags through the options field:
final response = await http.post(
Uri.parse('https://api.ffmpeg-micro.com/v1/transcodes'),
headers: {
'Authorization': 'Bearer $apiKey',
'Content-Type': 'application/json',
},
body: jsonEncode({
'inputs': [{'url': inputUrl}],
'outputFormat': 'webm',
'options': [
{'option': '-c:v', 'argument': 'libvpx-vp9'},
{'option': '-crf', 'argument': '30'},
{'option': '-b:v', 'argument': '0'},
{'option': '-vf', 'argument': 'scale=-2:720'},
],
}),
);
This converts to 720p WebM with VP9 encoding. Same FFmpeg flags you'd use on the command line, sent as structured JSON. If you're not sure which flags to use, the FFmpeg CRF guide covers quality settings in detail.
CLI vs. API: Side-by-Side
Same operation (MP4 to 720p WebM) done both ways:
FFmpeg CLI (requires local install):
ffmpeg -i input.mp4 -c:v libvpx-vp9 -crf 30 -b:v 0 -vf scale=-2:720 output.webm
FFmpeg Micro API (from Dart, no install):
final body = {
'inputs': [{'url': 'https://example.com/input.mp4'}],
'outputFormat': 'webm',
'options': [
{'option': '-c:v', 'argument': 'libvpx-vp9'},
{'option': '-crf', 'argument': '30'},
{'option': '-b:v', 'argument': '0'},
{'option': '-vf', 'argument': 'scale=-2:720'},
],
};
The CLI version requires FFmpeg installed on every machine. The API version runs from any Dart environment with the http package.
Common Pitfalls
Don't pass Airtable/Firebase Storage private URLs. FFmpeg Micro needs to download your source video. If the URL requires authentication or generates short-lived tokens, the download will fail. Use a publicly accessible URL, or upload through FFmpeg Micro's presigned upload flow: POST to /v1/upload/presigned-url, PUT the file to the returned GCS URL, then POST to /v1/upload/confirm.
Handle 402 responses for quota limits. The free tier has processing limits. If you exceed them, the API returns a 402 with details about which quota was hit. Check response.statusCode before parsing the body as a successful job.
Don't poll too aggressively. A 2-second interval is fine for most jobs. Short videos (under 60 seconds) typically finish in a few seconds. Polling every 100ms won't make it faster and will eat your rate limit.
Dart's String.fromEnvironment is compile-time only. In Flutter apps, const String.fromEnvironment('FFMPEG_MICRO_API_KEY') gets baked in at build time via --dart-define. For server-side Dart, use Platform.environment['FFMPEG_MICRO_API_KEY'] instead.
FAQ
Can I still use ffmpeg-kit with Flutter?
The package still installs, but it's frozen. No bug fixes, no security patches, no support for new Flutter versions. You can fork it, but you're taking on the entire native build chain. For new projects, a cloud API is less maintenance.
Does FFmpeg Micro work with Flutter Web?
Yes. The Dart http package works in browser environments. Your Flutter web app sends the same HTTP request, and FFmpeg Micro processes the video server-side. No WASM builds, no browser codec limitations.
How much does FFmpeg Micro cost for a Flutter app?
The free tier includes processing minutes with no credit card required. Paid plans start at $19/month for higher limits. Pricing is based on minutes of video processed, not API calls. Check ffmpeg-micro.com/pricing for current rates.
What about real-time video processing in Flutter?
FFmpeg Micro is designed for batch and asynchronous processing. If you need real-time filters or live preview, you still need a client-side solution. But for upload processing, format conversion, compression, and thumbnail generation, async is the right model.
Can I upload files directly from a Flutter app?
Yes. Use the three-step presigned upload: POST to /v1/upload/presigned-url with the filename, content type, and file size. PUT the file to the returned URL. POST to /v1/upload/confirm. Then use the GCS URL in your transcode request.
FFmpeg Micro gives you full FFmpeg without native binaries, platform channels, or abandoned dependencies. Sign up for a free API key and run your first transcode from Dart in under five minutes.
Last verified: July 2026. Code examples tested against Dart 3.4+, Flutter 3.22+, and FFmpeg Micro API v1.
Top comments (0)