Skip to main content

@permify-toolkit/cli

CLI for managing schemas, seeding relationships, and querying relationship data from your Permify instance.

NPM Version

Installation

pnpm add @permify-toolkit/cli

Configuration

The CLI relies on a permify.config.ts file in your project root. See Configuration for full details.

Schema Definition Options

Inline Schema (AST-based)

import {
defineConfig,
schema,
entity,
relation,
permission
} from "@permify-toolkit/core";

export default defineConfig({
tenant: "t1",
client: {
endpoint: "localhost:3478",
insecure: true
},
schema: schema({
user: entity({
relations: {
manager: relation("user")
},
permissions: {
manage: permission("manager")
}
}),
document: entity({
relations: {
owner: relation("user"),
viewer: relation("user")
},
permissions: {
view: permission("viewer or owner"),
edit: permission("owner")
}
})
}),
relationships: {
seedFile: "./relationships.json",
mode: "append"
}
});

File-based Schema

import { defineConfig, schemaFile } from "@permify-toolkit/core";

export default defineConfig({
tenant: "t1",
client: { endpoint: "localhost:3478", insecure: true },
schema: schemaFile("./schema.perm")
});

Tenant Configuration

The --tenant flag is optional if tenant is defined in permify.config.ts.

Resolution order:

  1. --tenant CLI flag (or PERMIFY_TENANT env var)
  2. tenant field in permify.config.ts
  3. Error if neither is provided

Commands

Schema

schema push

Pushes the schema defined in your config to the Permify server.

permify-toolkit schema push [--tenant <tenant-id>] [flags]

Flags:

FlagAliasDescriptionDefault
--tenantTenant ID to push toFrom config
--create-tenant-cCreate tenant if it doesn't existfalse

Examples:

# Push using tenant from config
permify-toolkit schema push

# Push to a specific tenant
permify-toolkit schema push --tenant my-tenant-id

# Push and create tenant if needed
permify-toolkit schema push --tenant new-tenant-id --create-tenant

Schema Validation:

The Permify server validates your schema on push. If there are errors, you'll see a detailed message:

Error: Entity "usr" referenced in relation "document.owner" does not exist

schema validate

Validates your schema locally without connecting to a Permify server. Catches structural errors, broken references, permission cycles, and suspicious patterns before you push.

permify-toolkit schema validate

This command takes no flags. It reads schema configuration from permify.config.ts in the current directory.

What it checks:

CategoryExamples
InputSchema source exists, file readable, .perm extension required
StructureAt least one entity defined
ReferencesRelation targets exist, permission symbols resolve, traversal targets valid
Expression syntaxNo dangling operators (owner or), balanced parentheses, no double-dot traversal (parent..view)
CyclesDirect self-reference (view = view), indirect cycles (view → edit → view)
WarningsUnused relations, entities with no permissions

Output:

When the schema is valid:

✔ Schema is valid

When valid but with warnings:

⚠ Schema is valid with warnings

Warnings:
1. Entity "document": relation "viewer" is never used in any permission
2. Entity "organization": has no permissions defined

When validation fails:

Error: Schema validation failed:
Permission "document.view" references undefined relation or permission "viewer"

Examples:

# Validate schema in your current project
permify-toolkit schema validate

# Validate before pushing in CI
permify-toolkit schema validate && permify-toolkit schema push
Use before push

Run schema validate before schema push for instant local feedback, no server connection needed.

schema diff

Previews what will change before pushing a schema update. Compares your local schema (from permify.config.ts) against the schema currently deployed on the Permify server — or against another local .perm file.

permify-toolkit schema diff [--tenant <id>] [flags]

Flags:

FlagAliasDescriptionRequiredDefault
--tenantTenant ID to diff againstNoFrom config
--create-tenant-cCreate tenant if it doesn't existNofalse
--source-sPath to a .perm file to compare against (local-vs-local mode)No
--verbose-vShow raw unified text diff after the structural summaryNofalse
--exit-code-eExit with code 1 if changes are detected (useful for CI pipelines)Nofalse

Examples:

# Compare local schema against what's deployed on the server
permify-toolkit schema diff

# Compare against a specific tenant
permify-toolkit schema diff --tenant staging

# Compare two local schemas (no server connection needed)
permify-toolkit schema diff --source ./old-schema.perm

# Include a unified text diff for full detail
permify-toolkit schema diff --verbose

# CI mode — fail the pipeline if schema has drifted
permify-toolkit schema diff --exit-code

Output:

The command shows a structural summary of changes at the entity, relation, and permission level:

Schema Diff Output

  • Green (+) — added entities, relations, or permissions
  • Red (-) — removed entities, relations, or permissions
  • Yellow (~) — modified entities (contents changed), or individual relations/permissions whose definition changed

When no changes are detected:

✔ Schema is up to date — no changes detected (tenant: t1)

When no schema exists on the remote server yet (first-time push), everything is shown as additions:

Schema Diff — tenant: t1
ℹ No schema found on remote — showing full schema as additions

With --verbose, a unified text diff is appended below the structural summary:

--- remote (tenant: t1)
+++ local (permify.config.ts)
@@ -1,5 +1,8 @@
entity user {}
entity document {
relation owner @user
+ relation editor @user
- permission view = owner
+ permission view = owner or editor
+ permission edit = editor
}

Exit codes:

CodeMeaning
0No changes detected, or changes detected (default mode)
1Changes detected and --exit-code flag is set
Use in CI pipelines

Combine --exit-code with your CI to detect schema drift:

permify-toolkit schema diff --exit-code || echo "Schema has changed — review before pushing"
Preview before push

Run schema diff before schema push to review exactly what will change on the server. Pair with --verbose for a complete picture.

Relationships

relationships seed

Seeds relationship data from a JSON file.

permify-toolkit relationships seed [--tenant <id>] [--file-path <path>] [flags]

Flags:

FlagAliasDescriptionDefault
--tenantTenant ID to seed toFrom config
--file-path-fPath to JSON file with tuplesFrom config
--create-tenant-cCreate tenant if it doesn't existfalse

Example relationships.json:

{
"tuples": [
{
"entity": { "type": "organization", "id": "org_1" },
"relation": "member",
"subject": { "type": "user", "id": "alice" }
},
{
"entity": { "type": "document", "id": "doc_1" },
"relation": "owner",
"subject": { "type": "user", "id": "bob" }
},
{
"entity": { "type": "document", "id": "doc_1" },
"relation": "viewer",
"subject": { "type": "user", "id": "charlie" }
}
]
}

Examples:

# Seed to existing tenant
permify-toolkit relationships seed --tenant my-tenant-id --file-path ./data/relationships.json

# Seed and create tenant
permify-toolkit relationships seed --tenant new-tenant-id --file-path ./relationships.json --create-tenant

relationships list

Queries and displays relationship tuples from a Permify tenant. Useful for debugging authorization — quickly see what relationships exist for a given entity type.

Unlike schema push or relationships seed, this command does not require a schema in your config. It only needs a client connection.

permify-toolkit relationships list --entity-type <type> [--tenant <id>] [flags]

Flags:

FlagAliasDescriptionRequiredDefault
--entity-type-eEntity type to queryYes
--tenantTenant IDNoFrom config
--entity-idFilter by a specific entity IDNo
--relation-rFilter by relation nameNo
--subject-type-sFilter by subject typeNo
--subject-idFilter by subject IDNo
--output-oOutput format: table or compactNotable
--page-size-pNumber of results per gRPC pageNo50

Minimal config required:

// permify.config.ts — no schema needed for read-only commands
export default {
tenant: "t1",
client: {
endpoint: "localhost:3478",
insecure: true
}
};

Examples:

# List all relationships for the "document" entity type
permify-toolkit relationships list -e document

# Filter by relation and subject
permify-toolkit relationships list -e document -r viewer -s user

# Show a specific entity's relationships
permify-toolkit relationships list -e document --entity-id doc-1

# Use compact output (one tuple per line)
permify-toolkit relationships list -e document -o compact

# Specify tenant and page size
permify-toolkit relationships list -e document --tenant my-tenant -p 100

Output formats:

Table (default):

Entity Type  Entity ID  Relation  Subject Type  Subject ID  Subject Relation
document doc-1 owner user alice
document doc-1 viewer user bob
document doc-2 viewer group eng member
✔ Found 3 relationships

Compact (one Zanzibar-style tuple per line):

document:doc-1#owner@user:alice
document:doc-1#viewer@user:bob
document:doc-2#viewer@group:eng#member
✔ Found 3 relationships

When no relationships match:

ℹ No relationships found.
Debugging permissions

Use relationships list to verify that the tuples you expect actually exist in Permify. If a permission check fails unexpectedly, list the relationships for that entity to see what's stored.

relationships export

Exports relationship tuples from a Permify tenant to a JSON file. The output format is identical to the relationships seed input format — so you can export from one tenant and seed into another.

Like relationships list, this command does not require a schema in your config.

permify-toolkit relationships export --entity-type <type> --file-path <path> [--tenant <id>] [flags]

Flags:

FlagAliasDescriptionRequiredDefault
--entity-type-eEntity type to queryYes
--file-path-fOutput file path (must be .json)Yes
--tenantTenant IDNoFrom config
--entity-idFilter by a specific entity IDNo
--relation-rFilter by relation nameNo
--subject-type-sFilter by subject typeNo
--subject-idFilter by subject IDNo
--page-size-pNumber of results per gRPC pageNo100

Examples:

# Export all document relationships to a file
permify-toolkit relationships export -e document -f ./backup/documents.json

# Export only viewer relationships
permify-toolkit relationships export -e document -r viewer -f viewers.json

# Export from a specific tenant
permify-toolkit relationships export -e document --tenant staging -f staging-docs.json

Output file format:

The exported JSON file uses the same structure as relationships seed, so you can directly re-import it:

{
"tuples": [
{
"entity": { "type": "document", "id": "doc-1" },
"relation": "owner",
"subject": { "type": "user", "id": "alice" }
},
{
"entity": { "type": "document", "id": "doc-1" },
"relation": "viewer",
"subject": { "type": "user", "id": "bob" }
}
]
}

Common workflows:

# Back up relationships before a migration
permify-toolkit relationships export -e document -f ./backup/documents.json
permify-toolkit relationships export -e organization -f ./backup/orgs.json

# Copy relationships from staging to dev
permify-toolkit relationships export -e document --tenant staging -f transfer.json
permify-toolkit relationships seed --tenant dev -f transfer.json

# Export, inspect, edit, then re-seed
permify-toolkit relationships export -e document -f tuples.json
# ... edit tuples.json manually ...
permify-toolkit relationships seed --tenant t1 -f tuples.json
Export + Seed round-trip

The export format is designed to be seed-compatible. You can export from one environment, review or modify the JSON, and seed it into another — making it easy to migrate or duplicate relationship data across tenants.

Local Development

# Build the package
pnpm build

# Run using local bin script
./bin/permify-toolkit schema push --tenant dev-tenant -c