---
title: "Deploy OpenFGA"
description: "OpenFGA: Zanzibar-style fine-grained auth engine, backed by Postgres"
category: "Authentication"
url: https://railway.com/deploy/openfga-authorization
---

# Deploy OpenFGA

OpenFGA: Zanzibar-style fine-grained auth engine, backed by Postgres

**[Deploy OpenFGA on Railway](https://railway.com/template/openfga-authorization)**

- **Creator:** A3A
- **Category:** Authentication

## Template content

### Postgres https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/postgresql.svg

- **Image:** ghcr.io/railwayapp-templates/postgres-ssl:18

### openfga https://raw.githubusercontent.com/openfga/openfga/main/openfga-logo.png

- **Source:** https://github.com/gridalpha/openfga-railway
- **Health check:** /healthz
- **Public domain:** Yes

## Documentation

![OpenFGA logo](https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRr-wMajOs1dAaG9jhYlmXfGjdMDImqyEwtsp17wsQIEDQ9SBMnCYEVrEY&amp;s=10)

# Deploy and Host OpenFGA on Railway

OpenFGA is an open-source authorization engine built on Google's Zanzibar design, the system behind permissions in Docs and Drive. Instead of scattering `if user.isAdmin` checks through your codebase, you declare an authorization model once, store relationships as tuples like `user:anne is owner of document:roadmap`, and ask the server one question at runtime: can this user do this to this object? It is a CNCF project, originally built by the Auth0 team, running in production at Docker, Grafana Labs and Canonical. Teams self-host OpenFGA when permissions outgrow a role column — nested groups, folder inheritance, per-object sharing, multi-tenancy — and want those decisions answered in milliseconds.

This template runs OpenFGA on Railway with a dedicated PostgreSQL database, the shape the project's own production guide recommends. The API service is built from [gridalpha/openfga-railway](https://github.com/gridalpha/openfga-railway), a thin image around the official `openfga/openfga` binary that applies database migrations on every boot, so the schema is created and kept current with no manual step. The server is published on a Railway domain over HTTPS and protected by a pre-shared API key generated at deploy time. PostgreSQL stays on the private network holding every store, model, tuple and changelog entry, and a gRPC listener and Prometheus endpoint run alongside the HTTP API.

![Diagram of the OpenFGA and Postgres services on Railway](https://res.cloudinary.com/rroe4rtk/image/upload/v1788291094/openfga-architecture.png)

## Getting Started with OpenFGA on Railway

OpenFGA is an API rather than a web app, so the quickest check is to open `https://your-app.up.railway.app/healthz`, which answers `{"status":"SERVING"}` with no credentials. Every other route needs the key from `OPENFGA_AUTHN_PRESHARED_KEYS`, sent as `Authorization: Bearer `; without it you get a 401, which is the fastest proof auth is on. Your first action is to create a store — OpenFGA's tenant boundary — and write an authorization model into it. Models are usually authored in OpenFGA's DSL and compiled to JSON by the [FGA CLI](https://github.com/openfga/cli) or an SDK, though the HTTP API accepts JSON directly. Then write tuples and call `/check`:

```
FGA=https://your-app.up.railway.app
AUTH="Authorization: Bearer $FGA_KEY"   # the key from your service variables

curl -s -X POST "$FGA/stores" -H "$AUTH" -H 'Content-Type: application/json' \
  -d '{"name":"acme-docs"}'

curl -s -X POST "$FGA/stores/$STORE_ID/check" -H "$AUTH" -H 'Content-Type: application/json' \
  -d '{"tuple_key":{"user":"user:anne","relation":"viewer","object":"document:roadmap"}}'
```

Point an official SDK at the same base URL and key and you are done. Keep the key server-side: whoever holds it can ask about anyone.

![OpenFGA store listing and its seven relationship tuples](https://res.cloudinary.com/rroe4rtk/image/upload/v1788291096/openfga-store-and-tuples.png)
![Four Check calls answering allowed true and false](https://res.cloudinary.com/rroe4rtk/image/upload/v1788291098/openfga-check-decisions.png)
![ListObjects, ListUsers and the tuple changelog responses](https://res.cloudinary.com/rroe4rtk/image/upload/v1788291099/openfga-list-and-changes.png)

## About Hosting OpenFGA

Relationship-based access control moves authorization out of application code and into data. You declare types and relations — a `team` has `member`s, a `folder` has `viewer`s, a `document` inherits `viewer` from its parent — then write plain facts about who relates to what. OpenFGA walks that graph, so a user who joins a team immediately reaches everything that team can, and removing them revokes it just as fast. Self-hosting keeps that graph — a precise map of who can see what — in your own infrastructure.

- **Check** answers one yes/no authorization question in a few milliseconds
- **ListObjects** and **ListUsers** run it in reverse: every document a user can view, or every user who can view one
- **Contextual tuples and conditions** evaluate unstored facts like time of day or IP range
- **Immutable model versions** mean a model change never rewrites existing tuples
- **A changelog API** journals every tuple write for audit and cache invalidation
- Both **HTTP/REST** and **gRPC**, plus Prometheus metrics and OpenTelemetry tracing

The architecture is two services. OpenFGA is stateless, so it restarts cleanly and scales to more replicas on demand. PostgreSQL is the system of record, dedicated to OpenFGA so it is tuned independently of your application's own database.

## Why Deploy OpenFGA on Railway

Railway removes the operational work self-hosting an authorization service involves.

- Managed PostgreSQL provisioned and wired up in one click
- Schema migrations applied automatically on every deploy
- HTTPS, certificates and a public domain handled for you
- Private networking keeps the database off the public internet
- A health check that fails closed when the database is unreachable
- Vertical and horizontal scaling with no config change

## Common Use Cases

- **Document and file sharing** — per-object permissions with folder inheritance and share links
- **Multi-tenant SaaS** — organisations, workspaces, nested teams and roles that stay correct as the hierarchy grows
- **Platform tooling** — who may deploy to which environment, or read a cluster's logs
- **AI agent authorization** — filtering retrieval with `ListObjects` so an agent sees only what the user can

## Dependencies for OpenFGA

- **OpenFGA server** — [gridalpha/openfga-railway](https://github.com/gridalpha/openfga-railway), packaging the official [`openfga/openfga`](https://hub.docker.com/r/openfga/openfga) binary and running `openfga migrate` before the server starts
- **PostgreSQL 18** — `ghcr.io/railwayapp-templates/postgres-ssl:18`, holding stores, models, tuples and the changelog on a persistent volume

### Environment Variables Reference

| Variable | Purpose |
|---|---|
| `OPENFGA_AUTHN_METHOD` | `preshared` for API keys, or `oidc` to accept JWTs from your identity provider |
| `OPENFGA_AUTHN_PRESHARED_KEYS` | Accepted API keys, comma separated; list two to rotate live |
| `OPENFGA_DATASTORE_MAX_OPEN_CONNS` | Connection pool ceiling; divide between replicas |
| `OPENFGA_PLAYGROUND_ENABLED` | Left off — the playground is deprecated and only runs unauthenticated |

### Deployment Dependencies

[Docs](https://openfga.dev/docs) · [API reference](https://openfga.dev/api/service) · [configuration](https://openfga.dev/docs/getting-started/setup-openfga/configuration) · [GitHub](https://github.com/openfga/openfga) · [SDKs](https://openfga.dev/docs/getting-started/install-sdk) · [FGA CLI](https://github.com/openfga/cli)

## Hardware Requirements for Self-Hosting OpenFGA

| Resource | Minimum | Recommended |
|---|---|---|
| CPU | 0.5 vCPU | 2 vCPU |
| RAM | 512 MB | 2 GB |
| Storage | 1 GB database | 10 GB+, sized to tuple count |
| Runtime | Linux container | PostgreSQL 14+ |

Latency is dominated by database round trips, so keep both in one region; on Railway they already share a private network.

## Self-Hosting OpenFGA with Docker

The official image runs against an in-memory store for evaluation:

```
docker run -p 8080:8080 openfga/openfga run
```

Against Postgres, migrate first, then run the server:

```
URI="postgres://user:pass@host:5432/openfga"
docker run -e OPENFGA_DATASTORE_ENGINE=postgres -e OPENFGA_DATASTORE_URI="$URI" \
  openfga/openfga migrate
docker run -p 8080:8080 -p 8081:8081 -e OPENFGA_DATASTORE_ENGINE=postgres \
  -e OPENFGA_DATASTORE_URI="$URI" -e OPENFGA_AUTHN_METHOD=preshared \
  -e OPENFGA_AUTHN_PRESHARED_KEYS="your-api-key" openfga/openfga run
```

## Is OpenFGA Free?

OpenFGA is free and open source under Apache 2.0, with no paid tier, seat limit or feature gate. Okta FGA is the commercial hosted service built on it, but self-hosting costs nothing in licensing. On Railway you pay only for the compute and storage the two services use: a few dollars a month at low traffic.

## FAQ

**What is OpenFGA?**

An open-source authorization engine, based on Google's Zanzibar paper, that stores relationships between users and resources and answers permission checks against them. It is a CNCF project under Apache 2.0; the closest alternative is SpiceDB.

**What does this Railway template deploy?**

The OpenFGA API server with HTTP, gRPC and Prometheus endpoints, plus a dedicated PostgreSQL database on a volume. The API key is generated at deploy time and migrations run on every boot.

**Why does OpenFGA need a PostgreSQL database?**

Stores, models, tuples and the changelog all live there. The in-memory engine is for local evaluation only and loses everything on restart.

**How do I secure my self-hosted OpenFGA server?**

The template sets `OPENFGA_AUTHN_METHOD=preshared` and generates a key, so every call needs a bearer token. Rotate by adding a second key to the comma-separated list, migrating clients, then dropping the old one. For SSO-issued JWTs, switch to `oidc` and set the issuer and audience.

**Does OpenFGA have a web UI or playground?**

Not in a production deployment. The built-in playground is deprecated upstream and only runs with authentication disabled, so it is off here. Author models with the FGA CLI, the VS Code extension, or an SDK.

**How do I connect to self-hosted OpenFGA over gRPC?**

The server listens for gRPC on 8081 alongside HTTP. Railway's public domain serves HTTP only, so add a TCP proxy to port 8081 in the service's networking settings and point your client at the host and port it returns. To add replicas, raise them in Railway and divide `OPENFGA_DATASTORE_MAX_OPEN_CONNS` by the count.


## Similar templates

- [Keycloak](https://railway.com/deploy/mSwigX) — Keycloak template with keywind theme + apple and discord providers
- [lua-protector](https://railway.com/deploy/lua-protector) — Test deployed my project first
- [bknd](https://railway.com/deploy/p4nTYL) — Feature-rich yet lightweight backend

Open this page in a browser: https://railway.com/deploy/openfga-authorization
