Configuration
Configure Fabriq in library code with the Config struct and functional options, or via the environment variables the binary reads.
Fabriq takes its configuration two ways: library code passes a fabriq.Config value (plus functional Options) to fabriq.Open, and the fabriq binary loads the same shape through Forge's config manager — a config.yaml file plus FABRIQ_* environment overrides. This page is task-oriented — the exhaustive field-by-field reference lives at Reference: Configuration.
The Config shape
fabriq.Config declares which stores exist and which projections run. Entities are not configured here — they are registered in code through the registry.
type Config struct {
Postgres PostgresConfig // DSN required (single-shard): the source of truth
Shards []ShardConfig // optional: shard the source of truth by tenant
Redis RedisConfig // event fan-out; required for subscriptions + projections
FalkorDB FalkorDBConfig // graph projection engine
Elasticsearch ElasticsearchConfig // search projection engine
Projections ProjectionsConfig // Graph/Search on-off toggles
Subscriptions SubscriptionsConfig // delta-plane tuning
}Postgres is the only required store. PostgresConfig.DSN must be set; PostgresConfig.PoolSize is optional. Everything else is opt-in and degrades to a typed ErrStoreNotConfigured when absent. To scale the source of truth across multiple Postgres instances, set Shards in place of Postgres — a single Postgres block is the one-shard case. See Sharding.
The subscription plane is tuned through three fields:
type SubscriptionsConfig struct {
ConflationWindow time.Duration // hub last-write-wins flush window (default 150ms)
StreamMaxLen int64 // approximate MAXLEN per Redis change channel (default 500)
SubscribeBuffer int // per-subscriber delta buffer (default 64)
}Library vs binary
f, stores, err := fabriq.Open(ctx, reg, fabriq.Config{
Postgres: fabriq.PostgresConfig{
DSN: "postgres://user:pass@pg:5432/fabriq?sslmode=disable",
PoolSize: 16,
},
Redis: fabriq.RedisConfig{Addr: "redis:6379"},
// Turn projections on only when their backing store is configured.
FalkorDB: fabriq.FalkorDBConfig{Addr: "falkordb:6379"},
Elasticsearch: fabriq.ElasticsearchConfig{Addrs: []string{"http://es:9200"}},
Projections: fabriq.ProjectionsConfig{Graph: true, Search: true},
Subscriptions: fabriq.SubscriptionsConfig{
ConflationWindow: 200 * time.Millisecond,
StreamMaxLen: 1000,
SubscribeBuffer: 128,
},
})export FABRIQ_POSTGRES_DSN="postgres://user:pass@pg:5432/fabriq?sslmode=disable"
export FABRIQ_REDIS_ADDR="redis:6379"
export FABRIQ_FALKORDB_ADDR="falkordb:6379"
export FABRIQ_ELASTICSEARCH_ADDRS="http://es:9200"
export FABRIQ_HTTP_ADDR=":8081"
fabriq serveThe binary loads its Config through Forge's config manager: it auto-discovers config.yaml (and config.local.yaml) in the working directory and /etc/fabriq, then overlays FABRIQ_* environment variables on top — env wins over the file. So a container can bake the static shape into config.yaml and inject endpoints and secrets via env. Every key maps to an env var under the FABRIQ_ prefix with _ joining nested keys, so postgres.dsn ↔ FABRIQ_POSTGRES_DSN, redis.addr ↔ FABRIQ_REDIS_ADDR, elasticsearch.addrs ↔ FABRIQ_ELASTICSEARCH_ADDRS (comma-separated).
# config.yaml — discovered from the working directory or /etc/fabriq.
postgres:
dsn: postgres://user:pass@pg:5432/fabriq?sslmode=require
pool_size: 16
redis:
addr: redis:6379
falkordb:
addr: falkordb:6379 # enables the graph projection
elasticsearch:
addrs:
- https://es:9200 # enables the search projection
projections:
graph: true
search: true
subscriptions:
conflation_window: 150ms
stream_max_len: 1024
subscribe_buffer: 64Unlike the env path, config.yaml can set the subscription-plane knobs and projection toggles directly. A starter file ships at config.example.yaml. The operator commands (migrate, inspect, rebuild, reconcile) still take their connection from --dsn/FABRIQ_* rather than the config file — only serve reads the full config.
Functional options
Pass Option values after the Config to fabriq.Open (or fabriq.New). These come from options.go:
f, stores, err := fabriq.Open(ctx, reg, cfg,
fabriq.WithConflationWindow(200*time.Millisecond),
fabriq.WithSubscribeBuffer(128),
fabriq.WithStreamMaxLen(1000),
fabriq.WithWaitPollInterval(25*time.Millisecond),
fabriq.WithUpcasters(chain),
fabriq.WithAuthz(authzFn),
fabriq.WithDocumentAuthz(docAuthzFn),
)The full set:
WithConflationWindow(d time.Duration)— the hub's last-write-wins flush window (spec range 100–250ms; default 150ms).WithSubscribeBuffer(n int)— per-subscriber delta buffer (default 64). A full buffer drops; clients refetch and resume byLast-Event-ID.WithStreamMaxLen(n int64)— approximateMAXLENfor per-channel Redis streams, i.e. catch-up depth before clients must refetch (default 500).WithWaitPollInterval(d time.Duration)— poll cadence forWaitForProjection(default 25ms).WithAuthz(fn subscribe.AuthzFunc)— the subscribe-time authorization hook, consulted when resolving aSubscribeScopeto a channel.WithDocumentAuthz(fn func(ctx context.Context, docID string) error)— the document-plane authorization hook, consulted for bothApplyUpdate(writes) andSubscribeDocument(reads). Without it, any authenticated member of the tenant may touch any of the tenant's documents.WithUpcasters(chain *event.UpcasterChain)— registers the event payload upcaster chain. Projection engines apply it at decode, so appliers only ever see the latest payload shape.WithTraceparent(fn func(context.Context) string)— supplies the W3C traceparent extractor stamped into event envelopes.Openalready installs the production extractor by default, so override only for custom propagation.WithClock(now func() time.Time)— overrides the command-plane clock (tests).
Config derives some options for you
Config.Options() translates the Subscriptions block into the matching options, so a value you set on Config and the equivalent option are interchangeable:
func (c Config) Options() []Option {
var opts []Option
if c.Subscriptions.ConflationWindow > 0 {
opts = append(opts, WithConflationWindow(c.Subscriptions.ConflationWindow))
}
if c.Subscriptions.StreamMaxLen > 0 {
opts = append(opts, WithStreamMaxLen(c.Subscriptions.StreamMaxLen))
}
if c.Subscriptions.SubscribeBuffer > 0 {
opts = append(opts, WithSubscribeBuffer(c.Subscriptions.SubscribeBuffer))
}
return opts
}Open prepends cfg.Options() to the explicit options you pass, so an explicit option wins on a later duplicate. Use Config for declarative deployment values; use options for behaviors with no config field (authz hooks, upcasters, clock).
Environment variables
Forge's config manager reads these, overlaying them on any config.yaml (env wins). --dsn is a global flag that overrides FABRIQ_POSTGRES_DSN for ad-hoc operator commands.
| Variable | Required | Default | Purpose |
|---|---|---|---|
FABRIQ_POSTGRES_DSN | to serve | — | Postgres DSN; the source of truth. Overridable with --dsn. |
FABRIQ_REDIS_ADDR | to serve | — | Redis address for the event stream and subscriptions. |
FABRIQ_FALKORDB_ADDR | no | — | FalkorDB address; enables the graph projection. |
FABRIQ_ELASTICSEARCH_ADDRS | no | — | Comma-separated Elasticsearch addresses; enables the search projection. |
FABRIQ_HTTP_ADDR | no | :8081 | Worker HTTP listen address (health, metrics). |
FABRIQ_RECONCILE_INTERVAL | no | — | Reconciliation cadence as a Go duration; "0" disables it. |
The operator commands (migrate, inspect, rebuild, reconcile) open their own stores from --dsn/FABRIQ_POSTGRES_DSN and never serve. Only fabriq serve connects the full worker plane. See CLI.
Validation
Config.Validate() runs cross-field checks before Open dials anything — it never opens a connection. It enforces:
postgres.dsnis set (the source of truth).- If
projections.graphis on,falkordb.addris non-empty. - If
projections.searchis on,elasticsearch.addrsis non-empty. - If either projection is on,
redis.addris set (projections need the event stream). subscriptions.conflation_windowis>= 0.
A failed check returns a descriptive error and Open aborts before touching the network, so a misconfiguration surfaces at startup rather than on the first request.