User Guide
Manifest guide
A pgroles manifest declares the desired state of PostgreSQL access control: who can log in, which group roles exist, what they can access, and what future objects should inherit.
The shape of a manifest
Most manifests combine four ideas:
rolesdefine PostgreSQL roles and login attributesgrantsdefine access to current database objectsdefault_privilegesdefine access for objects created latermembershipsconnect login roles to group roles
For larger databases, profiles and schemas remove repetition by expanding one privilege template across many schemas. For field-by-field details, use the manifest reference.
A complete application example
default_owner: app_migrator
profiles:
app_writer:
grants:
- privileges: [USAGE]
object: { type: schema }
- privileges: [SELECT, INSERT, UPDATE, DELETE]
object: { type: table, name: "*" }
- privileges: [USAGE, SELECT, UPDATE]
object: { type: sequence, name: "*" }
default_privileges:
- privileges: [SELECT, INSERT, UPDATE, DELETE]
on_type: table
- privileges: [USAGE, SELECT, UPDATE]
on_type: sequence
readonly:
grants:
- privileges: [USAGE]
object: { type: schema }
- privileges: [SELECT]
object: { type: table, name: "*" }
default_privileges:
- privileges: [SELECT]
on_type: table
schemas:
- name: app
owner: app_migrator
profiles: [app_writer, readonly]
roles:
- name: app_migrator
login: true
- name: app_runtime
login: true
- name: analyst
login: true
memberships:
- role: app-app_writer
members:
- name: app_runtime
- role: app-readonly
members:
- name: analyst
This produces two schema-scoped group roles:
app-app_writer, with read/write table access and sequence access in theappschemaapp-readonly, with read-only table access in theappschema
The login roles (app_runtime, analyst) get access through memberships rather than direct grants. This keeps runtime connection strings stable while letting you change profile grants in one place.
How the sections connect
| Section | Defines | Referenced by |
|---|---|---|
default_owner | Default object-creator role for future grants | default_privileges, profiles, schemas |
profiles | Reusable schema-relative grant templates | schemas[].profiles |
schemas | Managed schemas and profile bindings | profiles, generated roles, generated grants |
roles | Explicit PostgreSQL roles | grants, memberships, default_privileges |
grants | Current object privileges | role names and object targets |
default_privileges | Future object privileges | owner roles, grantee roles, schemas |
memberships | Role inheritance edges | parent roles and member roles |
retirements | Safe role removal workflow | roles omitted from desired state |
Choosing direct grants or profiles
Use direct top-level grants for one-off roles or database-level privileges:
roles:
- name: analytics
login: true
grants:
- role: analytics
privileges: [CONNECT]
object: { type: database, name: mydb }
- role: analytics
privileges: [USAGE]
object: { type: schema, name: reporting }
- role: analytics
privileges: [SELECT]
object: { type: table, schema: reporting, name: "*" }
Use profiles when the same access shape repeats across schemas:
profiles:
reader:
grants:
- privileges: [USAGE]
object: { type: schema }
- privileges: [SELECT]
object: { type: table, name: "*" }
schemas:
- name: inventory
profiles: [reader]
- name: catalog
profiles: [reader]
Declared vs referenced schemas
Declared schemas can be created and have their owner converged by pgroles. Referenced-only schemas must already exist:
schemas:
- name: app_managed
owner: app_owner
profiles: []
grants:
- role: reporting
privileges: [USAGE]
object: { type: schema, name: app_managed }
- role: reporting
privileges: [SELECT]
object: { type: table, schema: existing_warehouse, name: "*" }
In this example:
app_managedis declared underschemas:, so pgroles can create it and set its owner.existing_warehouseis only referenced from a top-level grant, so it must already exist beforeapplyruns.
Wildcard grants and future objects
Use name: "*" to grant on all current objects of a type in a schema. pgroles expands relation wildcards safely by object type, so table, view, and materialized_view privileges do not bleed across each other.
Pair wildcard grants with default_privileges when the same role should access future objects created by the migration or owner role. Wildcards cover existing objects at reconcile time; default privileges cover objects created later.
Managed owners still need declared privileges
If the role that owns tables or functions is also inside pgroles' managed role set, declare the privileges you want that owner role to keep. PostgreSQL owners effectively have broad privileges on their own objects, and pgroles treats undeclared current privileges as drift in authoritative mode.
Convergent model
pgroles is convergent
The manifest represents the entire desired state. Roles, grants, default privileges, and memberships that exist in the database but are absent from the manifest will be dropped or revoked. Declared schemas are created and their owner may be converged, but schemas are not dropped automatically. Only declare roles and schemas that pgroles should manage.
Next: use the manifest reference for exact field names, defaults, and bundle-mode details.