Supabase PG17 — Canonical Relational Truth
Platform 6 of 12·OS Layer 7 (Memory & Data Layer)·Required in all deployment modes
Scope of this page. Reference material for the Supabase platform: what it is, what it is normally used for, and how and why Synedrix OS uses it. It is descriptive, not normative — where this page and a canonical spec in
docs/os/disagree, the canonical spec wins. Platform responsibilities are set by Tech Stack §5; the table-level schema is Agent DB Schema.
What Supabase is
Supabase is a platform built around Postgres, not a database in its own right. Its own architecture documentation is explicit about the relationship: “Postgres is the core of Supabase. We do not abstract the Postgres database—you can access it and use it with full privileges.”
The stated design position is that Supabase composes existing open source tools rather than writing replacements: “we use Postgres rather than a NoSQL store. This choice was deliberate.” Each project is one Postgres instance with a set of services in front of it, behind a single API gateway.
| Component | Official definition | Language |
|---|---|---|
| Postgres | “Postgres is the core of Supabase. We do not abstract the Postgres database—you can access it and use it with full privileges.” | C |
| PostgREST (API) | “A standalone web server that turns your Postgres database directly into a RESTful API.” | Haskell |
| Auth (formerly GoTrue) | “A JWT-based API for managing users and issuing access tokens. This integrates with Postgres’s Row Level Security and the API servers.” | Go |
| Realtime | “A scalable WebSocket engine for managing user Presence, broadcasting messages, and streaming database changes.” | Elixir |
| Storage API | “An S3-compatible object storage service that stores metadata in Postgres.” | Node.js / TypeScript |
| Edge Functions (Deno) | “A modern runtime for JavaScript and TypeScript.” | TypeScript / Rust |
postgres-meta | “A RESTful API for managing your Postgres. Fetch tables, add roles, and run queries.” | Node.js / TypeScript |
| Supavisor | “A cloud-native, multi-tenant Postgres connection pooler.” | Elixir |
| Studio | “An open source Dashboard for managing your database and services.” | TypeScript |
| Envoy | API gateway. Default in the self-hosted stack, “Kong available as an optional override”. | C++ |
The important structural fact is that every service in that list terminates at the same Postgres instance. Auth writes users into the auth schema. Storage keeps object metadata in Postgres. PostgREST is “a thin API layer on top of Postgres” that resolves each request to a single SQL statement. There is no second store to reconcile.
Row Level Security
RLS is the piece of Supabase that matters most to a governed system, and it is not a Supabase invention — it is a Postgres feature that Supabase makes central. Per the official documentation: “When you need granular authorization rules, nothing beats Postgres’s Row Level Security (RLS).” Policies “are Postgres’s rule engine… You can just think of them as adding a WHERE clause to every query.”
Three properties follow:
- It is enforced by the database, not the caller. “RLS is a Postgres primitive and can provide ‘defense in depth’ to protect your data from malicious actors even when accessed through third-party tooling.” An application that forgets its tenant filter still gets a filtered result.
- It is mandatory on anything exposed. “RLS must always be enabled on any tables stored in an exposed schema. By default, this is the
publicschema.” Once enabled, “no data will be accessible via the API when using a publishable key, until you create policies” — deny-by-default. - It composes with identity. Supabase maps every request to the
anon(unauthenticated) orauthenticatedPostgres role, and policies can target roles with aTOclause and read JWT claims through helpers such asauth.uid().
What Supabase is normally used for
The cases Supabase’s own documentation leads with:
- A Postgres database with the plumbing already attached — a dedicated Postgres instance plus auto-generated APIs, auth, storage and realtime, without assembling those services by hand.
- Auto-generated data APIs — “Supabase auto-generates an API directly from your database schema”, instant and self-documenting, reflected from the schema as it changes, with
pg_graphqlproviding a GraphQL surface over the same tables. - Authentication and user management — JWT issue and refresh, social login and SSO, with the user table living in the same database as the application data.
- Authorization at the row level — RLS combined with Supabase Auth for “end-to-end user security from the browser to the database”.
- Realtime data — Broadcast, Presence and Postgres Changes over WebSockets for collaborative and live-dashboard workloads.
- Extension-driven workloads — vectors (
pgvector), scheduling (pg_cron), queues, and the rest of the Postgres extension surface, run inside the database rather than beside it.
The common thread is that Supabase owns state and access to state. It does not sequence work and it does not reason.
How Synedrix OS uses it
Supabase PG17 is the canonical relational truth of Synedrix OS and sits at Layer 7 (Memory & Data Layer) of the twelve-layer taxonomy, alongside Redis, QuestDB, Neo4j and Qdrant. It is required in all three deployment modes.
It is the most authoritative store in the stack. Where two platforms hold overlapping facts, Supabase is the one that is right: the Layered Truth Summary assigns it “business entities, workflow state, approvals, audit trails”, and everything else at Layer 7 is a projection, a cache, or a different shape of the same underlying record.
flowchart LR
n1([Supabase PG17]):::term
subgraph What it owns
n2[Business entities]:::agent
n3[Workflow state snapshots]:::agent
n4[Policies and approvals]:::agent
n5[Audit trails]:::agent
n6[Operator configuration]:::agent
n7[Domain-pack data models]:::agent
n8[Agent definitions]:::agent
end
n1 --> n2
subgraph What it does not own
n9[Hot execution state coordination idempotency keys]:::warn
n10[Redis]:::term
n9 --> n10
n11[High-volume time-series and temporal aggregation]:::warn
n12[QuestDB]:::term
n11 --> n12
n13[Queryable lineage and relationship graph]:::warn
n14[Neo4j]:::term
n13 --> n14
n15[Semantic retrieval and similarity search]:::warn
n16[Qdrant]:::term
n15 --> n16
n17[LLM traces prompts evaluations]:::warn
n18[Langfuse]:::term
n17 --> n18
n19[Workflow sequencing retries approval routing]:::warn
n20[n8n]:::term
n19 --> n20
n21[Stateful cyclic multi-agent reasoning]:::warn
n22[LangGraph]:::term
n21 --> n22
end
n1 --> n9
subgraph Why Supabase
n23[It is Postgres undisguised]:::term
n24[RLS turns multi-tenancy into a database guarantee]:::term
n25[One store several access shapes]:::term
n26[Self-hostable in full under permissive licences]:::term
n27[Studio is an operator surface]:::term
end
n1 --> n23
What it owns
Per Tech Stack §5, Supabase owns:
- Business entities
- Workflow state snapshots
- Policies and approvals
- Audit trails
- Operator configuration
- Domain-pack data models
- Agent definitions
Access pattern is standard read/write at low tens of milliseconds — a transactional store, queried on the critical path of workflow execution.
The agent database schema
The relational schema for the agent layer is already specified in full. Agent DB Schema is the detailed source for every table named below and is not summarised here. It defines the agent layer across seven table groups:
| Group | Concern |
|---|---|
| A | Agent definition — static, versioned: identity, prompt layers, authority profiles, contracts, tool bindings, memory profiles, task surfaces, workflow roles, interop profiles, policy bindings |
| B | Registry and lifecycle — live registry entries, registry versions, capability tags, dependency declarations, instance controls, lifecycle events |
| C | Runtime policy — model routing, token and cost budgets, retry and circuit-breaker state |
| D | Execution records — append-only invocation starts and outcomes, tool call records, workflow task assignments |
| E | Evaluation and quality — eval suites, runs, results, promotion gates, compliance events |
| F | Lineage — the canonical write record for relationships, projected into Neo4j |
| G | Memory control plane — memory records, their lineage, promotions, tombstones and the brokered recall log; write-authoritative for every audit-bearing memory tier |
Four of that spec’s invariants are the reason Supabase is the layer it is, rather than one store among several:
- All canonical agent configuration lives in Supabase Postgres. Redis holds only ephemeral hot state. The two are not interchangeable and a value present in both is authoritative only in Supabase.
- Invocation starts, invocation outcomes, tool-call records, lifecycle events and compliance breach events are append-only and must not be updated or deleted.
- Every table must have forced RLS policies enforcing tenant, domain-pack and business-instance scoping, with the tenant boundary defined in the Tenancy Spec.
- Lineage links are written to Postgres first, then synced to Neo4j. Postgres is the write-authoritative source; the graph is the queryable projection.
The Outcome Spec writes into the same store: immutable agent starts and completed tool calls are persisted as they happen, then the terminal agent outcome is inserted into agent_invocation_outcomes; workflow outcomes remain in workflow_outcomes. Both outcome records are append-only, with the emitted event carrying only the outcome_id, correlation_id, status and duration_ms — the full outcome record stays in Supabase.
RLS as a governance primitive
Layer 12 (Business Instance Layer) configures a concrete tenant runtime: pack selection, credentials, thresholds, environment settings, deployment_mode. Tenancy has to be enforced somewhere, and enforcing it only in orchestration code means every new caller is a new opportunity to leak across tenants.
RLS moves that boundary into the database. Because policies act as an implicit WHERE clause evaluated on every access, a business instance’s rows are unreachable to another instance’s session regardless of which service is asking — n8n, the LangGraph runtime, a domain-pack agent, or an operator with a psql prompt. This is the “defense in depth” property in Supabase’s own words, and it is what makes instance_id scoping (for example on agent_instance_controls, which is unique per instance and agent) a control rather than a convention.
The practical consequence for anyone extending the schema: a new table without an RLS policy is a governance defect, not a missing optimisation. The Agent DB Schema states the requirement without exception.
Append-only audit trails
Principle 7 (Explainability and audit by design) requires that every action be traceable with a clear what, why, and under whose authority. The Agent DB Schema’s own rationale is blunt about the implication: “A mutable invocation record cannot satisfy this requirement reliably.”
Append-only is a design constraint the OS imposes, not a Postgres table type. It has to be constructed — from grants, RLS policies that permit INSERT but not UPDATE or tenant-facing DELETE, and triggers — and it therefore has to be verified. agent_invocations, agent_invocation_outcomes, agent_tool_call_records, agent_runtime_events, agent_lifecycle_events and agent_eval_compliance_events are the tables where that matters most. The restricted retention role may delete eligible invocation starts, outcomes, and tool-call records under policy; runtime, lifecycle, and compliance events are retained indefinitely.
The registry is append-only at runtime
The agent registry is append-only at runtime — an OS invariant, not a schema preference. Registry mutation is a governed, versioned, out-of-band operation: Agent Registry Spec governs the record shape, Agent Registry holds the OS agent definitions, and the schema implements the split as agent_registry_entries (current live record) against agent_registry_versions and agent_lifecycle_events (history that is never rewritten).
No agent adds itself to the registry mid-execution. An agent that could grant itself capabilities at runtime has no meaningful authority boundary.
What it does not own
| Concern | Owner |
|---|---|
| Hot execution state, coordination, idempotency keys | Redis (Layer 7) |
| High-volume time-series and temporal aggregation | QuestDB (Layer 7) |
| Queryable lineage and relationship graph | Neo4j (Layer 7) |
| Semantic retrieval and similarity search | Qdrant (Layer 7) |
| LLM traces, prompts, evaluations | Langfuse (Layer 10) |
| Workflow sequencing, retries, approval routing | n8n (Layer 3) |
| Stateful, cyclic, multi-agent reasoning | LangGraph (Layer 4) |
| Policy decisions | Policy Guard (os-agt-002) |
A note on the Supabase components themselves: the OS depends on the Postgres core, and on RLS in particular. PostgREST, Auth, Realtime, Storage and Edge Functions ship with the platform and are available, but they are not load-bearing for OS governance — orchestration is n8n’s job at Layer 3 and the governed agent surface is LangGraph’s at Layer 4. Reaching for Edge Functions to run business logic, or Realtime to trigger work, would put execution behind the orchestration layer’s back and is not how the OS is specified. Workflow triggers belong in the Workflow Contract Spec.
How it is operated
Self-hosting is Docker Compose from the docker/ directory of the supabase/supabase repository, which brings up Postgres, Envoy, Studio, Auth, PostgREST, Realtime, Storage, imgproxy, postgres-meta, Edge Runtime and Supavisor.
Three operational details are worth recording:
- Postgres 17 is now the default, not an explicit choice. The base
docker-compose.ymlpinssupabase/postgres:17.6.1.136. Staying on PG15 — an existing deployment not yet upgraded, or a rollback — means layering thedocker-compose.pg15.ymloverride (which pinssupabase/postgres:15.8.1.085); the documentedutils/upgrade-pg17.shscript handles an in-place upgrade, since the two versions use different PostgreSQL user IDs, which can otherwise cause permission issues against an existing volume.timescaledb,plv8,plcoffeeandpllsare still not available in the Postgres 17 builds. - Connections go through Supavisor. The self-hosted stack ships the pooler in front of Postgres, session mode on port
5432and transaction mode on6543. - Logs and analytics are opt-in. Logflare and Vector are not in the default configuration and are enabled via a compose override. Synedrix OS reads operational telemetry from the Layer 10 platforms, so this is a deliberate non-adoption rather than a gap: database telemetry should reach Grafana, not a second analytics stack inside Supabase.
Write-authoritative for the memory fabric
Supabase’s role as the most authoritative store in the stack becomes a named invariant under the
Memory Fabric Spec: it is write-authoritative for every audit-bearing memory tier. episodic, semantic, procedural, profile and relational records are written here; the Qdrant points, the Neo4j entity graph and the LangGraph store are all projections of them.
The operational test is blunt and worth running: wipe a projection, rebuild it from Postgres, and behaviour must be identical. A projection that cannot be rebuilt has quietly become a second source of truth.
The memory control plane adds one table group (Agent DB Schema Group G): memory_records, memory_record_lineage, memory_promotions, memory_tombstones and memory_recall_log. Four of those five are append-only, for the same reason invocation records are — they are the governance trail for what the fabric remembered, who was allowed to read it, and what was destroyed.
The tombstone design is where this matters most. When a tenant exercises a right to erasure, content is set to NULL and a memory_tombstones row is written in the same transaction, retaining the content hash, the provenance, the derived-from chain and the approving policy decision. Afterwards it remains provable that a record existed, what produced it and that it was destroyed under an approval — while the content itself is unrecoverable. RLS carries the tenant boundary here as it does everywhere else, and tenant_id is first in every memory scope tuple so that a malformed scope fails closed rather than open.
Why Supabase
- It is Postgres, undisguised. The OS needs a canonical relational store with transactions, foreign keys, constraints and real migrations. Supabase does not abstract the database — full privileges, standard SQL, standard tooling — so the canonical layer is a Postgres schema rather than a vendor object model.
- RLS turns multi-tenancy into a database guarantee. Layer 12 tenant isolation is enforced in the same place the data lives, for every caller, rather than re-implemented in each service that connects.
- One store, several access shapes. SQL for the OS, PostgREST for operator surfaces, Realtime for change streams — all reading the same rows. Nothing has to be kept in sync because nothing is duplicated.
- The extension surface absorbs work that would otherwise become a platform. Scheduling, queues and vectors exist inside Postgres, which keeps the stack at its current size instead of growing a component per capability.
- Self-hostable in full, under permissive licences. Every component listed in the architecture is open source, which is what Modes 2 and 3 require under Principle 11 (Open by default, sovereign by design).
- Studio is an operator surface. A governed system needs humans to be able to inspect approvals, audit rows and policy state directly. Studio is that surface for Layer 7, protected by HTTP basic authentication in the self-hosted stack.
Deployment and licensing
Self-hosting. Documented paths are Docker Compose (recommended), a community Helm chart for Kubernetes, and a community Traefik reverse-proxy project. Minimum stated requirements for all components are 4 GB RAM, 2 CPU cores and 40 GB SSD, with 8 GB, 4 cores and 80 GB recommended. HTTPS is not on by default and the documented approach is a reverse proxy such as Caddy or Nginx in front of the gateway. Self-hosted releases of the compose setup are published approximately monthly.
What self-hosting does not include. The managed platform carries features absent from the self-hosted stack: “branching, advanced metrics beyond logs, managed backups and PITR, analytics and vector buckets, ETL, and the platform management API”. Server provisioning, security hardening, database maintenance, high availability, backups and disaster recovery, and monitoring are all operator responsibilities. “Self-hosted Supabase is community-supported.”
Licence — verified. The supabase/supabase repository is licensed under the Apache License, Version 2.0, so the Tech Stack’s “Apache 2.0” record is accurate for the platform as a whole. The licences of the constituent components are not uniform, but all are permissive and all are open source:
| Component | Licence |
|---|---|
| Postgres | PostgreSQL License |
Studio, Realtime, Storage API, postgres-meta, Supavisor, Envoy | Apache 2.0 |
| Auth (GoTrue), PostgREST, Deno | MIT |
None of these carry the commercial-use restriction that applies to fair-code licensing, so unlike n8n there is no delivery-model question to resolve here.
Still an open item: “all Supabase features.” Deployment Model Spec’s “Full Postgres 17 + all Supabase features” remains inaccurate on its second half. Branching, managed backups and PITR, ETL, and the platform management API are still cloud-only, per “What self-hosting does not include” above. Neither document is wrong about intent — the stack is fully self-hostable — but “all Supabase features” needs correcting to match what the official documentation actually describes.
Official documentation
- Supabase documentation home
- Architecture — component list, source repositories and per-component licences
- Row Level Security — policies, roles, helper functions
- Data REST API — PostgREST behaviour and guarantees
- Auth architecture — the four layers of Supabase Auth
- Self-Hosting — options, limits, and operator responsibilities
- Self-Hosting with Docker — compose setup, secrets, Supavisor, overrides
- Upgrade to Postgres 17 — PG17 override and
pg_upgradepath supabase/supabaseLICENSE — Apache License, Version 2.0
Related Synedrix OS documents
- Memory Fabric Spec — Why this store is write-authoritative for every audit-bearing tier, and the tombstone rule.
- Agent DB Schema — Group G, the memory control-plane tables.
- Synedrix OS Tech Stack — normative platform responsibilities; §5 covers Supabase PG17.
- Agent DB Schema — the full relational schema for the agent layer; the detailed source for every table referenced on this page.
- Layer Taxonomy Table — Layer 7 definition and platform mapping.
- Agent Registry — OS agent definitions and the systems each agent may read or write.
- Agent Registry Spec — registry record shape implemented by the registry table group.
- Workflow Contract Spec — the contract governing triggers, side effects and approval requirements.
- Outcome Spec — the append-only outcome records written to Supabase.
- Core Principles — Principle 7 and Principle 11, which this layer implements.
- Deployment Model Spec — per-mode component requirements.
Synedrix OS · Platform reference · Supabase PG17