Install
cargo install faucet-cli --features sink-bigquery faucet init --sink bigquery
# Cargo.toml — use it as a library cargo add faucet-sink-bigquery
Starter config
sink:
type: bigquery
config:
project_id: "" # REQUIRED — GCP project ID.
dataset_id: "" # REQUIRED — BigQuery dataset ID.
table_id: "" # REQUIRED — BigQuery table ID.
auth:
type: service_account_key_path # one of: service_account_key_path, service_account_key, application_default
config:
path: "" # REQUIRED — Filesystem path to the service-account JSON key.
# --- Alternative variants — replace the block above with one of these ---
# type: service_account_key
# config:
# json: "" # REQUIRED
#
# type: application_default
# batch_size: 1000 # Maximum rows per `tabledata.insertAll` request.
# insert_id_field: "" # Optional record field whose value is sent as the BigQuery streaming `insertId` for each row.
# job_timeout: 3600 # Longest the sink waits, in seconds, for one BigQuery job it started (a MERGE, the overwrite swap, a cleanup DELETE, DDL, a load job) before requesting its cancellation and failing the write.
# write_mode: null # Write semantics for a sink.
# key: [] # Key columns.
# delete_marker: null # Optional.
# rollback: null # Runtime rollback settings (#706): the run id to journal under, the run-id column, and whether to journal before-images / keep a replaced table.
# scope: null # Scoped/windowed overwrite (#518): with `write_mode: overwrite`, replace only the rows matching this scope (e.g.
# create_table: true # Create the target table (and its dataset) if it does not exist, inferring the schema from the first written page.
# schema: null # **Experimental** (PRINCIPLES.md §3): this field may change shape in a minor release; changes are called out in the changelog.
# location: "" # Location (region or multi-region, e.g.
# media_load: true # Bucket-free bulk load for the **append** and **overwrite** write paths (default **`true`**, #612).
# bulk_load: null # Arrow columnar **load-job** mode (#380): buffer Arrow `RecordBatch`es to Parquet, stage them on a GCS bucket, then run a BigQuery `PARQUET` load job (`jobs.insert`) instead of the per-row `insertAll` path.
Capabilities
| Delivery | Exactly-once (atomic watermark) |
|---|---|
| Write modes | append, upsert, delete, overwrite |
| Exactly-once writes | Yes |
| Schema evolution | Yes |
| Scoped cleanup | Yes |
| Staged bulk load | Yes |
| Run rollback | No |
| Compression | No |
Config fields
| Field | Type | Default | Description |
|---|---|---|---|
project_idrequired | string | — | GCP project ID. |
dataset_idrequired | string | — | BigQuery dataset ID. |
table_idrequired | string | — | BigQuery table ID. |
authrequired | object | — | Authentication credentials. YAML/JSON key is auth for consistency with every other connector's auth block. |
batch_size | integer | 1000 | Maximum rows per tabledata.insertAll request. Defaults to DEFAULT_BATCH_SIZE. |
insert_id_field | string | — | Optional record field whose value is sent as the BigQuery streaming insertId for each row. BigQuery uses insertId for best-effort de-duplication over a short window, so a stable per-row key here makes streaming inserts resilient to transport retries (which are otherwise at-least-once and can produce duplicate rows) (#78/#31). When None (the default) no insertId is sent. A row missing the field is inserted without an insertId (no dedup for that row). |
job_timeout | integer | 3600 | Longest the sink waits, in seconds, for one BigQuery job it started (a MERGE, the overwrite swap, a cleanup DELETE, DDL, a load job) before requesting its cancellation and failing the write. Default 3600; 0 waits for as long as the job runs. After the cancel the sink waits up to 30 s for the job to stop; a job that finished successfully before the cancel took effect is treated as completed, and the error says when a job could not be confirmed stopped (it may still commit). |
write_mode | object | append | Append (default), upsert, or delete. |
key | array | [] | Key columns. Required and non-empty for upsert/delete; ignored for append. |
delete_marker | object | — | Optional. Upsert only: rows whose field matches one of values are deletes; all others are upserts. The marker field is stripped from upsert rows before writing. |
rollback | object | — | Runtime rollback settings (#706): the run id to journal under, the run-id column, and whether to journal before-images / keep a replaced table. Injected per invocation by the CLI when a config has a top-level rollback: block — not meant to be written by hand. |
scope | object | — | Scoped/windowed overwrite (#518): with write_mode: overwrite, replace only the rows matching this scope (e.g. a partition/date window) instead of the whole table — the out-of-scope rows are preserved. |
create_table | boolean | true | Create the target table (and its dataset) if it does not exist, inferring the schema from the first written page. Enabled by default: a first-ever sync cannot assume the destination table already exists. Set to false to require the table to pre-exist and fail fast when it is missing (e.g. the schema is managed externally and a missing table signals a typo). |
schema | any | — | **Experimental** (PRINCIPLES.md §3): this field may change shape in a minor release; changes are called out in the changelog. |
location | string | — | Location (region or multi-region, e.g. US, EU, us-central1) used only when create_table has to create the dataset. None uses the BigQuery job's default location. Ignored once the dataset exists. |
media_load | boolean | true | Bucket-free bulk load for the **append** and **overwrite** write paths (default **true**, #612). |
bulk_load | object | — | Arrow columnar **load-job** mode (#380): buffer Arrow RecordBatches to Parquet, stage them on a GCS bucket, then run a BigQuery PARQUET load job (jobs.insert) instead of the per-row insertAll path. Only present in arrow builds; drives the columnar fast path the pipeline negotiates when the source and sink are both columnar. Load jobs are append/truncate only, so the sink advertises columnar support **only** when the write mode is append — upsert/delete stay on the MERGE path. |
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