Skip to main content
DB

OLTP · OLAP · Streaming · one SQL engine

The only data engine your product needs.

Serve transactions, run analytics and follow live changes from one self-hosted SQL database. Tables stay exact as writes land, derived tables maintain themselves, and queries stay open. No cache, no queue, no stream processor to keep in sync.

Self-hosted · one process · plain SQL over HTTP and WebSocket

nyxdb — one table · one reader · three writers
Reader A
nyx>
Writer A

nyx>

Writer B

nyx>

Writer C

nyx>

Built into the engine
  • MODE APPEND · UPSERT · VERSIONED
  • ATTRIBUTE GROUP
  • CREATE TRANSFORMATION
  • STREAM SELECT
  • AS OF COMMIT
Self-hosted, one node

Store it, derive it, follow it live. One engine.

Every derived table, materialized view, index and live query is fed by the same stream of committed writes, so nothing drifts out of sync.

Tables that remember exactly what you need

Keep every event, only the latest state per key, or the complete history of every change. Read a table as it was at a past commit, and let the engine settle which version wins when writes arrive out of order.

Tables · Versioned history

Derived tables that maintain themselves

Describe the aggregate, the enriched view or the balance you need as a query. NYXDB keeps it current from every committed write, inside the database, so there is no stream processor to run and no results to reconcile.

Transformations · Materialized views

Queries that stay open

Put STREAM in front of a query and get the answer now, then every exact change as new writes land. Dashboards and services follow live state over one WebSocket session instead of polling.

Streaming queries · WebSocket

The challenge

Fresh data should not cost you a cache, a queue and three databases

Stale reads against fresh writes
A value that lags its source by one hop is wrong exactly when it matters most. For a trading desk or a payments team that is not a rounding error, it is a wrong decision.
Glue instead of guarantees
Every extra system adds a copy to keep in sync, serialization work on every hop, and a new way for the cache to disagree with the store.
Two writers, one row
When several pipelines update parts of the same entity, the last writer wins and the others lose. NYXDB gives each writer its own columns and its own version order, so nothing overwrites anything.
one row, two writers, one table
CREATE TABLE balances (
chain_id UINT16 NOT NULL,
address STRING NOT NULL,
token STRING NOT NULL,
amount UINT256 NULL,
updated_at DATETIME64(3, 'UTC') NULL,
balance_index UINT128 NULL,
balance_version UINT64 NULL,
transfer_count UINT64 NULL,
last_transfer_at DATETIME64(3, 'UTC') NULL,
activity_index UINT128 NULL,
PRIMARY KEY (chain_id, address, token),
ATTRIBUTE GROUP holding (amount, updated_at, balance_index, balance_version)
VALID BY (balance_index)
REVISION BY (balance_version),
ATTRIBUTE GROUP activity (transfer_count, last_transfer_at, activity_index)
VALID BY (activity_index)
)
MODE VERSIONED
SHARD BY (address) SHARDS AUTO
ORDER BY (chain_id, address, token)
STORAGE PROFILE ROW;

How it works

From your first table to a live view in three statements

Plain SQL, start to finish. The same two tables run through every example on this site and in the docs.

01

Create a table

Decide what each table remembers: every event, the latest state per key, or the full history of every change. Shard it by a key and pick the storage layout that fits how you read it.

an append table of transfers
CREATE TABLE transfers (
chain_id UINT16 NOT NULL,
token STRING NOT NULL,
sender STRING NOT NULL,
recipient STRING NOT NULL,
amount UINT256 NOT NULL,
transferred_at DATETIME64(3, 'UTC') NOT NULL,
_index UINT128 NOT NULL
)
MODE APPEND
SHARD BY (token) SHARDS AUTO;
02

Follow it live

Put STREAM in front of any query and it stays open: you get the answer now, then every change to it as new writes land. No polling, no second system.

a continuous grouped query
STREAM SELECT chain_id, token, SUM(amount) AS volume, COUNT(*) AS transfers
FROM transfers
GROUP BY chain_id, token;
03

Keep a derived table current

Describe the table you wish you had as a query. A transformation keeps it up to date from every committed write, so the aggregate, the enriched view or the balance is always ready to read.

a fold into one attribute group
CREATE TRANSFORMATION balance_activity INTO balances ATTRIBUTE GROUP activity AS
SELECT
chain_id,
recipient AS address,
token,
COUNT(*) AS transfer_count,
MAX(transferred_at) AS last_transfer_at,
MAX(_index) AS activity_index
FROM transfers
GROUP BY chain_id, recipient, token;

Built for

The workloads that cannot tolerate stale or wrong data

Frequently asked questions

The questions a technical buyer asks first, including the awkward ones. Anything else is answered in the docs, or in the open on GitHub.

A SQL database. Your tables hold exact current and versioned state, and the derived tables, materialized views and streaming queries you define are kept current from every committed write, inside the engine. There is no separate stream processor to run.

Fresh, exact and live, from your first table onward

Start a node, create a table, and watch a streaming query follow it. The docs take you from install to your first self-maintaining derived table.

Self-hosted · one process · your infrastructure