An OpenFGA-to-PostgreSQL authorization compiler.
Melange compiles OpenFGA authorization schemas into specialized PL/pgSQL functions that run directly in your PostgreSQL database. Like Protocol Buffers compiles .proto files into serialization code, Melange compiles .fga files into optimized SQL functions for Zanzibar-style relationship-based access control.
The generated functions query a melange_tuples view you define over your existing domain tables—no separate tuple storage or synchronization required.
Traditional authorization systems require syncing your application data to a separate service. Melange takes a different approach: it's a compiler, not a runtime service.
Compile time — When you run melange migrate, the compiler:
- Parses your OpenFGA schema
- Analyzes relation patterns (direct, union, exclusion, etc.)
- Computes transitive closures for role hierarchies
- Generates specialized SQL functions for each relation
- Installs the functions into PostgreSQL
Runtime — Permission checks are simple SQL function calls:
check_permission()executes the generated functions- Functions query a
melange_tuplesview you define over your domain tables - PostgreSQL's query planner optimizes the specialized functions
This compilation model gives you:
- Always in sync — Permissions query your tables directly, no replication lag
- Transaction-aware — Permission checks see uncommitted changes in the same transaction
- Language-agnostic — Use from any language that can call SQL (Go, TypeScript, Python, Ruby, etc.)
- Optional runtime libraries — Convenience clients for Go and TypeScript, or use raw SQL
- Single query — Role hierarchies resolved at compile time, no recursive lookups at runtime
Inspired by OpenFGA and built on ideas from pgFGA.
Note
📚 Full Documentation Visit melange.sh for comprehensive guides, API reference, and examples.
Homebrew (macOS and Linux):
brew install pthm/tap/melangeGo install:
go install github.com/pthm/melange/cmd/melange@latestPre-built binaries: Download from GitHub Releases (macOS binaries are code-signed)
Updating:
# Homebrew
brew upgrade melange
# Go install
go install github.com/pthm/melange/cmd/melange@latestMelange automatically checks for updates and notifies you when a new version is available. Use --no-update-check to disable.
If you want to use the Go convenience library instead of raw SQL:
go get github.com/pthm/melange/melangeThe runtime module has zero external dependencies (Go stdlib only).
Create a schema file (schema.fga) using the OpenFGA DSL:
model
schema 1.1
type user
type repository
relations
define owner: [user]
define reader: [user] or owner
define can_read: reader
Run the migration to generate specialized PL/pgSQL functions:
melange migrate --db postgres://localhost/mydb --schemas-dir ./schemas/This generates optimized SQL functions like check_permission(), list_objects(), and specialized check functions for each relation.
Create a melange_tuples view that exposes 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;With Go runtime (optional):
import "github.com/pthm/melange/melange"
checker := melange.NewChecker(db)
decision, err := checker.Check(ctx,
melange.Object{Type: "user", ID: "alice"},
"can_read",
melange.Object{Type: "repository", ID: "my-repo"},
)
if !decision.Allowed {
return ErrForbidden
}Or use raw SQL from any language:
SELECT check_permission(
'user', 'alice',
'can_read',
'repository', 'my-repo'
);
-- Returns: true/falseFor better type safety, generate constants and constructors:
melange generate client --runtime go --schema schema.fga --output ./authz/import "yourapp/authz"
checker := melange.NewChecker(db)
decision, err := checker.Check(ctx,
authz.User("alice"),
authz.RelCanRead,
authz.Repository("my-repo"),
)melange - PostgreSQL Fine-Grained Authorization
Commands:
generate client Generate type-safe client code from schema
migrate Apply schema to database
validate Validate schema syntax
status Show current schema status
doctor Run health checks on authorization infrastructure
# Generate Go code
melange generate client --runtime go --schema schema.fga --output ./authz/
# With custom package name
melange generate client --runtime go --schema schema.fga --output ./authz/ --package myauthz
# With int64 IDs instead of strings
melange generate client --runtime go --schema schema.fga --output ./authz/ --id-type int64
# Only generate permission relations (can_*)
melange generate client --runtime go --schema schema.fga --output ./authz/ --filter can_Supported runtimes: go (TypeScript coming soon)
# Apply schema
melange migrate --db postgres://localhost/mydb --schemas-dir ./schemas/
# Dry run (show SQL without applying)
melange migrate --db postgres://localhost/mydb --schemas-dir ./schemas/ --dry-run
# Force re-apply even if unchanged
melange migrate --db postgres://localhost/mydb --schemas-dir ./schemas/ --forcemelange validate --schema schema.fgamelange status --db postgres://localhost/mydbmelange doctor --db postgres://localhost/mydb --verboseMelange generates standard PostgreSQL functions, so you can use it from any language that can execute SQL:
# Python
cursor.execute(
"SELECT check_permission(%s, %s, %s, %s, %s)",
('user', 'alice', 'can_read', 'repository', 'my-repo')
)# Ruby
DB.fetch(
"SELECT check_permission(?, ?, ?, ?, ?)",
'user', 'alice', 'can_read', 'repository', 'my-repo'
).first// TypeScript (with pg or any SQL client)
const result = await db.query("SELECT check_permission($1, $2, $3, $4, $5)", [
"user",
"alice",
"can_read",
"repository",
"my-repo",
]);For convenience, Melange provides type-safe runtime clients:
| Language | Runtime Package | CLI Flag | Status |
|---|---|---|---|
| Go | github.com/pthm/melange/melange |
--runtime go |
Implemented |
| TypeScript | @pthm/melange |
--runtime typescript |
Planned |
These libraries provide a nicer API but are completely optional. See clients/ for language-specific implementations.
Contributions are welcome! Here's how to get started:
- Fork the repository and clone locally
- Create a branch for your changes
- Run tests with
just test - Submit a pull request with a clear description
Please ensure your code:
- Passes all existing tests
- Includes tests for new functionality
- Follows the existing code style
For bug reports and feature requests, please open an issue.
- Documentation — Guides, API reference, and examples
- OpenFGA — The authorization model Melange implements
- Zanzibar Paper — Google's original authorization system
- pgFGA — PostgreSQL FGA implementation that inspired this project
MIT License — see LICENSE for details.
