Storage Backends
Thepath field determines which storage backend Ingest Engine uses. Ingest Engine parses the URI scheme to select the backend automatically - you don’t need to configure the backend type separately.
s3://- AWS S3 or any S3-compatible store. Example:s3://my-bucket/data/gs://- Google Cloud Storage. Example:gs://my-bucket/data/abfs://orabfss://- Azure Blob Storage (ADLS Gen2). Example:abfs://[email protected]/data/file://or bare absolute paths - Local filesystem. Example:file:///tmp/data/or/tmp/data/
https://bucket.s3.region.amazonaws.com/key) and endpoint-embedded URLs for custom S3-compatible services (s3::https://minio.local:9000/bucket/key).
Storage Options
Thestorage_options map passes authentication and configuration to the underlying object_store library. The keys depend on which backend the path resolves to.
AWS S3:
endpoint is provided, Ingest Engine automatically sets allow_http: true and virtual_hosted_style_request: false on the S3 client. This means custom endpoints (MinIO, LocalStack, etc.) work out of the box without additional flags.
Google Cloud Storage:
On GKE with Workload Identity, no explicit credentials are needed. Otherwise:
Reading from the FileSystem
To read files from a storage path, configure a source with the path, a compression format, and a schema describing the file contents.Source Config
path(required) - URI of the folder to read from. Ingest Engine lists all objects under this prefix and reads them one by one. Supportss3://,gs://,abfs://,file://, and bare absolute paths.compression_format- Compression applied to the source files.none(default),zstd, orgzip. For JSON files, Ingest Engine wraps the byte stream in the appropriate decompression reader. Parquet files handle compression internally at the column-chunk level, so this setting only applies to JSON sources.regex_pattern- Regex pattern to filter which files to read. Ingest Engine lists everything underpathrecursively and only reads files whose object key matches this pattern. Optional - when omitted, all files underpathare read.storage_options- Cloud storage credentials. See the Storage Options section above.
Format
Theformat field inside schema determines how files are deserialized:
json: {}- Newline-delimited JSON (one JSON object per line)parquet: {}- Apache Parquet (columnar format, compression handled internally)
How the Source Works
Ingest Engine distributes files across parallel subtasks by hashing each file path and assigning it to a subtask based on the hash modulo the parallelism. Each subtask reads its assigned files sequentially. File read progress is tracked in Ingest Engine’s checkpoint state - on recovery, already-finished files are skipped and partially-read files resume from the last checkpointed position. The source is a bounded source - once all matching files have been read, the pipeline finishes. It does not watch for new files after the initial listing.Writing to the FileSystem
To write pipeline output to files, configure a sink with the destination path, a rolling policy, and a schema describing the output format.Sink Config
path(required) - URI of the folder to write to. All output files land under this prefix. The path is validated at pipeline creation time - Ingest Engine parses the URI and rejects invalid schemes or malformed URLs.storage_options- Cloud storage credentials. Same as the source.rolling_policy- When to close files and start new ones. See Rolling Policy below.file_naming- File naming strategy and prefix/suffix. See File Naming below.partitioning- Hive-style data partitioning. See Partitioning below.multipart- Multipart upload tuning. See Multipart Upload below.
Format
Theformat field inside schema determines how data is serialized to files:
parquet: {}- Apache Parquet. Supports compression options (snappy,gzip,zstd,lz4,uncompressed) and configurable row group size viarow_group_bytes(default 128 MB).json: {}- Newline-delimited JSON.
Delivery Guarantee
The FileSystem sink uses a two-phase commit protocol tied to Ingest Engine’s checkpoint system. On each checkpoint, in-progress multipart uploads are snapshotted (including part IDs and buffered bytes). On recovery, the sink resumes uploads from the last checkpoint - already-uploaded parts are reused and only incomplete parts are re-uploaded. Files are finalized (multipart complete) only after a successful commit, so output is exactly-once: no duplicate or partial files appear in the output path. For local filesystem paths, the sink writes to a temporary__in_progress subdirectory and moves files to the final location on commit.
Rolling Policy
Controls when files are closed and flushed to the object store. Multiple policies can be combined - whichever triggers first wins. A hard limit on the number of multipart parts (frommultipart.max_parts, default 1000) is always enforced regardless of other policies.
file_size_bytes- Close the file after it reaches this many bytes. Use this to produce predictably-sized files for downstream readers.interval_seconds- Close the file after this many seconds since the first write. Must be >= 1. Useful for bounding file age in high-volume pipelines.inactivity_seconds- Close the file after this many seconds of no new data. Must be >= 1. Good for low-volume or bursty sources where you want files flushed during idle periods.
file_size_bytes and interval_seconds to get both size-bounded and time-bounded files. For low-volume or bursty sources, inactivity_seconds alone is often sufficient.
Important: At least one rolling policy should be configured. Without it, files are only rolled when the multipart part limit (default 1000 parts) is reached, which can produce very large files.
File Naming
Controls how output files are named. The final filename follows the pattern{prefix}-{id}.{suffix} (or {id}.{suffix} if no prefix is set).
prefix- String prepended to the filename. Example: with prefixevents, files are namedevents-<id>.parquet.suffix- Overrides the default file extension. Defaults to the format’s natural extension (.parquetfor Parquet,.jsonfor JSON). Use with caution - changing the suffix does not change the actual format.strategy- How the{id}portion is generated. Default:uuid.
Naming Strategies
The
serial strategy produces filenames like {prefix}-{file_index}-{subtask_index}.{suffix}, where the file index increments each time a file is rolled and the subtask index identifies the parallel writer. The other strategies generate a globally unique ID per file.
Hive-Style Partitioning
Partition output files into directories based on column values. Produces a directory layout likecountry=US/events-17761234.parquet.
Partition Fields
partitioning.fields- List of columns to partition by. Each entry has:name- Column name. Supports dotted paths for nested structs (e.g.,geo.country).transform- Transform to apply before partitioning. Default:identity.
Transforms
The
hour, year, and month transforms only work with timestamp or date fields (UnixMicros, UnixMillis, UnixNanos, DateTime). Using them on non-temporal fields produces a validation error at pipeline creation time.
Time Pattern Rolling
partitioning.time_pattern- A date/time format string (e.g.,%Y/%m/%d). When set, the sink uses watermark-based rolling: a file is rolled when the pipeline watermark advances past the time bucket of the file’s first record. This ensures files align with time boundaries without relying on wall-clock timers.
Partition Shuffle
partitioning.shuffle_by_partition.enabled- Whentrue, Ingest Engine hash-shuffles records by partition keys before they reach the sink. This concentrates all records for a given partition value onto a single subtask, reducing the total number of output files. Default:false. Enable this for pipelines with many subtasks writing to the same partition keys. Disable it (or leave default) for single-writer pipelines or when data is heavily skewed - shuffling skewed data can cause backpressure on the hot subtask.
Multipart Upload
Tuning for object store multipart uploads. These settings affect how the sink splits data into parts for upload. Usually not needed - the defaults work for most cases.target_part_size_bytes- Target size for each part of the multipart upload, in bytes. Default: 33554432 (32 MB). Minimum: 5242880 (5 MB) - the S3 minimum part size. Ingest Engine enforces this minimum and rejects smaller values at pipeline creation time.max_parts- Maximum number of parts per upload. Default: 1000. This acts as a hard rolling policy - when a file reaches this many parts, it is rolled regardless of other rolling policy settings.