Connectors / Files & object stores

SFTP

sink

SFTP sink; JSONL objects, atomic temp+rename upload

Install

cargo install faucet-cli --features sink-sftp
faucet init --sink sftp
# Cargo.toml — use it as a library
cargo add faucet-sink-sftp

Starter config

sink:
  type: sftp
  config:
    host: ""    # REQUIRED — Server hostname or IP address.
    # port: 22    # Server port (default: 22).
    username: ""    # REQUIRED — SSH username.
    # known_hosts: { type: strict }    # one of: strict, accept_new, insecure
      # --- Alternative variants — replace the block above with one of these ---
      # type: accept_new
      #
      # type: insecure
    # connect_timeout_secs: 30    # Seconds the TCP connect, SSH handshake and authentication together may take, and then each SFTP channel's start (default 30).
    # keepalive_interval_secs: 15    # Seconds between SSH keepalives on a quiet connection (default 15); the connection is dropped after three go unanswered.
    path: ""    # REQUIRED — Remote directory the files are written in.
    # file_name: ""    # File-name template inside `path` — the file sink's `path` file name (#777).
    # if_exists: null    # What happens when a file this run writes already exists (`if_exists`).
    # write_mode: null    # Pipeline-level write mode (`write_mode`).
    # compression: null    # User-facing compression config.
    # format: null    # On-the-wire format of files written by the SFTP sink (#604).
    # file_extension: ".jsonl"    # File extension for written objects (default: `.jsonl`).
    # batch_size: 1000    # Records per file when `max_records_per_file` is not set (without `file_name`).
    # concurrency: 4    # Maximum number of file uploads in flight over the SSH session (default 4): a page that rolls into several files uploads them concurrently while the next file is encoded.
    # max_records_per_file: 0    # Maximum records per file before rolling to a new one (#618).
    # max_bytes_per_file: 0    # Maximum **bytes** per file before rolling to a new one (#618).
    # csv: { ... }    # CSV dialect.
    # excel: { ... }    # Excel worksheet selection.
    # xml: { ... }    # XML record framing.
    # avro: { ... }    # Avro read/write options.
    # parquet: { ... }    # Parquet write options.
    # json_lines: { ... }    # JSON Lines write options.
    # encryption: null    # Encrypt files at rest (#777; the `encryption` feature).
    # scratch_dir: ""    # Directory the sink builds each file in before uploading it (default: the system temporary directory).
    # max_listed_entries: 1000000    # Entries one directory listing may scan (default 1,000,000).

Capabilities

Delivery At-least-once
Write modes append, overwrite
Exactly-once writes No
Schema evolution No
Scoped cleanup No
Staged bulk load No
Run rollback No
Compression Yes

Config fields

FieldTypeDefaultDescription
host
required
string — Server hostname or IP address.
username
required
string — SSH username.
path
required
string — Remote directory the files are written in.
port integer 22 Server port (default: 22).
known_hosts object mode: accept_new Host-key verification policy (default: accept_new).
connect_timeout_secs integer 30 Seconds the TCP connect, SSH handshake and authentication together may take, and then each SFTP channel's start (default 30). A server that accepts and then stalls fails the run instead of hanging it.
keepalive_interval_secs integer 15 Seconds between SSH keepalives on a quiet connection (default 15); the connection is dropped after three go unanswered. 0 disables them.
file_name string — File-name template inside path — the file sink's path file name (#777). May contain {part} (numbered files) and ${now.*} tokens; a trailing / is a subdirectory of part-{part}<extension> files. When set, file_extension is not used. Unset: every run writes new files named <run id>-<part><file_extension> (<run id> is a fresh time-ordered UUID, <part> is 00001, 00002, …).
if_exists object replace What to do when a file of the same name already exists (if_exists): replace it (default), append to it (JSON Lines, CSV, raw text) or fail with error (#777). Needs file_name. mode is accepted as another name for this key, and overwrite / error_if_exists for its values.
write_mode object append append (default) or overwrite: write the run's files into a hidden swap area and move them into place only after a successful run, then remove files of an earlier run that match file_name and were not rewritten (#777). The move is one file at a time, so a reader listing the destination while it runs can see new files beside old ones; a move that was interrupted is finished by the next run. Needs file_name.
compression string | object auto Compression codec (default auto: from the file name's extension, .gz / .zst). The compression feature (#777).
format object json_lines File format (default json_lines) (#604).
file_extension string .jsonl File extension for written objects (default: .jsonl).
batch_size integer 1000 Records per file when max_records_per_file is not set (without file_name). Records accumulate across write_batch calls and a file closes once it holds this many records, or at flush. batch_size = 0 is the "no re-chunking" sentinel: no record cap, so JSON Lines and the whole-file formats write one file per flush, and Parquet one file per write_batch call. Ignored when file_name is set. Defaults to DEFAULT_BATCH_SIZE.
concurrency integer 4 Maximum number of file uploads in flight over the SSH session (default 4): a page that rolls into several files uploads them concurrently while the next file is encoded. flush returns only after every upload has landed.
max_records_per_file integer — Maximum records per file before rolling to a new one (#618). None removes the record cap; the sink accumulates across write_batch calls, so a small upstream page no longer means a small file.
max_bytes_per_file integer — Maximum **bytes** per file before rolling to a new one (#618).
csv object delimiter: ","has_headers: truequote: "on_unknown_field: widen CSV dialect, used when format: csv (#604).
excel object header_row: 0 Worksheet name, used when format: xlsx (#604).
xml object record_element: recordroot_element: records Record framing, used when format: xml (#604).
avro object codec: null Writer schema and block codec, used when format: avro (#719).
parquet object row_group_size: 1048576 Parquet writer options, used when format: parquet (#777): compression (default zstd), row_group_size, explicit schema.
json_lines object pretty: false JSON Lines writer options (pretty), used when format: json_lines.
encryption object — Encrypt files at rest (#777; the encryption feature). Scratch files are not encrypted while the run is in progress; those holding plaintext are kept in a private directory.
scratch_dir string — Directory the sink builds each file in before uploading it (default: the system temporary directory). JSON Lines and raw text need scratch space for the whole file; every other format needs room for each file being built (up to concurrency of them while uploads are in flight). A private subdirectory is created in it for each sink.
max_listed_entries integer 1000000 Entries one directory listing may scan (default 1,000,000). The sink lists its output directory, for example to remove files of an earlier run or finish an interrupted overwrite; every entry the server sends counts, and a directory with more fails the call with an error naming this field. Must be at least 1.
Get started

Your first pipeline runs in five minutes.

Install the CLI, scaffold a config, and move real data — nothing external to stand up.

curl -LsSf https://github.com/faucet-hq/faucet-stream/releases/latest/download/faucet-cli-installer.sh | sh
brew install faucet-hq/faucet-stream/faucet-cli