Minimal
PostgreSQL. One type, two queries, one mutation. The fastest way to see FraiseQL running.
Three starter templates cover the most common starting points. Each is a working project you can clone and run with one command.
Minimal
PostgreSQL. One type, two queries, one mutation. The fastest way to see FraiseQL running.
Blog API
PostgreSQL. Posts, comments, tags, and mutations. The reference project for all guides.
SaaS
Multi-tenant with Row-Level Security + JWT isolation. Production-quality data model.
PostgreSQL. One type, two queries, one mutation.
The smallest possible FraiseQL project. Use this to verify your installation or as a blank canvas.
git clone https://github.com/fraiseql/fraiseql-starter-minimalcd fraiseql-starter-minimalcp .env.example .envdocker compose upWhat’s included:
schema.py — one type, two queries, one mutationfraiseql.toml — minimal configinit.sql — table, view, function, and seed data.env.example — ready to copyStack: PostgreSQL · Docker Compose · ~100 lines total
PostgreSQL. Posts, comments, tags, mutations.
The reference project used throughout the FraiseQL guides. A complete read/write API with relationships.
git clone https://github.com/fraiseql/fraiseql-starter-blogcd fraiseql-starter-blogcp .env.example .envdocker compose upYour API is live at http://localhost:8080/graphql.
What’s included:
fn_create_post, fn_create_comment mutation functionsStack: PostgreSQL · Docker Compose · ~300 lines SQL + schema
Multi-tenant with Row-Level Security + JWT isolation.
A production-quality multi-tenant data model. Every tenant’s data is isolated at the database level — no application-layer bugs can leak rows across tenants.
git clone https://github.com/fraiseql/fraiseql-starter-saascd fraiseql-starter-saascp .env.example .envdocker compose upWhat’s included:
tenant_id claim enforced via session variablesStack: PostgreSQL · Docker Compose · RLS · JWT
@inject, RLS tenant isolation, structured mutation errors.
The security-focused starter. Shows the three patterns most teams ask about: injecting JWT claims server-side, enforcing row isolation at the database level, and returning structured errors from mutations.
git clone https://github.com/fraiseql/fraiseql-starter-authcd fraiseql-starter-authcp .env.example .env# Edit .env: set DATABASE_URL and JWT_SECRETpython schema.py && fraiseql compiledocker compose up@fraiseql.query( sql_source="v_post", inject={"tenant_id": "jwt:tenant_id"},)def posts(limit: int = 20) -> list[Post]: """tenant_id comes from the verified JWT — client cannot override it.""" passThe inject parameter maps JWT claims to SQL parameters. The claim is verified by the runtime before any query runs. The client cannot pass tenant_id directly — it is not exposed in the GraphQL schema.
CREATE POLICY tenant_isolation ON tb_post USING (tenant_id = current_setting('app.tenant_id')::UUID);Before each query, FraiseQL sets app.tenant_id from the injected JWT claim. The RLS policy filters every read automatically. Even if application code is compromised, the database enforces isolation.
@fraiseql.typeclass CreatePostError: code: str # "unauthorized" | "conflict" | "invalid_input" message: str
@fraiseql.mutation( sql_source="fn_create_post", operation="CREATE", inject={"user_id": "jwt:sub", "tenant_id": "jwt:tenant_id"},)def create_post(title: str, content: str) -> Post: passOn failure, the mutation returns a typed error instead of a generic GraphQL error:
{ "data": { "createPost": { "post": null, "error": { "code": "conflict", "message": "Post with this title already exists" } } }}Stack: PostgreSQL · Docker Compose · JWT · RLS
| Minimal | Blog | SaaS | Auth | |
|---|---|---|---|---|
| Database | PostgreSQL | PostgreSQL | PostgreSQL | PostgreSQL |
| Docker | Yes | Yes | Yes | Yes |
| Mutations | Yes | Yes | Yes | Yes |
| Multi-tenant | No | No | Yes | Yes |
| JWT inject | No | No | Partial | Yes |
| RLS | No | No | Yes | Yes |
| Published | ✅ | ✅ | ✅ | ✅ |
| Best for | First run | Learning | Production scaffold | Security patterns |