An OpenFGA-to-PostgreSQL authorization compiler.
Melange compiles OpenFGA authorization schemas into specialized PL/pgSQL functions that run inside your PostgreSQL database. Like Protocol Buffers compiles .proto files into serialization code, Melange compiles .fga files into SQL functions for Zanzibar-style relationship-based access control.
The generated functions read a melange_tuples view you define over your existing domain tables. There is no separate tuple store and nothing to sync.
Note
📚 Documentation: guides, API reference and examples at melange.sh.
Most authorization systems run as a separate service that you keep in sync with your application data. Melange is a compiler instead.
At migration time, melange migrate parses your OpenFGA schema, analyzes each relation's patterns (direct, union, exclusion, tuple-to-userset and so on), resolves role hierarchies, and installs a specialized SQL function per relation.
At runtime, a permission check is a single SQL function call, check_permission(), which runs those functions against your melange_tuples view.
That gives you:
- Always in sync. Checks read your tables directly, with no replication lag.
- Transaction-aware. Checks see uncommitted changes in the same transaction, so they work in triggers and RLS policies.
- Any language. Anything that can run SQL can check permissions. Go and TypeScript clients are optional conveniences.
- No recursive lookups. Role hierarchies are resolved at compile time and inlined into the generated SQL.
- OpenFGA compatible. Every Schema 1.1 feature except conditions, validated against the official OpenFGA test suite.
Inspired by OpenFGA and built on ideas from pgFGA.
macOS and Linux (Homebrew):
brew install pthm/tap/melangeWindows (Scoop):
scoop bucket add pthm https://github.com/pthm/scoop-bucket
scoop install pthm/melangeGo (1.27 or later):
go install github.com/pthm/melange@latestDocker:
docker pull ghcr.io/pthm/melange:latestDebian / RPM packages and archives: .deb and .rpm packages for Linux, and .tar.gz / .zip archives for Linux, macOS, and Windows, all for amd64 and arm64, on GitHub Releases. macOS binaries are code-signed and notarized.
The installation guide has step-by-step instructions for each platform, running in Docker, updating, and verifying downloads. The CLI tells you when a newer release is available; pass --no-update-check to turn that off.
Client libraries (optional):
go get github.com/pthm/melange/melange # Go 1.24+, standard library only
npm install @pthm/melange pg # TypeScript, Node.js 18+, pg is a peer dependencymodel
schema 1.1
type user
type repository
relations
define owner: [user]
define reader: [user] or owner
define can_read: reader
melange init creates a config file and a starter schema for you.
Create a melange_tuples view over the tables that already hold your authorization data:
CREATE VIEW melange_tuples AS
SELECT
'user' AS subject_type,
user_id::text AS subject_id,
'owner' AS relation,
'repository' AS object_type,
repo_id::text AS object_id
FROM repository_owners
UNION ALL
SELECT 'user', user_id::text, 'reader', 'repository', repo_id::text
FROM repository_readers;melange migrate --db postgres://localhost/mydb --schema schema.fgaThis installs check_permission(), list_accessible_objects(), list_accessible_subjects(), and a specialized check function for each relation.
SQL, from any language:
SELECT check_permission('user', 'alice', 'can_read', 'repository', 'my-repo');
-- 1 (allowed) or 0 (denied)Go:
checker := melange.NewChecker(db)
allowed, err := checker.Check(ctx,
melange.Object{Type: "user", ID: "alice"},
melange.Relation("can_read"),
melange.Object{Type: "repository", ID: "my-repo"},
)TypeScript:
const checker = new Checker(pool);
const decision = await checker.check(
{ type: "user", id: "alice" },
"can_read",
{ type: "repository", id: "my-repo" },
);
if (decision.allowed) { /* ... */ }melange generate client --runtime go --schema schema.fga --output ./authz/
melange generate client --runtime typescript --schema schema.fga --output ./src/authz/allowed, err := checker.Check(ctx, authz.User("alice"), authz.RelCanRead, authz.Repository("my-repo"))melange studio opens a local, read-only web console on any melange database. See what a user can access and who can access an object, explain a decision step by step, try a grant before you write it, and read the SQL melange generated for each relation. It reads the model from the database, so it needs only a connection.
melange studio --env staging
Explain any check, path by path |
Relations with their analysis and generated SQL |
Matrix of every relation for a subject |
Studio binds a loopback address, opens read-only connections, and loads nothing from other hosts. It is experimental. See the Studio guide for environments, privileges and every page.
Schema
migrate Apply schema to database
validate Validate a schema
status Show schema, tuples, and deployed-model status
diff Show what changed between the deployed model and your local schema
history Show the migration history recorded in the database
schema Inspect the model deployed in a database
explain Show why a permission check returns true or false
expand Show who has a permission on an object
doctor Run health checks
studio Open a local, read-only web console for a database (experimental)
Client
generate Generate code from schema
Utility
init Initialize a new Melange project
config Configuration utilities
env Environment profile utilities
version Print version information
license Print license and third-party notices
A few common commands:
melange migrate --dry-run # print the SQL without applying it
melange diff # compare your schema with the deployed one
melange explain user:alice can_read repository:42
melange expand repository:42 can_read
melange doctor --verboseCommands read melange.yaml and support named environments (--env staging). See the CLI reference.
Contributions are welcome. Melange is still evolving, and feedback, bug reports and improvements are appreciated.
- Chat: questions, ideas and help getting started in the Matrix room.
- Issues: bug reports and feature requests. For bugs, include steps to reproduce, expected and actual behavior, and any errors.
- Security: report vulnerabilities through private vulnerability reporting.
- Pull requests: fork, branch, run
just test, and open a PR with a clear description. Include tests for new behavior. For larger changes, open an issue or ask on Matrix first so we can agree on the approach.
The contributing guide covers the architecture, testing and benchmarks.
- Documentation: guides, API reference and examples
- OpenFGA: the authorization model Melange implements
- Zanzibar paper: Google's original authorization system
- pgFGA: the PostgreSQL FGA implementation that inspired this project
MIT License. See LICENSE for details.
