Durable Streams API https://s2.dev
  • Rust 99.3%
  • Shell 0.3%
  • Smarty 0.2%
  • Just 0.1%
Find a file
github-actions[bot] ff6651ef2f
chore: release v0.26.2 (#117)
## 🤖 New release

* `s2-common`: 0.26.1 -> 0.26.2
* `s2-api`: 0.26.1 -> 0.26.2
* `s2-lite`: 0.26.1 -> 0.26.2 (✓ API compatible changes)
* `s2-cli`: 0.26.1 -> 0.26.2

<details><summary><i><b>Changelog</b></i></summary><p>

## `s2-common`

<blockquote>

## [0.26.2] - 2026-01-29

<!-- generated by git-cliff -->
</blockquote>

## `s2-api`

<blockquote>

## [0.26.2] - 2026-01-29

<!-- generated by git-cliff -->
</blockquote>

## `s2-lite`

<blockquote>

## [0.26.2] - 2026-01-29

### Miscellaneous Tasks

- Update Cargo.lock dependencies

<!-- generated by git-cliff -->
</blockquote>

## `s2-cli`

<blockquote>

## [0.26.2] - 2026-01-29

### Miscellaneous Tasks

- Update Cargo.lock dependencies

<!-- generated by git-cliff -->
</blockquote>


</p></details>

---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
History 2026-01-29 22:25:23 +05:30
.claude/skills/release chore: update release skill and release tag (#111) 2026-01-29 09:56:39 +05:30
.github/workflows fix: release artifact upload (#116) 2026-01-29 22:23:21 +05:30
api chore: release v0.26.2 (#117) 2026-01-29 22:25:23 +05:30
assets readme tweaks (#90) 2026-01-21 11:19:35 -05:00
cli chore: release v0.26.2 (#117) 2026-01-29 22:25:23 +05:30
common chore: release v0.26.2 (#117) 2026-01-29 22:25:23 +05:30
lite chore: release v0.26.2 (#117) 2026-01-29 22:25:23 +05:30
.gitignore init 2025-11-07 12:09:00 -08:00
.gitmodules chore: fix submodule sync workflow (#57) 2026-01-14 23:47:18 -05:00
.rustfmt.toml init 2025-11-07 12:09:00 -08:00
AGENTS.md feat(lite): add local filesystem support; startup sleep for safe fencing (#94) 2026-01-26 11:26:56 -05:00
Cargo.lock chore: release v0.26.2 (#117) 2026-01-29 22:25:23 +05:30
Cargo.toml chore: release v0.26.2 (#117) 2026-01-29 22:25:23 +05:30
CLAUDE.md s2-lite backend (#11) 2026-01-04 23:37:38 -05:00
cliff.toml chore: fix cliff.toml preprocessor and import s2-cli changelog (#105) 2026-01-29 05:27:43 +05:30
Dockerfile feat!(cli): integrate s2-cli into workspace with lite subcommand (#103) 2026-01-29 05:04:11 +05:30
justfile feat!(cli): integrate s2-cli into workspace with lite subcommand (#103) 2026-01-29 05:04:11 +05:30
LICENSE update copyright line in license 2026-01-17 17:03:56 -05:00
README.md chore: reverting README till s2-cli with lite is released 2026-01-28 22:18:30 -05:00
release-plz.toml fix: use per-package tags in release-plz (#107) 2026-01-29 05:54:01 +05:30

S2, the durable streams API

s2.dev is a serverless datastore for real-time, streaming data.

s2-lite

s2-lite is an open source, self-hostable server implementation of the S2 API.

It uses SlateDB as its storage engine, which relies entirely on object storage for durability.

It is easy to run s2-lite against object stores like AWS S3 and Tigris. It is a single-node binary with no other external dependencies. Just like s2.dev, data is always durable on object storage before being acknowledged or returned to readers.

You can also simply not specify a --bucket, which makes it operate entirely in-memory. This is great for integration tests involving S2.

Quickstart

Note

Point the S2 CLI or SDKs at your lite instance like this:

export S2_ACCOUNT_ENDPOINT="http://localhost:8080"
export S2_BASIN_ENDPOINT="http://localhost:8080"
export S2_ACCESS_TOKEN="redundant"

Here's how you can run in-memory without any external dependency:

docker run -p 8080:80 ghcr.io/s2-streamstore/s2-lite
AWS S3 bucket example
docker run -p 8080:80 \
  -e AWS_PROFILE=${AWS_PROFILE} \
  -v ~/.aws:/root/.aws:ro \
  ghcr.io/s2-streamstore/s2-lite \
  --bucket ${S3_BUCKET} \
  --path s2lite
Static credentials example (Tigris, R2 etc)
docker run -p 8080:80 \
  -e AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} \
  -e AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} \
  -e AWS_ENDPOINT_URL_S3=${AWS_ENDPOINT_URL_S3} \
  ghcr.io/s2-streamstore/s2-lite \
  --bucket ${S3_BUCKET} \
  --path s2lite

Let's make sure the server is ready:

while ! curl -sf ${S2_ACCOUNT_ENDPOINT}/ping -o /dev/null; do echo Waiting...; sleep 2; done && echo Up!

Install the CLI or upgrade it if s2 --version is older than 0.25

Let's create a basin with auto-creation of streams enabled:

s2 create-basin liteness --create-stream-on-append --create-stream-on-read

Test your performance:

s2 bench liteness --target-mibps 10 --duration 5s --catchup-delay 0s

S2 Benchmark

Now let's try streaming sessions. In one or more new terminals (make sure you re-export the env vars noted above),

s2 read s2://liteness/starwars 2> /dev/null

Now back from your original terminal, let's write to the stream:

nc starwars.s2.dev 23 | s2 append s2://liteness/starwars

S2 Star Wars Streaming

Monitoring

/ping will pong, you can treat 200 as a success response for readiness and liveness checks

/metrics returns Prometheus text format

Internals

SlateDB settings

Settings reference

Use SL8_ prefixed environment variables, e.g.:

# Defaults to 50ms for remote bucket / 5ms in-memory
SL8_FLUSH_INTERVAL=10ms

Design

Concepts

  • HTTP serving is implemented using axum
  • Each stream corresponds to a Tokio task called streamer that owns the current tail position, serializes appends, and broadcasts acknowledged records to followers
  • Appends are pipelined to improve performance against high-latency object storage
  • lite::backend::kv::Key documents the data modeling in SlateDB

Caveats

Compatibility

API Coverage

Tip

Complete specs are available: OpenAPI for the REST-ful core, Protobuf definitions, and S2S which is the streaming session protocol.

Fully supported

  • /basins
  • /streams
  • /streams/{stream}/records

Important

Unlike the cloud service where the basin is implicit as a subdomain, /streams/* requests must specify the basin using the S2-Basin header. The SDKs take care of this automatically.

Not supported