Zanzibar-Style Authorization
for PostgreSQL
Implement fine-grained, relationship-based access control without external services.
Melange compiles OpenFGA schemas into SQL functions that run inside your existing database.
Pure PostgreSQL
Zero external dependencies. No sidecars, no services. Everything runs as SQL functions inside your database.
OpenFGA Compatible
Full Schema 1.1 conformance. Use familiar DSL syntax with complete feature support, validated against the official OpenFGA test suite.
Optimized for Speed
300-600 μs permission checks with O(1) constant-time scaling. Same speed whether you have 1K or 1M tuples.
No Tuple Sync
Permissions derived from views over your domain tables. Always in sync, transaction-aware, zero data duplication.
Transaction Aware
Permission checks see uncommitted changes within the same transaction. No eventual consistency, no stale authorization data.
Language Agnostic
Go and TypeScript client libraries included, or call SQL functions directly from any language. Works in triggers, RLS policies, or application code.
How It Works
Melange is an authorization compiler. Like Protocol Buffers or GraphQL Code Generator, you define a schema and Melange generates optimized code tailored to your exact model. Instead of a generic runtime that interprets your model at query time, Melange generates purpose-built SQL functions for each relation in your schema. Role hierarchies are resolved at compile time and inlined into SQL, so runtime checks avoid recursive graph traversal entirely.
flowchart LR
schema["schema.fga"] --> melange["melange compile"]
melange --> funcs["PostgreSQL Functions"]
funcs --> check["check_permission()"]
funcs --> list["list_accessible_objects()"]
funcs --> subjects["list_accessible_subjects()"]
Define Your Schema
Write your authorization model using the OpenFGA DSL. The same .fga files work with both Melange and OpenFGA, so there’s no vendor lock-in.
Melange supports direct assignments, computed usersets, unions, intersections, exclusions, tuple-to-userset, wildcards, userset references, and contextual tuples.
model
schema 1.1
type user
type organization
relations
define owner: [user]
define admin: [user] or owner
define member: [user] or admin
type repository
relations
define org: [organization]
define owner: [user]
define admin: [user] or owner
define can_read: member from org or admin
define can_write: admin
define can_delete: ownerQuery Your Existing Tables
Unlike traditional FGA systems, Melange doesn’t need a separate tuple store. Create a SQL view that maps your existing domain tables into tuples, and Melange queries them directly.
No data duplication. No sync jobs. Permissions are always consistent with your domain data, down to the current transaction.
CREATE VIEW melange_tuples AS
-- Organization memberships
SELECT
'user' AS subject_type,
user_id::text AS subject_id,
role AS relation,
'organization' AS object_type,
organization_id::text AS object_id
FROM organization_members
UNION ALL
-- Repository ownership
SELECT
'organization' AS subject_type,
organization_id::text AS subject_id,
'org' AS relation,
'repository' AS object_type,
id::text AS object_id
FROM repositories;Check Permissions From Any Language
Once compiled, permission checks are simple SQL function calls. Use the Go or TypeScript client libraries for convenience, or call the generated functions directly from any language that can talk to PostgreSQL.
checker := melange.NewChecker(db)
allowed, err := checker.Check(ctx,
authz.User("alice"),
authz.RelCanRead,
authz.Repository("123"),
)Get Started in Minutes
# Install
brew install pthm/tap/melange
# Initialize your project
melange init
# Apply schema and generate SQL functions
melange migrate
# Generate type-safe client code
melange generate client