Introduction
Fabriq is a standalone data fabric for Go — the single module through which application code talks to every datastore, enforcing tenancy, eventing, and projection invariants across all of them.
Fabriq is the single module through which application code talks to every datastore. Application code never opens a connection, writes SQL, or calls Redis directly — it holds one facade and reaches every store through typed capability ports. In exchange, fabriq guarantees a small set of invariants that are otherwise impossible to hold across five different engines.
The three invariants
One versioned event per write
Every command runs in a Postgres transaction that appends exactly one versioned event to a transactional outbox. A leader-elected relay publishes it to Redis Streams. Delivery-on-commit: the event can never outrun the data.
Every access is tenant-scoped
Tenant rides on context.Context and is stamped structurally
into every engine — Postgres SET LOCAL + RLS, graph-per-tenant,
index routing, key prefixes — with a grove pre-query hook as a loud
backstop.
Projections rebuild from Postgres
The knowledge graph and the search index are derived projections, never written directly. They can always be rebuilt from the source of truth, and the rebuild is proven identical to the event-built result.
Architecture
Postgres is the source of truth. Redis is the event fan-out. FalkorDB and
Elasticsearch are derived projections. The kernel in core/ is
domain-agnostic and engine-agnostic; engine dialects live exclusively under
adapters/.
commands queries (capability ports) deltas
│ │ ▲
▼ ▼ │
┌──────────────────────────────────────────────────────────────────┴─────┐
│ fabriq (facade) │
│ core/registry core/command core/event core/projection core/subscribe
│ ─────────────────────────── ports ────────────────────────────────── │
│ adapters/postgres (grove) adapters/redis adapters/falkordb adapters/elastic
└─────────────────────────────────────────────────────────────────────────┘
Postgres+Timescale+pgvector Redis Streams FalkorDB Elasticsearch
(source of truth) (fan-out) (projection) (projection)Capability ports
There is deliberately no unified query language. Each storage capability has an explicit, engine-typed port. Relational work speaks SQL through grove, graph work speaks openCypher, search speaks queries over declared fields. No engine types appear in any signature, so adapters stay swappable.
| Port | Engine | Purpose |
|---|---|---|
| Relational | Postgres (grove) | The source of truth: aggregate rows, raw SQL escape hatch. |
| Graph | FalkorDB | Knowledge-graph projection, openCypher traversal + batched hydration. |
| Search | Elasticsearch | Full-text projection over declared fields. |
| Timeseries | TimescaleDB | Bulk telemetry ingest and windowed reads (event-bypass). |
| Vector | pgvector | Embedding upsert and nearest-neighbour search. |
| Document | Postgres + grove CRDT | Collaborative CRDT documents that materialize into ordinary events. |
A first taste
reg := registry.New()
_ = domain.RegisterAll(reg) // or your own entity pack
f, stores, err := fabriq.Open(ctx, reg, fabriq.Config{
Postgres: fabriq.PostgresConfig{DSN: dsn},
Redis: fabriq.RedisConfig{Addr: redisAddr},
})
// Writes: the only path, one versioned event per command.
res, err := f.Exec(tenantCtx, command.Command{
Entity: "asset", Op: command.OpCreate,
Payload: &domain.Asset{Name: "Pump 7", SiteID: siteID},
})
// Reads: capability ports.
var a domain.Asset
err = f.Relational().Get(tenantCtx, "asset", res.AggID, &a)
// Live deltas: server-resolved channel, conflated, resumable.
deltas, err := f.Subscribe(tenantCtx, query.SubscribeScope{
Entity: "asset", Scope: "site", ID: siteID,
})
// Live query: a maintained, ordered, filtered window with
// enter/leave/move/update deltas and exact top-N.
snap, live, cancel, err := f.LiveQuery(tenantCtx, livequery.LiveQuery{
Entity: "asset",
Where: query.Where{query.Eq("kind", "pump")},
Sort: []livequery.SortKey{{Column: "name"}},
Limit: 50,
})Every call requires a tenant-stamped context (tenant.WithTenant), set only
by auth middleware from validated claims. An unstamped context is rejected
before it reaches a store.
Where to go next
Getting Started
Install fabriq, wire the facade, and run your first command, query, and subscription.
Core Concepts
The facade, the registry, tenancy layers, the command/outbox plane, projections, and the delta plane.
Data Planes
Per-port guides: relational, graph, search, timeseries, vector, and the CRDT document plane.
Operations
Deploy the worker, run migrations, rebuild and reconcile projections, and read the metrics and runbooks.
Fabriq is built on the Forge ecosystem: storage on grove, binaries on forge (apps) and forge/cli.