What it is. A time-series engine that lives inside your process — no server to deploy, no network hop to query. It holds billions of timestamped facts and answers range, tag, scan and aggregate queries with SIMD in microseconds.
The problem it kills. The usual answer to “a lot of time-series data, queried fast” is a cluster of database nodes you have to run, tune and pay for. Facts does it on one box.
For example. Store every tick from thousands of sensors or market symbols, then ask “what did device 4200 look like between 09:00 and 09:05” — and get the answer back before a network round-trip would have even finished.
Every record is dead simple, which is exactly why it’s fast. A fact is a timestamp and a tag — that pair is the core. Onto it you attach two kinds of payload, depending on the shape of your data.
The timestamp orders the fact; the tag names the series it belongs to — a device, a market symbol, a driver, a log source.
Everything is indexed and queried on this pair: “this tag, this time window.” Nothing else to declare to get a working store.
For fixed-size fields — a price, a temperature, an RPM — declare typed columns. They’re stored columnar, so a SIMD kernel streams one column at full memory bandwidth.
That’s what makes point access and scans cheap: read just the column you asked for, never the rest of the row.
For variable-size payloads — a log line, a JSON document, a packet, a Dry.Wire record — attach a blob. Facts stores it opaque and hands it straight back.
Blobs can be compressed by a codec you plug in (e.g. LZ4): Facts stores the packed bytes and decompresses transparently on read, so the on-disk footprint shrinks while your code still sees plain payloads. Ideal for logs and journals — see the Log Viewer demo.
The whole stack, one standard. Facts is one layer of a stack — store, network, and serialization — where every layer is tuned to the same bar. There’s no slow component quietly capping the rest, no glue code bleeding away the speed. The same engine scales from a Raspberry Pi to a server, and from one box to many.
Billions of records on a single box — the ceiling is your disk, not the engine, with optional retention caps that evict the oldest data automatically.
Up to ~16 million distinct series per shard, and a variable-size blob of up to 256 MiB per record.
Split a dataset into independent shards for parallel ingest and query. Throughput scales with cores — add shards, add speed — with no cross-shard coordination on the hot path.
Data is written in immutable, self-describing segments. Each one is independently checksummed and recoverable, so a single bad block never takes the dataset down.
Built-in replication with veto-based failover: a stale replica can’t win an election, so two leaders can never exist — no split-brain, and a bounded, well-defined loss window. Break it yourself in the live demo.
A periodic checkpoint sets your maximum loss window, and every segment verifies its own integrity on open and repairs what it can — power loss doesn’t corrupt the store.
One codebase, tuned down to the SIMD for Intel, AMD and ARM, on Windows and Linux — the same engine from a server rack to a $35 board.
Every card is a real Facts engine serving real queries — not a screenshot.
We put Facts against DuckDB — a fast in-process analytical engine — on real TSBS data (the standard time-series benchmark): the same 8.19-million-row dataset, on the same machine, warm. Facts ran on one core; DuckDB got all 32.
Medians from our open harness (Facts.Benchmarks) on real
TSBS cpu-only data. DuckDB got every advantage: all cores, its fastest bulk-load
(Parquet COPY) and a host index. Facts wins on one core everywhere except
storage density — DuckDB compresses; Facts keeps data raw and
memory-mapped for speed. Honest trade, stated plainly.
† Facts supports state-of-the-art compression on blob payloads but keeps column data uncompressed — a deliberate trade: the hot columnar path stays raw and memory-mapped for SIMD-speed scans, while bulky blob data still packs down.
The test above was in-process. This one is over the wire — a real client/server database, where every query travels across a network connection and the answer is serialized back. That’s how you actually run QuestDB and InfluxDB, two of the most popular purpose-built time-series databases. Same 8.19-million-row TSBS dataset, same machine (Ryzen 9 9950X), loopback, warm, durability matched.
Here’s the kicker: Facts used a single connection. We gave the rivals their fastest setup — eight parallel connections each — because Facts doesn’t get faster with more (one is already enough). It still wins every speed test, often by a wide margin.
What that means. On ingest, Facts is about an order of magnitude faster than QuestDB and two orders of magnitude faster than InfluxDB; the high-CPU scan widens the gap further. And the point query — “what’s the latest reading for each sensor,” the single most common dashboard query — comes back in tens of microseconds. Facts answers before a typical network round-trip would even finish. (Exact figures shown above.)
Medians + p99 from our open harness (Facts.Benchmarks,
--tier b) on real TSBS cpu-only data; each engine shown at its
best configuration. Why the gap? Facts speaks a compact
binary wire format; QuestDB and InfluxDB use text line protocols
— every number is spelled out as ASCII and re-parsed, a tax that dominates at
millions of rows per second. Facts’ ingest tops out at one connection because a
single server thread is already saturating the link; the rivals genuinely need the extra
connections to reach the numbers shown. These speeds are with full durability:
re-run with every engine writing to a real NVMe SSD instead of RAM, Facts held at
25 M rows/s — flushing to disk is essentially free for it.
The honest loss is storage density: at rest on disk, QuestDB
(~23 B/point) and InfluxDB (~86 B) compress their columns; Facts keeps
data raw and memory-mapped at ~96 B — the same speed-for-size trade we make
against DuckDB. Both rivals are also full query languages (SQL / Flux, joins,
ad-hoc) with far bigger ecosystems. InfluxDB’s v2/Flux engine is additionally known
to be slow on these access patterns; its newer v3 would narrow the query gap.
loading…