XRAPH/Work/Data fabric
Go · since 2026

Fabriq

One write path for applications that outgrew a single database. A command commits state, a versioned event and an outbox row in the same Postgres transaction; a leader-elected relay publishes to Redis Streams; the graph (FalkorDB) and search (Elasticsearch) projections are rebuilt from that log rather than written to directly. Tenancy is structural, using row level security, a graph per tenant and index routing, rather than a WHERE clause you can forget.

Language
Go
Category
Data fabric
Since
2026
Stars
1
Repository Docs
01

Highlights

3 claims
H.01
Onewritepath
Exec, and nowhere else

Every command commits inside a Postgres transaction that appends exactly one versioned event. Nothing is written twice and nothing is lost.

H.02
Structural
Tenancy in every engine

Tenant rides the context into row-level security, graph-per-tenant, index routing and key prefixes. Cross-tenant reads cannot happen.

H.03
Rebuildable
Graph and search are projections

Neither is written directly. Blue-green rebuilds swap in atomically and a reconciler heals drift through the same outbox.

02

Invariants

3 entries

Structural properties of the fabric, which is the kind you cannot forget to apply.

02.1
Transactional outbox

One write, one event

Every command commits inside a Postgres transaction that appends exactly one versioned event. A leader-elected relay publishes it to Redis Streams, so nothing is written twice and nothing is lost.

PostgresRedis
02.2
Structural tenancy

Tenant-scoped in every engine

Tenant rides on the context and is stamped into row-level security in Postgres, graph-per-tenant, index routing and key prefixes. A cross-tenant read has nowhere to run.

RLS
02.3
Derived projections

Always rebuildable

Graph and search are projections. Nothing writes to them directly. Blue-green rebuilds swap in atomically, and a reconciler detects drift and heals it through the same outbox.

Blue-green
03

The write path

Four stages

Following one write through the fabric, from the facade to every engine that ends up holding it.

03.01

f.Exec(cmd)

A command enters the facade, validated against the registry with tenant and traceparent stamped on the envelope.

Validated
03.02

Postgres commit

State and exactly one versioned event commit atomically, because the outbox lives in the same transaction.

Atomic
03.03

Leader relay

A leader-elected relay wakes on LISTEN/NOTIFY and publishes the event to Redis Streams in order.

Ordered
03.04

Woven outward

Consumer groups project the event into graph and search, redact it for analytics and push live deltas to subscribers.

Fan-out
04

Capability ports

Twelve ports

Reads go through typed ports and writes go through Exec. The fabric decides which engine serves which shape, and your code imports one package.

04.01

Relational

Typed gets, filtered lists and pagination against the source of truth.

Postgres
04.02

Timeseries

Bulk telemetry ingest and windowed reads on hypertables.

TimescaleDB
04.03

Vector

Similarity search over embeddings with HNSW indexes.

pgvector
04.04

Spatial

Radius and nearest-neighbour search over WKT geometries, in true metres.

PostGIS
04.05

Graph

openCypher traversals with one-shot, batched hydration.

FalkorDB
04.06

Search

Full-text multi-match over declared fields, with alias-swap rebuilds.

Elasticsearch
04.07

Document

CRDT documents that materialise into ordinary versioned entities.

Merge engine
04.08

Blob

External byte storage with content-addressable dedup. Files stay cataloged in Postgres and the bytes never touch it.

Object store
04.09

Subscribe

Conflated live deltas with Last-Event-ID resume over SSE.

Redis Streams
04.10

LiveQuery

Maintained, ordered, filtered windows with enter, leave and move deltas, exact to top-N.

SSE
04.11

Analytics

A typed cube over the tenant’s own events and facts, with metrics that materialise themselves in the background.

Postgres
04.12

Cache

A transparent two-level read-through cache behind the read ports, invalidated on write.

Opt-in
05

Anatomy

4 modules
01

Command plane

One transaction and an outbox; every write emits exactly one versioned event.

02

Postgres

The source of truth. Everything else is a projection.

03

Fan-out

Redis Streams carrying events to graph, search and live queries.

04

Reconciler

Re-projects the affected window when an observation arrives late.

06

Why it exists

Design notes

#What it is

Fabriq is a data fabric for Go: one transactional write path that fans out to relational, time-series, vector, graph and search engines. It exists because an application that outgrows a single database usually grows a second write in the same handler, and that second write is where silent divergence starts.

#Three invariants

Everything else in the design follows from these, and each is enforced structurally rather than by convention.

  • Every write emits exactly one versioned event. A command runs in a Postgres transaction that applies state, appends the event and inserts an outbox row. A leader-elected relay, woken by LISTEN/NOTIFY, publishes it to Redis Streams in order.
  • Every access is tenant-scoped. Tenant rides on context.Context and is stamped into each engine the way that engine can enforce: Postgres SET LOCAL plus row-level security, a FalkorDB graph per tenant, Elasticsearch index routing, Redis key prefixes. A pre-query hook is a loud backstop, not the mechanism.
  • Projections are rebuildable from Postgres. The knowledge graph and the search index are derived. Nothing writes to them except an applier reading the log, so both can be dropped and replayed.

#What is implemented

All of the following has integration coverage:

  • Command plane and outbox: registry-driven commands, optimistic concurrency, atomic batches.
  • Postgres as source of truth: RLS verified as a non-superuser, Timescale hypertables for bulk telemetry, pgvector with HNSW for similarity, and PostGIS for geometry with GiST-accelerated Within queries (SRID 4326 resolves to true metres).
  • Dynamic entities: entities defined at runtime from a schema descriptor rather than a Go struct, with fabriq-managed DDL, map-native reads and writes over real typed columns, and the full projection pipeline. It is a fenced, opt-in lane so the migrations-as-authority discipline stays intact for everything else.
  • Redis Streams fan-out: consumer groups with XAUTOCLAIM recovery, plus a subscription hub with delta conflation, SSE and Last-Event-ID resume.
  • Live queries: a filter/sort/limit subscription returns a snapshot then exact enter, leave, move and update deltas. The in-engine window stays an exact prefix of the Postgres-ordered result through a cushion and keyset boundary refill, so top-N is exact at all times.
  • Graph projection: an openCypher dialect behind a conformance suite that acts as the engine-swap gate, a batched traverse-and-hydrate, and blue-green rebuilds verified to produce an identical graph.
  • Search projection: version-gated bulk writes, lazy per-tenant index and alias provisioning, and atomic alias-swap rebuilds.
  • Reconciler: per-aggregate drift detection between Postgres and the projections, classified as missing, stale or zombie.

#Operating it

cmd/fabriq is the whole fabric in one binary. serve runs the worker (outbox relay, projection consumers, reconciler and document plane), and migrate, rebuild, reconcile and inspect are the operator commands.

The property worth the complexity is not exactly-once delivery. It is that dropping a projection entirely is a routine operation rather than an incident.
07

Signals

GitHub
Stars
1
Language
Go
Since
2026
Adopters
00

Shipping something on Fabriq? Nobody is listed here yet. Tell me what you built and you will be the first.

Get listed