Melange
!GitHub License
!GitHub Release
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.
Why Melange?
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.
Installation
macOS and Linux (Homebrew):
brew install pthm/tap/melange
Windows (Scoop):
scoop bucket add pthm https://github.com/pthm/scoop-bucket
scoop install pthm/melange
Go (1.27 or later):
go install github.com/pthm/melange@latest
Docker:
docker pull ghcr.io/pthm/melange:latest
Debian / 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 dependency
Quick Start
1. Define your schema
model
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.
2. Map your tables to tuples
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;
3. Compile the schema into SQL functions
melange migrate --db postgres://localhost/mydb --schema schema.fga
This installs check_permission(), list_accessible_objects(), list_accessible_subjects(), and a specialized check function for each relation.
4. Check permissions
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) { / ... / }
5. Generate type-safe clients (optional)
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"))
Inspect It With Studio
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.
CLI
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 --verbose
Commands read melange.yaml and support named environments (--env staging). See the CLI reference.
Contributing
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.
Resources
- 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
License
MIT License. See LICENSE for details.