Skip to main content
Streamling is an open source columnar streaming runtime from Goldsky, built for high-throughput real-time pipelines with checkpointing and at-least-once delivery. S2 support ships as two plugins in streamling-community-plugins v0.2.0 and later:
  • s2_source reads S2 streams into Arrow batches for any downstream Streamling transform or sink — exact stream names or a prefix, with newly created streams discovered automatically. Records can flow through as the raw envelope (stream, seq_num, timestamp, headers, body) or as typed columns decoded from JSON bodies.
  • s2_sink appends rows from any Streamling source or transform as JSON records to an S2 stream, with optional per-row routing across streams via a template like events/{tenant}.
Use s2_source when S2 is the durable input to a Streamling pipeline, and s2_sink when S2 is the durable output. The examples below use ClickHouse and Postgres CDC to show useful Streamling sources and sinks in both directions, but the S2 plugins compose with Streamling’s other sources, sinks, and transforms. The two plugins also compose into CDC round trips: the sink carries each row’s operation as a Debezium-style dbz.op record header, and the source restores it, so inserts, updates, and deletes survive a trip through S2 and apply correctly in a downstream database.

Reference

Configuration tables for both plugins are in the streamling-community-plugins README.
Both plugins accept an endpoint option, so pipelines can run against s2-lite — handy for CI and local development. See the CLI endpoint overrides for the accompanying CLI setup; use any non-empty access token value locally, since s2-lite ignores it.

Prerequisites

1

Set up the S2 CLI

Generate an access token from the dashboard, then:
Install the S2 CLI and point it at the same token:
2

Create a basin

3

Install and start Docker

The ClickHouse and Postgres examples use Docker. Install Docker, start it, and verify that the daemon is available:
4

Install Streamling

5

Create a walkthrough directory

Keep the pipeline files and checkpoint state for this walkthrough together:
6

Install the community plugins

Download the shared library for your platform from the releases page and tell Streamling where to find it:
Use the darwin-x86_64 asset on Intel Macs.
The run commands below set STREAMLING__PLUGIN__PATH inline, so they also work in a fresh terminal.
Run every example from $HOME/streamling-s2-demo. Streamling stores checkpoints there in state.db; see Clean up and rerun before replaying the walkthrough from the beginning.
Shell variables and the working directory do not carry into a new terminal. Whenever the walkthrough opens another terminal, return to the walkthrough directory and set S2_BASIN again; also set S2_ACCESS_TOKEN before starting a Streamling pipeline:

Example: Events into ClickHouse

This example sends POST → S2 → Streamling → ClickHouse: services append JSON events to S2 streams over the REST API, and a Streamling pipeline tails every stream under a prefix, decodes the events into typed columns, and upserts them into ClickHouse.
1

Create event streams and append some events

Append an event to each stream:
Each append is acknowledged with the durable sequence number range:
2

Start ClickHouse

3

Write the pipeline

Create events-to-clickhouse.yaml:
The schema option decodes JSON bodies into typed columns, and include_metadata adds _s2_stream, _s2_seq_num, and _s2_timestamp columns. The ClickHouse sink creates the table on first write.
4

Run it

Connection details are passed as environment variables, keeping secrets out of the pipeline definition:
The pipeline reads both streams from the beginning and keeps tailing them for new records. Leave it running while you query ClickHouse in the next step.
5

Query ClickHouse

In another terminal:
Append more events with curl and they show up in ClickHouse within moments. You can even create a brand new events-* stream: the source re-lists the prefix every 60 seconds (tunable via update_streams_interval_secs) and starts reading it automatically.
Events posted to S2 are flowing into ClickHouse as typed rows.
When you are ready to continue, return to the terminal running this pipeline and press Ctrl+C.

Example: Postgres CDC into S2

This example sends Postgres CDC → Streamling → S2: Streamling’s postgres_cdc_source performs an initial table copy followed by continuous logical replication, and s2_sink appends every change to an S2 stream with the operation preserved as a dbz.op record header.
1

Start Postgres with logical replication

Create a table with some rows:
2

Write the pipeline

Create postgres-cdc-to-s2.yaml:
The target stream is created automatically on first append (ensure_stream defaults to true).
memory_backpressure_enabled: false suits local machines, where system memory use often sits above the plugin’s default backpressure threshold. See the plugin README for production guidance, including least-privilege Postgres permissions.
3

Run it

Leave this pipeline running while you read from S2 and apply Postgres changes.
4

Read the changes from S2

In another terminal, the initial table copy is already there, each record carrying its operation as a header:
Leave the read session tailing. In a third terminal, return to the walkthrough directory, set S2_BASIN, and make some changes:
The update and delete stream in with u and d ops:
Postgres changes are flowing into your S2 stream in order, with CDC semantics intact.

Example: Postgres to ClickHouse through S2

Because s2_source maps dbz.op headers back to row operations, the CDC stream from the previous section can drive a second pipeline into ClickHouse — S2 acting as the durable, replayable changelog between the two. If the ClickHouse container from the first example is not already running, start it:
In a new terminal, create cdc-to-clickhouse.yaml:
Run the second pipeline:
Non-key columns are marked nullable (?) since delete records carry only the primary key. In another terminal, query ClickHouse to see the update applied and the deleted row gone:
Streamling checkpoints source positions in its state backend — by default a SQLite file at ./state.db, so a restarted pipeline resumes where it left off rather than re-reading streams. Postgres is available as a state backend for production. Delivery is at-least-once end to end. The ClickHouse sink converges on the latest row per primary key, so replayed rows do not change the final table state. The S2 changelog itself can contain duplicates after ambiguous retries or checkpoint replay; consumers should deduplicate if each change must be processed exactly once.

Clean up and rerun

Stop every Streamling process and the tailing s2 read command with Ctrl+C. Then remove the walkthrough’s containers and their anonymous data volumes:
To replay the walkthrough from sequence number 0, also remove its checkpoint file and streams. The S2_BASIN guard prevents accidental deletion from an unset variable; only continue if the named streams were created for this walkthrough:
Wait for the stream deletions to finish before recreating them. Keep the existing basin and resume at Events into ClickHouse instead of creating the basin again.