Documentation Index
Fetch the complete documentation index at: https://s2.dev/docs/llms.txt
Use this file to discover all available pages before exploring further.
Define your S2 infrastructure in a JSON spec file and apply it declaratively using the CLI. Resources that already exist are reconfigured to match the spec, and only the fields present in the spec are updated.
The spec is a JSON file with a top-level basins array. Each basin entry has a name, an optional config, and an optional streams array.
{
"$schema": "https://raw.githubusercontent.com/s2-streamstore/s2/main/cli/schema.json",
"basins": [
{
"name": "my-basin",
"config": {
"stream_cipher": "aegis-256",
"create_stream_on_append": true,
"default_stream_config": {
"storage_class": "express",
"retention_policy": "7days"
}
},
"streams": [
{
"name": "events",
"config": {
"storage_class": "standard",
"retention_policy": "infinite"
}
}
]
}
]
}
IDE setup
Add the $schema key to your spec file to point to the published schema hosted on GitHub to enable inline validation and autocomplete in your editor:
{
"$schema": "https://raw.githubusercontent.com/s2-streamstore/s2/main/cli/schema.json",
"basins": []
}
Or generate a local copy and reference it by path:
s2 apply --schema > schema.json
{
"$schema": "./schema.json",
"basins": []
}
VS Code: configure schema associations in .vscode/settings.json so $schema is not needed in every file:
{
"json.schemas": [
{
"fileMatch": ["*.s2spec.json", "s2-spec.json"],
"url": "https://raw.githubusercontent.com/s2-streamstore/s2/main/cli/schema.json"
}
]
}
You can use any glob pattern in fileMatch to match your spec files by naming convention.
IntelliJ / JetBrains IDEs: add a schema mapping in the IDE settings:
- Open Settings (
Ctrl+Alt+S / ⌘,) → Languages & Frameworks → Schemas and DTDs → JSON Schema Mappings
- Click + to add a new mapping
- Give the mapping a name (e.g.
S2 Spec)
- Set the schema to
https://raw.githubusercontent.com/s2-streamstore/s2/main/cli/schema.json (or a local path)
- Set the Schema version to JSON Schema version 7
- Add file patterns to associate (e.g.
*.s2spec.json)
Basin config fields
| Field | Type | Description |
|---|
default_stream_config | object | Default stream configuration applied to newly created streams |
stream_cipher | "aegis-256" | "aes-256-gcm" | Cipher to apply to streams created after this basin config is in place |
create_stream_on_append | boolean | Auto-create a stream on first append using the default config |
create_stream_on_read | boolean | Auto-create a stream on first read using the default config |
Stream config fields
| Field | Type | Description |
|---|
storage_class | "express" | "standard" | Storage class for recent writes |
retention_policy | "infinite" | humantime string | How long records are retained (e.g. "7days", "1week") |
timestamping | object | Timestamping behavior (see below) |
delete_on_empty | object | Delete the stream automatically when empty |
Timestamping
{
"mode": "client-prefer",
"uncapped": false
}
| Field | Values | Description |
|---|
mode | "client-prefer" | "client-require" | "arrival" | How record timestamps are resolved |
uncapped | boolean | Allow client timestamps to exceed the server arrival time |
Delete-on-empty
Set min_age to a humantime duration (e.g. "1day", "2h 30m") to enable automatic deletion of empty streams once they reach that age. The default of "0s" disables delete-on-empty.
Dry run
Preview what would change without making any mutations:
s2 apply -f spec.json --dry-run
Output uses the following legend:
| Symbol | Meaning |
|---|
+ | Will be created |
~ | Will be reconfigured (shows field-level diffs) |
= | Already matches spec, no change |
Example output:
+ basin new-basin
storage_class: express
+ stream new-basin/events
retention_policy: 7days
= basin existing-basin
~ stream existing-basin/logs
retention_policy: 7days → 30days
For the full list of CLI flags, see s2 apply.