s2_sourcereads 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_sinkappends rows from any Streamling source or transform as JSON records to an S2 stream, with optional per-row routing across streams via a template likeevents/{tenant}.
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.Prerequisites
Install and start Docker
The ClickHouse and Postgres examples use Docker. Install Docker, start it, and verify that the daemon is available:
Create a walkthrough directory
Keep the pipeline files and checkpoint state for this walkthrough together:
Install the community plugins
Download the shared library for your platform from the releases page and tell Streamling where to find it:Use the The run commands below set
- macOS
- Linux
darwin-x86_64 asset on Intel Macs.STREAMLING__PLUGIN__PATH inline, so they also work in a fresh terminal.$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 sendsPOST → 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.
Create event streams and append some events
Write the pipeline
Create The
events-to-clickhouse.yaml: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.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.
Query ClickHouse
In another terminal:Append more events with When you are ready to continue, return to the terminal running this pipeline and press Ctrl+C.
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.
Example: Postgres CDC into S2
This example sendsPostgres 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.
Write the pipeline
Create The target stream is created automatically on first append (
postgres-cdc-to-s2.yaml: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.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 The update and delete stream in with
S2_BASIN, and make some changes:u and d ops:Postgres changes are flowing into your S2 stream in order, with CDC semantics intact.
Example: Postgres to ClickHouse through S2
Becauses2_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:
cdc-to-clickhouse.yaml:
?) 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 tailings2 read command with Ctrl+C. Then remove the walkthrough’s containers and their anonymous data volumes:
S2_BASIN guard prevents accidental deletion from an unset variable; only continue if the named streams were created for this walkthrough:

