Shared S3 publication
Publish committed recording and thumbnail artifacts to one S3-compatible destination.
output.s3
Configure one S3-compatible destination for recording, thumbnails or both. The independent output.recording.publish and output.thumbnails.publish flags default to false. Each flag requires its own module to be enabled and output.s3.enabled to be true; an enabled S3 destination requires at least one publication owner. Thumbnail-only publication does not require recording.
"s3": {
"enabled": true,
"bucket": "${S3_BUCKET}",
"prefix": "media",
"region": "${AWS_REGION}",
"maxConcurrentUploads": 64,
"maxConcurrentThumbnailUploads": 8
}
Without publication there is no AWS configuration or credential lookup, client, transport, scheduler or object-storage request. Credentials come from the AWS SDK default provider chain. Thumbnail publication on a cascade-only node is a startup error; local push or managed pull can share a node with cascade input, but only the local inputs produce thumbnails.
Committed thumbnail JPEGs use the following immutable object key under the configured prefix, with Content-Type: image/jpeg. The local filename and remote basename both use {ordinal12}-{pts20}.jpg: the ordinal is zero-padded to 12 digits and the normalized 90 kHz PTS to 20 digits. For ordinal 1 and PTS 90000, both are 000000000001-00000000000000090000.jpg. Only the directory path and remote prefix differ. With an empty prefix, the key starts at thumbnails/.
{prefix}/thumbnails/YYYY/MM/DD/{encoded-streamId}/{HHmmssSSS}[~NNN]/{ordinal12}-{pts20}.jpg
The uploader reads only committed immutable artifacts. Remote success is followed by a durable local success marker; a remote response alone does not permit deletion. The local JPEG remains after an upload failure or a crash before marker commit. Retryable failures use bounded retry/backoff with the same key and content. Restart rebuilds publication work from authoritative local artifacts and durable state without S3 listing.
Each thumbnail session has its own .publication/closure.json, which verifies the complete committed JPEG set and its durable publication markers. session.json remains local lifecycle metadata, not a consumer manifest or publication closure. Once retention has elapsed, deletion still requires a durably closed session and its own complete durable publication closure. Recording publication can never satisfy the thumbnail retention gate, or vice versa.
Both owners share one S3 client, transport and bounded scheduler. At most one artifact per logical streamId is active across both owners and all its sessions. The global maxConcurrentUploads default is 64; maxConcurrentThumbnailUploads defaults to min(8, maxConcurrentUploads) and is a sub-limit inside that global budget, not extra capacity. When both owners have ready work, selection alternates between them even with one global slot. Retry backoff holds no upload slot, and pending artifacts remain in durable local catalogs rather than an in-memory artifact queue.
The full output.recording.s3 object is a legacy recording-only alias. It cannot coexist with output.s3; when enabled, it implies recording publication and never enables thumbnail publication. When migrating to output.s3, keeping the existing bucket and prefix preserves the recording object-key layout. Use the shared destination and explicit owner flags for new configurations.
Configuration reference
Use the shared output settings with this module. The complete field reference covers every accepted option; the maximal composition shows how modules fit together.