s3
The Amazon S3 sink (alpha) writes each resource as one NDJSON, JSON, or
Parquet object per finite write in an S3-compatible bucket, laid out so an external
table per resource can read it directly. It is not a lakehouse format with
table-level atomic commits. See the Iceberg sink for that.
Configuration
A
prefix left empty is defaulted server-side to the normalized source
connection name.
Instance Profile is the default. It uses the AWS SDK default credential
chain, including EC2 instance profiles and container or workload roles. Choose
IAM Credentials to provide access_key_id and secret_access_key; add
session_token when using temporary credentials.
TestConnection performs a read-only HeadBucket request. On AWS this
requires s3:ListBucket; it does not prove that the identity can write. Runs
also need object-write and multipart-upload permissions for the configured
prefix.
Supported write modes
The sink advertisesfull_replace and full_append. See
replication modes. Because every
run writes its own objects, the two modes behave identically here. Each
run produces a fresh object per resource and never touches a previous run’s
objects. A full replace run is therefore a snapshot in its own date partition.
Query the latest partition to read the current state, or every partition to
read history.
Object layout
Each successful bounded run writes one object per resource and a success manifest. With prefixlocal_pg, resources accounts and orders, and the default
partition, a bounded run has this layout.
local_pg/accounts/. Manifests live under _runs, which query engines usually
skip. Continuous replace is not supported. Each append boundary reopens the
sink and produces independent objects and a manifest.
Partition template
partition sets the folders between each resource and its files. Write it as
a path with placeholders in double braces. Time placeholders use
the bounded run’s start time or the continuous write’s start time in UTC.
Every object in that finite write uses the same time. The logical run ID in
{{.Run}} stays unchanged across continuous boundaries.
The default
dt={{.Date}} is a Hive-style partition that Athena, Glue
crawlers, Spark, and DuckDB discover without extra configuration. Other
layouts:
Format takes a Go time layout,
where 2006, 01, 02, and 15 stand for year, month, day, and hour. Plain
directories without key=value names need Athena partition projection with a
location template.
The template is checked when the pipeline is saved. It must produce a relative
path with no empty, ., or .. segments, and unknown placeholders are
rejected. Helm charts that render pipeline YAML treat {{ as their own
syntax, so escape the template there as {{ "{{" }}.Date{{ "}}" }}.
File formats
file_format chooses how each resource object is encoded. The extension and
Content-Type follow the format, and gzip adds a .gz suffix and
Content-Encoding: gzip.
JSON formats write source field names and JSON-compatible values:
compression field shows only the options valid for the selected format.
The success manifest lists every resource’s key, URI, rows, bytes, and object
CRC32C. Programmatic consumers should treat _SUCCESS.json as the visibility
boundary and ignore writes without it. Query engines cannot apply that rule and
read every object under the table location. See failure behavior below.
Write mechanics and atomicity
The sink streams fullpart_size_mib buffers as multipart uploads while the run
is active. upload_concurrency limits S3 requests across resources; when that
limit is reached, source extraction waits. At commit, Filament uploads the
remaining bytes and completes each object. Small resources use PutObject, and
a selected resource with no rows becomes a zero-byte object.
The sink does not need temporary disk for the full run. Memory use comes mainly
from unfinished multipart buffers, in-flight uploads, and the current encoded
batch. Objects smaller than one part remain in memory until commit.
Each resource object is atomic, but a group of S3 objects cannot be committed
atomically. Resource objects may be visible while Commit is still running.
The write becomes valid only when _SUCCESS.json is uploaded last.
Failure behavior
Abort cancels in-flight work and abandons incomplete multipart uploads. If
Commit fails after some resources complete, those objects remain in their
resource partitions, but no _SUCCESS.json is published, so the write is not
valid. Query engines still read those objects. If partial data matters, remove
them by their run ID for bounded output or write ID for continuous output
before retrying. Configure an S3 lifecycle
rule to expire incomplete multipart uploads. Multipart uploads do not resume across worker
attempts. Resource progress is saved only after commit succeeds.
See Continuous streaming runs for boundary
defaults, setup costs, and checkpoint recovery. A replay after publication can
produce another append object with the same rows under a new write identity.