Key takeaways
- Start with a preset when it already matches the playback target, then override only the settings the product has deliberately chosen.
- Treat the container, video codec, audio codec, profile, rate control, pixel format, and filters as separate compatibility decisions.
- Select an
ffmpeg_stackdeliberately and retest fixtures before changing it, because encoder and filter behavior can vary between releases.
Codec control is rarely an all-or-nothing choice between a fixed preset and a raw FFmpeg command. Transloadit lets a Template start from maintained video or audio presets, replace individual supported FFmpeg options, or use the empty preset when the workflow must define the output settings itself.
What matters most
- Use
preset: "empty"with the explicitffmpeg_stack: "v7"selector recommended by the Robot documentation for encoding settings without preset defaults. - Create alternate codecs as independent Steps, then validate the produced metadata and playback instead of treating a successful encode as acceptance.
Start with the compatibility target, not a favorite codec
Write down where the result must play or be edited before choosing parameters. A browser delivery file, an archival master, a podcast download, and an interchange file have different requirements even when they begin with the same source. Record the required container, video and audio codecs, profiles, channel layout, dimensions, frame rate, sample rate, captions, and maximum delivery size for each target.
Keep containers and codecs separate in that matrix. MP4, WebM, Ogg, and MOV describe how streams and metadata are packaged; H.264, HEVC, VP9, AAC, Opus, and FLAC describe how individual streams are represented. A player can recognize a container and still reject one of its streams, so extension-only testing cannot establish compatibility.
Playback target
Name the actual browsers, devices, editors, or distribution specifications that decide whether an output is acceptable.
Stream policy
Specify video and audio requirements independently so a valid container does not hide an unsupported stream.
Acceptance evidence
Combine metadata inspection with playback on representative clients instead of approving a file from its extension alone.
Layer supported overrides on a maintained preset
A preset is a versioned collection of encoding settings for a common target. /video/encode and /audio/encode merge the entries in the ffmpeg object over the selected preset, so an explicit option replaces the corresponding preset value. This is usually the smallest maintainable policy: inherit the established baseline and record only the codec, profile, rate control, filter, or container behavior the product has intentionally changed.
Do not copy every resolved preset option into a Template merely to make it look explicit. That creates a private preset that the application must understand and maintain. Instead, name the preset, keep the override object focused, and inspect the result. If the workflow needs to avoid preset-supplied FFmpeg defaults, choose preset: "empty", keep the documentation’s recommended ffmpeg_stack: "v7" selector explicit, and supply the required format and codecs.
Preset baseline
Provides a documented starting point for a common output without requiring the Template to restate every FFmpeg option.
Override object
Records only the supported settings that deliberately differ, and those values take precedence over the preset.
Empty preset
Makes the deliberate absence of preset-supplied encoding defaults visible to future maintainers instead of relying on an omitted default.
Control video codec and rate-control settings deliberately
The video example begins with the web/mp4/1080p preset, selects the recommended v7 stack line, and then overrides the H.264 level constraint plus the product-specific rate-control settings in ffmpeg. JSON keys omit the command-line dash: level, crf, maxrate, and bufsize become FFmpeg output options. The preset continues to provide its H.264 (libx264) video codec, high profile, yuv420p pixel format, AAC (libfdk_aac) audio encoder, MP4 container, and movflags: "+faststart"; those inherited values do not need to be restated.
The values are an example policy, not universal quality recommendations. CRF, a bitrate cap, encoder profile, pixel format, source complexity, and playback constraints interact. Test text, animation, grain, motion, dark scenes, and ordinary talking-head material at the intended resolution. Inspect the output for both visual quality and decoder compatibility before promoting the settings.
{
"steps": {
":original": {
"robot": "/upload/handle"
},
"web_video": {
"use": ":original",
"robot": "/video/encode",
"ffmpeg_stack": "v7",
"preset": "web/mp4/1080p",
"ffmpeg": {
"level": "4.1",
"crf": 21,
"maxrate": "5M",
"bufsize": "10M"
},
"result": true
}
}
}Rate control and conformance
CRF targets a quality level while maxrate and bufsize cap the bitrate and smooth bursts; useful values depend on the encoder and delivery target. level is separate: it sets an H.264 decoder-conformance ceiling that bounds frame size, macroblock rate, and a maximum bitrate, but it is not the target or cap bitrate set through CRF, maxrate, and bufsize.
Preset compatibility baseline
The selected preset supplies the profile and pixel format, which can matter as much as the codec name to older hardware and browser decoders.
Inherited fast start
The preset supplies the MP4 movflags option for progressive download, but that does not replace adaptive streaming or a CDN.
Build an explicit audio output with the empty preset
The audio example uses preset: "empty" with the documentation’s recommended ffmpeg_stack: "v7" selector, so the Template supplies its encoding settings instead of inheriting them from a preset. Keep that selector explicit rather than relying on the implicit v6 runtime fallback. The example chooses the Ogg container, the Opus encoder, a target bitrate, a 48 kHz sample rate, two output channels, and a simple high-pass filter. /audio/encode accepts audio files and video files that contain an audio stream, which makes the same Step useful for audio-only uploads and soundtrack extraction workflows.
The empty preset removes preset-supplied encoding defaults rather than every Robot-added argument. /audio/encode still adds a default stream map so embedded cover art is not encoded as audio, and it derives the format or bitrate from the input when either value is omitted. This example states both values explicitly in the ffmpeg object with f and b:a.
This audio example uses the ffmpeg object because it demonstrates explicit empty-preset encoding settings. For simple conversions that only change bitrate or sample rate, prefer the documented top-level bitrate and sample_rate Robot parameters instead. They take integers in bits per second and Hertz—for example, 256000 and 48000—while ffmpeg.b:a accepts strings such as "128k". The Audio Encode Robot applies the top-level values after the ffmpeg merge, so they override conflicting b:a or ar values. Avoid specifying the same concern in both places: one authoritative value is easier to review, test, and change.
{
"steps": {
":original": {
"robot": "/upload/handle"
},
"podcast_audio": {
"use": ":original",
"robot": "/audio/encode",
"ffmpeg_stack": "v7",
"preset": "empty",
"ffmpeg": {
"f": "ogg",
"codec:a": "libopus",
"b:a": "128k",
"ar": 48000,
"ac": 2,
"af": "highpass=f=80"
},
"result": true
}
}
}Explicit container
The f option selects the output container format through its muxer, independently from codec:a, so the container and audio codec are chosen separately.
Channel policy
The ac option makes the requested output channel count visible instead of inheriting an unexpected source layout.
Audio filter
An af chain can apply supported FFmpeg filters, but each filter still needs representative listening and level checks.
Use FFmpeg flexibility inside the managed safety boundary
The ffmpeg value is a structured option object, not a shell command. Transloadit turns its keys and values into arguments for the selected managed FFmpeg stack. That boundary provides substantial control without exposing the worker host. It also means a Template cannot install a different FFmpeg build, add an unavailable encoder library, or assume every option from the newest upstream documentation exists in every stack.
User-controlled options pass through safety checks. Filter scripts and filter directives that read local files are rejected, including file-based subtitle, font, and text inputs. Use dedicated Robot parameters and Robots where available, such as watermark_url, /video/subtitle, or inline drawtext text with an available font family. Treat a rejection as a boundary to redesign around, not a reason to hide another command inside a filter string.
No shell syntax
Pass option names and values as JSON so quoting, interpolation, and validation stay within Assembly Instructions.
Stack capabilities
An encoder, muxer, or filter must be compiled into the selected managed stack before an otherwise valid option can work.
Safe file handling
Use declared inputs and purpose-built Robot parameters instead of asking an FFmpeg filter to open worker-local paths.
Create codec variants as independent Assembly Steps
One source Step can feed several independent encoding Steps. The example creates H.264/MP4 and VP9/WebM video renditions plus AAC and Opus audio outputs. These branches do not need application-side loops or repeated uploads: their shared use value declares the dependency, and each encode can run after the source file is available.
Give each Step a name that describes the output contract rather than an implementation detail likely to change. An application may care about browser_fallback and modern_web more than today’s encoder names. Mark only intentional outputs as results, export every durable rendition, and retain the Assembly ID so an operator can connect a rejected file to the exact Step and settings that produced it.
{
"steps": {
":original": {
"robot": "/upload/handle"
},
"browser_fallback": {
"use": ":original",
"robot": "/video/encode",
"ffmpeg_stack": "v7",
"preset": "web/mp4/720p",
"result": true
},
"modern_web": {
"use": ":original",
"robot": "/video/encode",
"ffmpeg_stack": "v7",
"preset": "web/webm/720p",
"result": true
},
"download_aac": {
"use": ":original",
"robot": "/audio/encode",
"ffmpeg_stack": "v7",
"preset": "aac",
"result": true
},
"download_opus": {
"use": ":original",
"robot": "/audio/encode",
"ffmpeg_stack": "v7",
"preset": "opus",
"result": true
}
}
}Shared source
Sibling Steps read the same uploaded or imported file without requiring the application to transfer it again.
Independent results
Each codec branch has its own status, metadata, error, and result entries for precise application handling.
Purpose-based names
Stable contract names let the underlying codec policy evolve without forcing every consumer to rename its field.
Version the Template and test the produced media
Keep the preset, FFmpeg overrides, and ffmpeg_stack in a saved Template so production jobs use one reviewable policy. Production Robot documentation recommends the v7 major selector, while a request that reaches the API runtime without a selector uses its implicit v6 fallback, so the examples save v7 explicitly. A major selector resolves to the highest available build within that major—for example, v7 resolves to a v7 build rather than v8. The deprecated v5 selector is no longer a valid stack and now resolves to v6. Exercise stack, preset, or override changes beside the current policy before routing all new jobs to them.
A successful Assembly proves that the command completed, not that the output meets the product contract. Read result metadata for codecs, dimensions, duration, frame rate, channel count, and sample rate, then play the files on representative clients. Keep known-good and difficult fixtures, compare file size and processing cost, check audio/video synchronization and seeking, and preserve a fallback while a changed policy rolls out.
Controlled Template
Keeps the codec policy together and prevents individual callers from drifting into undocumented combinations.
Fixture matrix
Covers the source codecs, resolutions, frame rates, channels, metadata, and damaged inputs production actually receives.
Playback checks
Prove decoding, seeking, timing, and quality on target clients instead of relying on an encoder exit status.
Technical details worth knowing
- The
ffmpegparameter is an object whose entries are merged on top of the selected preset; values supplied in that object take precedence over corresponding preset options. - When a caller supplies an
ffmpegobject without naming a preset, the default video or audio preset is not applied, which avoids inheriting settings that would then need to be overridden. - The explicit
emptypreset removes preset-supplied encoding defaults, but the Robot may still add stream selection or input-derived fallbacks when required values are omitted. - The
ffmpeg_stackmajor selector resolves within the requested major:v7selects the highest availablev7build and never jumps tov8. Supported majors arev6,v7, andv8. - Production Robot documentation currently recommends
v7, so every example setsffmpeg_stack: "v7"explicitly; a request that reaches the API runtime without a selector falls back tov6instead. - The deprecated
v5selector is accepted for backward compatibility but is no longer a runtime stack, so a request naming it is transparently upgraded tov6;v6,v7, andv8each run within their requested major. - A container option such as
f: "mp4"orf: "ogg"does not choose every stream codec; video and audio codecs are controlled independently. The stream-codec options accept either the long form (codec:v,codec:a) or the equivalent short FFmpeg aliases (c:v,c:a); maintained presets use the short forms, and the Robot treats the two spellings as interchangeable. - The Audio Encode Robot also exposes top-level integer
bitrateandsample_rateparameters, measured in bits per second and Hertz. Theffmpegobject covers codec, format, channel, filter, and other supported options, and accepts values such as"128k"forb:a. - FFmpeg option names are JSON keys without a leading dash, so the command-line option
-movflags +faststartis represented as"movflags": "+faststart"inside the object. - Transloadit validates user-controlled FFmpeg options against a managed safety policy; the selected stack must also contain the requested encoder, muxer, and filter.
- Independent Steps that use the same uploaded or imported file can encode different codec variants without another upload, and each Step appears separately in Assembly Status and results.
A practical approach
- 1
Define the players, devices, editors, or distribution systems that every output must support.
- 2
Choose the closest preset and record only the supported FFmpeg overrides needed for that target.
- 3
Run a fixture matrix that covers real input codecs, channels, frame rates, dimensions, and damaged files.
- 4
Store the Template, stack choice, acceptance checks, and approved outputs as one controlled release.
When Transloadit is useful
Use /video/encode and /audio/encode when a workflow needs a documented preset, selected codec and container controls, filters, or several renditions from one source. Run authorization and output-approval logic in your application, not inside the encode Step, and export approved results to durable storage.
Architecture boundary
The ffmpeg parameter exposes supported FFmpeg options inside managed encoding Robots; it is not shell access, a way to install another encoder build, or a guarantee that every option from every upstream FFmpeg release is available. Options outside the managed safety boundary are rejected.
Frequently asked questions
Can I pass any FFmpeg option through the ffmpeg object?
No. The object accepts supported FFmpeg options, but Transloadit validates them before execution and blocks forms outside the managed safety boundary. The selected stack must also contain the requested encoder, muxer, and filter. Test the exact option set against representative inputs rather than assuming an example for another FFmpeg build will transfer unchanged.
When should I use a preset instead of preset: "empty"?
Use a named preset when it provides the intended container, codec family, dimensions, and compatibility baseline. Add a small ffmpeg object when only a few choices differ. Use preset: "empty" when inheriting preset behavior would obscure or conflict with an explicit encoding policy, and keep the documentation’s recommended ffmpeg_stack: "v7" selector explicit.
How should I choose an ffmpeg_stack?
Use the current recommended stack unless the workflow requires another supported major selector, and keep that choice in the saved Template. Production Robot documentation recommends v7, so the examples select it explicitly instead of depending on the API runtime’s implicit v6 fallback. Before moving a production workflow to another stack, run the same source fixtures, compare output metadata and playback, and deploy the changed Template as a controlled release.
Does choosing MP4 or Ogg also choose the codecs?
No. A container packages streams, while codecs define how those video and audio streams are encoded. An MP4 file can still carry a codec that a target player does not support. Specify and inspect the video codec, audio codec, profile, pixel format, and other playback requirements separately from the container.
How do I create several codec variants from one input?
Create sibling /video/encode or /audio/encode Steps that all use the same source Step. Give each Step a stable purpose-based name, mark the selected outputs as results or export them, and validate each independent variant against its own playback target.