CLI quick start

On this page

Get up and running with pgroles in a few minutes.


Prerequisites

  • PostgreSQL 16, 17, or 18 — the versions supported and tested in CI
  • A disposable database named mydb, with a table in public and an administrator connection for this exercise

Installation

Download the binary for your platform from the latest stable release, then verify pgroles --version. See installation for containers and Cargo.

Create a manifest

Before typing any YAML, here is the role graph the manifest below describes — a single login role with read-only access to one schema.

The role graph you are about to build

One login role, analytics, granted read-only access to the public schema in mydb.

Role

analytics

LOGIN

Analytics read-only role

is granted

CONNECTDatabasemydb

Lets the role open a connection to the database.

USAGESchemapublic

Lets the role reach the objects that live inside the schema.

SELECTTablespublic.*

Read-only access to every table currently in the schema.

No membership edges yet

This manifest declares no memberships, so analytics holds every privilege directly. When you do add one, the edge runs member -> role: the member inherits the privileges of the role it is granted, never the other way around.

If schema USAGE, table SELECT, and membership still feel like separate pieces, start with The permission chain, then return here to apply the model.

Create a file called pgroles.yaml:

roles:
  - name: analytics
    login: true
    comment: "Analytics read-only role"

grants:
  - role: analytics
    privileges: [CONNECT]
    object: { type: database, name: mydb }
  - role: analytics
    privileges: [USAGE]
    object: { type: schema, name: public }
  - role: analytics
    privileges: [SELECT]
    object: { type: table, schema: public, name: "*" }

Validate the manifest

Check the manifest is valid without connecting to a database:

pgroles validate
Manifest is valid.
  1 role(s) defined
  3 grant(s) defined
  0 default privilege(s) defined
  0 membership(s) defined

Plan changes

See what SQL would be generated against a live database:

pgroles diff --mode additive --database-url postgres://localhost/mydb

This shows the exact SQL statements needed to converge the database to match your manifest.

Apply changes

When you're happy with the plan, apply it:

pgroles apply --mode additive --database-url postgres://localhost/mydb

Or preview without executing:

pgroles apply --mode additive --database-url postgres://localhost/mydb --dry-run

Using environment variables

Instead of passing --database-url every time, set the DATABASE_URL environment variable:

export DATABASE_URL=postgres://localhost/mydb
pgroles diff --mode additive
pgroles apply --mode additive

Verify the result

Run the same additive diff again; it should print -- No changes needed. This proves convergence within additive mode, which leaves undeclared access untouched. Continue with staged adoption before enabling revocations on an existing database.