Query your
NATS JetStream
state with
SQL
Zero infrastructure beyond NATS.
Define materialized views over JetStream streams, then query the resulting state with
SELECT ... WHERE ...
— no Postgres, no Redis, no Kafka. Just NATS.
Stream → Materialize → Query
natsql is a thin SQL query layer over NATS KV, fed by a configurable materializer that consumes your streams.
1. Define views
Specify source stream, key fields, and columns in YAML/JSON config
2. Publish events
The materializer consumes JetStream messages in order, automatically
3. KV storage
Materialized state is stored in a NATS KV bucket — PK lookups are O(1)
4. Query with SQL
Query via NATS, HTTP, or in-process Go — returns typed JSON
“Give a developer a stream, and they’ll build event-driven systems. Give them a materialized view engine, and they’ll query their state.”
Try it in 60 seconds
No Docker, no databases, no config. Just Go.
package main
import (
"context"
"fmt"
"time"
"github.com/nats-io/nats.go/jetstream"
"github.com/gacopys/natsql"
)
func main() {
ctx := context.Background()
cfg := &natsql.Config{
Views: []natsql.ViewConfig{{
Name: "users", SourceStream: "events",
KeyFields: []string{"user_id"},
Columns: []natsql.ColumnConfig{
{Name: "user_id", From: "id", Type: natsql.ColumnTypeString, PrimaryKey: true},
{Name: "name", From: "name", Type: natsql.ColumnTypeString},
},
}},
}
eng, _ := natsql.NewEmbedded(cfg)
defer eng.Close()
js, _ := jetstream.New(eng.NC())
js.CreateOrUpdateStream(ctx, jetstream.StreamConfig{
Name: "events", Subjects: []string{"events.>"},
})
eng.Start(ctx)
js.Publish(ctx, "events.user-created", []byte(`{"id": "abc", "name": "Alice"}`))
time.Sleep(time.Second)
fmt.Println(eng.Query(ctx, "SELECT name FROM users WHERE user_id = 'abc'").Results)
}
Everything you need,
nothing you don’t
Queryable State
SELECT
from your event streams without maintaining snapshots or bolting on a second database. PK lookups are O(1) KV gets.
Zero Infrastructure
No Postgres, no Redis, no Kafka. natsql runs entirely on NATS JetStream. Embedded NATS means zero dependencies for development.
SQL-Powered
Standard read-only SQL via the vitess sqlparser. Project columns, filter by PK, combine conditions with AND.
Event-Driven
Materialize any JetStream stream into a queryable KV snapshot. Malformed events go to a DLQ — your pipeline keeps running.
Perfect for
- NATS developers who need simple queryable state without leaving the NATS ecosystem
- Event-driven system builders who want to materialize a stream into a KV snapshot and query it
- Team leads looking to reduce infrastructure surface area — one less Postgres or Redis cluster
- Anyone prototyping — embedded NATS means you can be up in 60 seconds with zero dependencies