Getting Started

Quickstart

Install the CLI, create a project, allow your device, fetch branch URLs, connect an app, and run your first migration — all in under five minutes.

This is the fastest path from zero to a working Postgres branch. By the end of this guide, you'll have a provisioned database, your device allowlisted, connection URLs in your .env, and a Prisma migration running against your AxiomDB branch.

1. Install the CLI

npm install -g axiomdb-cli
axm -h

The package exposes axm as the short binary. The longer axiom binary remains available for backward compatibility with existing scripts and automation.

What the CLI does under the hood

The axm CLI is a Rust binary compiled for your platform and distributed through npm for cross-platform compatibility. When you run axm, it:

  1. Reads the local session token from ~/.axiomdb/.
  2. Constructs an HTTPS request to the AxiomDB Gateway at api.axiomdb.squareexp.com.
  3. Attaches a PASETO v4 bearer token for authentication.
  4. Sends the request to the appropriate /api/v1/* endpoint.
  5. Parses and formats the response for terminal display.

CLI version and updates

Check your current version:

axm --version

Update to the latest version:

npm update -g axiomdb-cli

2. Sign in

axm login

The CLI opens your browser for Square IdP authentication using OAuth2 PKCE (Proof Key for Code Exchange). This is a public client flow that doesn't require a client secret — making it safe for terminal use.

How the PKCE flow works

┌─────────┐         ┌─────────┐         ┌──────────────┐
│  axm    │         │ Browser │         │  Square IdP  │
│  CLI    │         │         │         │              │
└────┬────┘         └────┬────┘         └──────┬───────┘
     │  1. Generate       │                     │
     │  code_verifier +   │                     │
     │  code_challenge    │                     │
     │                    │                     │
     │  2. Start local    │                     │
     │  loopback server   │                     │
     │  on random port    │                     │
     │                    │                     │
     │  3. Open browser ──▶  4. Redirect to ──▶ │
     │     with auth URL  │     IdP authorize   │
     │                    │     endpoint         │
     │                    │                     │
     │                    │  5. User authenticates
     │                    │     ◀────────────────┘
     │                    │
     │                    │  6. Redirect to loopback
     │  7. Receive code ◀─┘     with auth code
     │                    │
     │  8. Exchange code  │
     │  + verifier for   ──────────────────────▶ 9. Validate
     │  tokens            │                      challenge
     │                    │                      issue tokens
     │  10. Store session ◀───────────────────── 11. Return
     │  locally           │                      PASETO tokens
     │                    │
     ▼                    │
  "AxiomDB OAuth          │
   complete"              │

Verifying your session

After signing in, verify your identity:

axm whoami
axm -li

The CLI stores a local session token and uses the active gateway configured for your environment. The session token is a PASETO v4 public token with Ed25519 signatures, with a default access TTL of 15 minutes and a refresh TTL of 7 days.

Password login is deprecated

Password login remains available only for legacy automation that passes --email and --password. All human users should authenticate through the browser-based OAuth2 PKCE flow.

3. Create a project

axm projects create --name "Square Experience" --app-key square_experience --env main

Project creation provisions the first branch:

project: Square Experience
branch:  main
db:      sq_square_experience_main

What happens during project creation

The gateway dispatches a provisioning command through the Redis queue to square-dbctl, which executes:

  1. Database creation:

    CREATE DATABASE sq_square_experience_main;
  2. Role provisioning:

    CREATE ROLE square_experience_main_owner WITH LOGIN PASSWORD '***' CREATEDB;
    CREATE ROLE square_experience_main_rw WITH LOGIN PASSWORD '***';
    CREATE ROLE square_experience_main_ro WITH LOGIN PASSWORD '***';
  3. Permission grants:

    GRANT ALL PRIVILEGES ON DATABASE sq_square_experience_main TO square_experience_main_owner;
    GRANT CONNECT ON DATABASE sq_square_experience_main TO square_experience_main_rw;
    GRANT CONNECT ON DATABASE sq_square_experience_main TO square_experience_main_ro;
  4. PgBouncer userlist update — Adds the runtime role to the PgBouncer authentication file.

  5. Credential storage — Writes the generated URLs to the encrypted secret file at ~/.creds/zone.env with namespaced keys:

    DATABASE_URL_SQUARE_EXPERIENCE_MAIN="postgresql://square_experience_main_rw:***@db.squareexp.com:6432/sq_square_experience_main?sslmode=require"
    DIRECT_URL_SQUARE_EXPERIENCE_MAIN="postgresql://square_experience_main_owner:***@db.squareexp.com:5432/sq_square_experience_main?sslmode=require"
  6. Audit logging — Records project.created and branch.created events.

The app_key parameter

The app_key becomes part of database names, role names, environment variable keys, and branch URL paths. Keep it:

  • Short — It appears in every URL and database name.
  • Lowercase — PostgreSQL normalizes identifiers to lowercase.
  • Stable — Changing it after creation would require renaming databases and roles.
  • Unique per environment — The (app_key, env) pair must be unique across all projects.

4. Select the project

axm projects list
axm projects use <project-id>

With an active project, branch commands can omit the project ID:

axm branches list          # Uses active project
axm branches urls --name main  # Uses active project

Without an active project, the CLI prints an actionable message:

No active project selected.
Run `axm projects use <project-id>` to set one.

Listing projects

axm projects list

Output:

  ID          NAME                APP_KEY              ENV    STATUS   BRANCHES
  proj_a1b2   Square Experience   square_experience    main   active   3
  proj_c3d4   Admin Dashboard     admin4               dev    active   1

Viewing the current project

axm projects current

5. Allow your device

Open the console Network page and press My IP, then Save JSON. This stores a CIDR rule like:

{
  "policy": {
    "apply": false,
    "mode": "restricted"
  },
  "rules": [
    {
      "cidr": "203.0.113.10/32",
      "expires_in": "7d",
      "label": "My current IP",
      "ports": "both",
      "scope": "project"
    }
  ]
}

Or use the CLI

axm network allow --current
axm -ne add --current

Understanding network modes

ModeRuntime 6432Direct 5432When to use
restrictedAllowlisted onlyAllowlisted onlyDefault. Most secure.
public_runtimePublicAllowlisted onlyWhen app traffic comes from changing IPs (serverless, edge).
public_allPublicPublicTemporary debugging only. Requires owner role and typed confirmation.

Restricted mode is the default. Only explicit CIDRs can reach runtime or direct Postgres ports.

How the allowlist works

When you add a CIDR rule, the gateway:

  1. Stores the rule in the network_rules table with metadata (actor, IP, user agent, expiry).
  2. Generates a managed pg_hba.conf entry:
    # BEGIN AXIOMDB MANAGED RULE proj_a1b2 rule_xyz
    host sq_square_experience_main square_experience_main_rw 203.0.113.10/32 scram-sha-256
    # END AXIOMDB MANAGED RULE
  3. Generates a PgBouncer auth entry.
  4. Generates a UFW firewall rule.
  5. Reloads PostgreSQL and PgBouncer configurations.
  6. Records a network.rule.created audit event.

6. Copy branch URLs

axm branches urls --name main

The output is ready for .env:

DATABASE_URL="postgresql://square_experience_rw:***@db.squareexp.com:6432/sq_square_experience_main?sslmode=require"
DIRECT_URL="postgresql://square_experience_owner:***@db.squareexp.com:5432/sq_square_experience_main?sslmode=require"

URL anatomy

SegmentRuntime URLDirect URLPurpose
Hostdb.squareexp.comdb.squareexp.comSame hostname, different ports
Port64325432PgBouncer vs direct Postgres
Usersquare_experience_rwsquare_experience_ownerRuntime vs migration role
Databasesq_square_experience_mainsq_square_experience_mainSame database
SSLsslmode=requiresslmode=requireTLS mandatory on both

Copy via console

  1. Navigate to your project.
  2. Click on the Branches tab.
  3. Click Connect on the main branch.
  4. The modal shows pre-formatted blocks for Prisma, Drizzle, Kysely, node-postgres, SQLAlchemy, Django, Laravel, Go pgx, and Rust SQLx.
  5. Click the copy button next to the framework you're using.

7. Run a migration

Add both URLs to your .env:

DATABASE_URL="postgresql://square_experience_rw:***@db.squareexp.com:6432/sq_square_experience_main?sslmode=require"
DIRECT_URL="postgresql://square_experience_owner:***@db.squareexp.com:5432/sq_square_experience_main?sslmode=require"

Configure Prisma to use both:

datasource db {
  provider  = "postgresql"
  url       = env("DATABASE_URL")
  directUrl = env("DIRECT_URL")
}

Run the migration:

npx prisma migrate dev --name init

Prisma uses DIRECT_URL (port 5432, owner role) to:

  1. Create a shadow database for diffing.
  2. Apply migration SQL.
  3. Record migration state in _prisma_migrations.

And uses DATABASE_URL (port 6432, runtime role) for:

  1. Application queries.
  2. Connection pooling through PgBouncer.

Why two URLs are required

Prisma Migrate needs direct Postgres access for:

  • Shadow database creation — Prisma creates a temporary database to diff your schema against the current state. The runtime role intentionally cannot create databases.
  • Advisory locks — Migrations use advisory locks to prevent concurrent schema changes. PgBouncer in transaction mode doesn't support advisory locks.
  • Prepared statements — Some migration operations use prepared statements that PgBouncer may not handle correctly.

The runtime role (_rw) only has CONNECT and read/write privileges on the database. It cannot create databases, manage roles, or perform DDL operations. This is a security boundary — if your application's database credentials are compromised, the attacker cannot modify the schema.

If connection fails

Check the Network page first. Most local failures are blocked by allowlist rules, not by database provisioning. Verify your IP is allowlisted and the rule hasn't expired.

8. Verify the setup

After migration, verify everything is working:

# Check migration status
npx prisma migrate status

# Inspect the schema
npx prisma db pull

# Generate the Prisma client
npx prisma generate

Verify from the console

  1. Navigate to your project in the console.
  2. Click on the Tables tab.
  3. You should see your migrated tables listed.
  4. Click on a table to inspect columns and browse rows.

Verify from the CLI

axm monitoring summary

This shows database size, connection counts, and migration state for the active project.

9. Create a branch for feature work

Branches let you test schema changes without touching the main database:

axm branches create --name feature-auth --source main --lifespan 7d

This provisions:

  • A new database: sq_square_experience_main_br_feature-auth
  • Independent credentials (owner, runtime, readonly roles)
  • Schema copied from the source branch
  • Independent network grants

Fetch the branch URLs:

axm branches urls --name feature-auth

Update your .env with the branch URLs and run migrations against the branch:

npx prisma migrate dev --name add-auth-tables

When the feature is complete, merge the schema changes to main and delete the branch:

axm branches delete feature-auth

Complete quickstart checklist

□ npm install -g axiomdb-cli
□ axm login
□ axm projects create --name "My App" --app-key my_app --env main
□ axm projects use <project-id>
□ axm network allow --current
□ axm branches urls --name main
□ Add DATABASE_URL and DIRECT_URL to .env
□ Configure schema.prisma with both URLs
□ npx prisma migrate dev --name init
□ npx prisma generate
□ Start building your application

On this page