Skip to main content
In Permify, you model authorization by defining the relationships between users and resources, then expressing what those relationships allow. This is called Relationship-Based Access Control (ReBAC) — inspired by Google Zanzibar.

Permify Schema

Permify has its own schema language (DSL) for modeling authorization logic. With it you can:
  • Define entities that represent your application’s resources and actors.
  • Define relations between entities (e.g. a user is an admin of an organization).
  • Define permissions (also called actions) that express what a subject can do on a resource.
  • Use set-algebraic operatorsand, or, not — to compose complex access rules.
  • Add attributes and rules to support attribute-based access control (ABAC).
You can write schemas in the Permify Playground, in any text editor, or using the VS Code extension (file extension .perm).

Developing a schema

The following steps walk through building a schema from scratch using a simplified GitHub authorization model, where organizations, teams, and users have different levels of access to repositories.
1

Define entities

Entities are the core objects in your permission system — think of them as your database tables. Use the entity keyword to declare them.
entity user {}

entity organization {}

entity team {}

entity repository {}
Each entity can contain relations, permissions, and attributes. The user entity is mandatory in Permify — it acts as the reference point for all subjects.
Name your entities the same as your database tables. This makes it easier to reason about your authorization model and eliminates mapping errors.
2

Define relations

Relations describe how entities relate to each other. They form the backbone of Permify’s evaluation engine.
relation name @type
Relation attributes:
  • name — letters and underscores only, max 64 characters.
  • type — the entity type this relation references (must exist in the schema).

Roles and user types

Define roles directly on the entity that owns them:
entity organization {

    relation admin  @user
    relation member @user

}

Parent-child relationships

Model hierarchies using a parent relation:
entity team {

    relation parent @organization
    relation member @user

}
The parent relation links the team to its owning organization, establishing a parent-child hierarchy.

Ownership

Represent resource ownership with a dedicated relation:
entity repository {

    relation parent     @organization
    relation owner      @user
    relation maintainer @user @team#member

}

Multiple relation types

The maintainer relation above accepts two types:
relation maintainer @user @team#member
This means a maintainer can be either a user directly, or any member of a team. The # character is used to reference a relation on another entity — this is called feature locking, and it locks the relation type to the specified sub-relation.
Feature locking lets you define sets of users. For example:
relation viewer @user @organization#member
This allows individual users and entire organization member sets to be assigned as viewers:
  • document:1#viewer@user:U1
  • document:1#viewer@organization:O1#member
The second tuple grants the viewer relation to all members of organization O1.
3

Define permissions

Permissions (also written as action) define what subjects are allowed to do on an entity.The basic form of an authorization check is: Can user U perform action X on resource Y?The keywords action and permission are interchangeable.

Union (or)

Use or to grant access if the subject satisfies any of the conditions:
entity repository {

    relation parent     @organization
    relation owner      @user
    relation maintainer @user @team#member

    action read = owner or maintainer or parent.member

}

Intersection (and)

Use and to require the subject to satisfy all conditions:
entity repository {

    relation parent     @organization
    relation owner      @user
    relation maintainer @user @team#member

    action delete = parent.admin and (owner or maintainer or parent.member)

}
The delete action requires the user to be an organization admin and also be an owner, maintainer, or member.
When using and with a traversal like org.member and org.admin, Permify evaluates each side across all reachable organizations and then intersects the results. If you need both conditions to be satisfied on the same organization, define the intersection on the organization entity and reference it from the child:
entity organization {
  relation member @user
  relation admin  @user
  permission delete = member and admin
}

entity repository {
  relation org @organization
  permission delete = org.delete
}

Exclusion (not)

Use not to exclude a set of subjects:
entity post {
    relation account   @account
    attribute restricted boolean

    action comment = account.following not restricted
    action like    = account.following not restricted
}
Users tagged with restricted = true are excluded from the comment and like actions.

Permission union (inherited permissions)

Permissions can reference other permissions, enabling inheritance:
action edit   = member or manager
action delete = edit or organization.admin
The delete action inherits everything from edit and additionally grants access to organization admins.
4

Full GitHub example

Here is the complete simplified GitHub authorization schema:
entity user {}

entity organization {

    relation admin  @user
    relation member @user

}

entity team {

    relation parent @organization
    relation member @user

}

entity repository {

    relation parent     @organization
    relation owner      @user
    relation maintainer @user @team#member

    action read   = owner or maintainer or parent.member or parent.admin
    action edit   = owner or maintainer or parent.admin
    action delete = parent.admin and (owner or maintainer or parent.member)

}

Attribute-based permissions (ABAC)

Permify extends ReBAC with attribute support, allowing you to write conditions based on properties of entities.

Defining attributes

Attributes associate typed values with entities:
attribute ip_range string[]
attribute is_public boolean
attribute balance   double
Supported attribute types:
boolean    boolean[]
string     string[]
integer    integer[]
double     double[]

Defining rules

Rules are condition functions that accept parameters and return true or false. They use Common Expression Language (CEL) syntax:
entity user {}

entity organization {

    relation admin @user

    attribute ip_range string[]

    permission view = check_ip_range(ip_range) or admin
}

rule check_ip_range(ip_range string[]) {
    context.data.ip in ip_range
}
Here, view is granted to admins or to any user whose IP address falls within the organization’s allowed IP range.

Modeling guides

Explore guides for common authorization patterns:

RBAC Guide

Role-based access control patterns including global, resource-specific, and custom roles.

ReBAC Guide

Relationship-based patterns including groups, hierarchies, and recursive structures.

ABAC Guide

Attribute-based patterns including boolean flags, string conditions, and numerical rules.

Build docs developers (and LLMs) love