# Installation

This extension is built from the `graph/` crate with `pgrx` 0.19.1. The crate
officially supports PostgreSQL 14 through 18 and defaults to `pg17`. A legacy
`pg13` pgrx feature remains available on a best-effort basis because pgrx
still exposes it, but PostgreSQL 13 has reached upstream EOL and is not part of
the release support matrix.

## Source Build Requirements

These requirements apply to PGXN, manual source, and direct `cargo-pgrx`
installs. Homebrew and Docker installs do not require installing Rust or pgrx
separately.

| Requirement | Version or note |
|---|---|
| Rust | `1.96`, pinned by `graph/rust-toolchain.toml` |
| PostgreSQL | 14, 15, 16, 17, or 18, with server development headers and `pg_config` |
| pgrx | `0.19.1` |
| Crate feature | One of `pg14`, `pg15`, `pg16`, `pg17`, `pg18` |
| Extension control | `graph/graph.control` |

<Callout type="info">
Install with the PostgreSQL major that matches the target server. A `pg17`
build should not be installed into a PostgreSQL 16 server.
</Callout>

## Homebrew Install

On macOS, pgGraph is available from the
[Evokoa Homebrew tap](https://github.com/Evokoa/homebrew-tap) for local
PostgreSQL extension installs. The current formula is `Evokoa/tap/pggraph`,
installs pgGraph 0.1.8, and builds against Homebrew `postgresql@17`.

```bash
brew tap Evokoa/tap
brew install pggraph
brew test pggraph
```

Create and verify the extension in a local database:

```bash
brew services start postgresql@17
psql -d postgres -c "CREATE EXTENSION graph;"
psql -d postgres -c "SELECT extname, extversion FROM pg_extension WHERE extname = 'graph';"
```

Use Homebrew when you want a local macOS PostgreSQL extension install. For the
fastest zero-build quickstart, use the pre-built Docker image below.

## Install pgrx

Install cargo-pgrx and register the PostgreSQL on your `PATH` with pgrx. The
major is detected from `pg_config`:

```bash
cargo install cargo-pgrx --version 0.19.1 --locked
PG_MAJOR=$(pg_config --version | sed -E 's/[^0-9]*([0-9]+).*/\1/')
cargo pgrx init --pg${PG_MAJOR}="$(which pg_config)"
```

To register a different installation, point the flag at that server's
`pg_config`. For example, a Debian or Ubuntu PostgreSQL 16 install:

```bash
cargo pgrx init --pg16=/usr/lib/postgresql/16/bin/pg_config
```

For PostgreSQL 13, use the legacy `pg13` pgrx feature only as best-effort
compatibility. It is not covered by release gates after PostgreSQL 13 upstream
EOL.

## PGXN Source Install

pgGraph is available on PGXN as a source distribution. Because pgGraph is a
Rust/pgrx extension, source installation requires Rust and `cargo-pgrx` before
running `pgxn install`.

```bash
cargo install cargo-pgrx --version 0.19.1 --locked
# Register the installed PostgreSQL with pgrx (auto-detects the major):
PG_MAJOR=$(pg_config --version | sed -E 's/[^0-9]*([0-9]+).*/\1/')
cargo pgrx init --pg${PG_MAJOR}="$(which pg_config)"
pgxn install pgGraph
```

## Manual Source Install

Compile and install the extension from source:

```bash
git clone https://github.com/evokoa/pggraph.git
cd pggraph
make install # may need sudo
```

If your machine has multiple PostgreSQL installations, set `PG_CONFIG` to the
target server's `pg_config`, then re-run the installation:

```bash
export PG_CONFIG=/usr/lib/postgresql/17/bin/pg_config
make install
```

If `sudo` is needed for `make install`, preserve `PG_CONFIG`:

```bash
sudo --preserve-env=PG_CONFIG make install
```

If compilation fails with `fatal error: postgres.h: No such file or directory`,
install the PostgreSQL server development package for the target PostgreSQL
major, such as `postgresql-server-dev-17` on Ubuntu or Debian.

## Build And Install With cargo-pgrx

`make install` wraps this flow. To run it directly, build with the feature that
matches your `pg_config` major and install into that server:

```bash
cd graph
PG_MAJOR=$(pg_config --version | sed -E 's/[^0-9]*([0-9]+).*/\1/')
cargo pgrx install --no-default-features --features pg${PG_MAJOR} --pg-config="$(which pg_config)"
```

To target a different installation, set its `pg_config` explicitly. For example,
a Debian or Ubuntu PostgreSQL 16 install:

```bash
cd graph
cargo pgrx install --no-default-features --features pg16 --pg-config=/usr/lib/postgresql/16/bin/pg_config
```

## Create The Extension

```sql
CREATE EXTENSION graph;
```

The bootstrap SQL creates:

| Object | Purpose |
|---|---|
| `graph.node_ref` | Composite start-node type for one traversal overload |
| `graph.node_ref(regclass, text)` | Constructor for `graph.node_ref` |
| `graph.traverse(graph.node_ref[], ...)` | SQL wrapper over the Rust multi-start traversal overload |
| `graph._registered_tables` | Durable graph-scoped registration catalog for node source tables |
| `graph._registered_edges` | Durable graph-scoped registration catalog for edge definitions |
| `graph._registered_filter_columns` | Durable graph-scoped registration catalog for traversal filter columns |
| `graph._graphs` | Durable named graph metadata and default graph identity |
| `graph._build_jobs` | Durable graph-scoped asynchronous build job state |
| `graph._maintenance_jobs` | Durable graph-scoped maintenance job state |
| `graph._jobs` | Durable graph-scoped generic job state for hosted schedulers |
| `graph._job_runs` | Durable run history for generic graph jobs |
| `graph._sync_policies` | Durable graph-scoped sync policy state |
| `graph._sync_log` | Durable trigger sync log |
| `graph._sync_buffer` | Legacy sync buffer compatibility table |

Internal catalog tables are extension-owned. They are readable by `PUBLIC` but
not directly writable by non-admin roles.

<Callout type="warning">
Pre-release catalog schema changes require recreating development and test
databases. Drop and recreate the extension with `DROP EXTENSION graph CASCADE;`
followed by `CREATE EXTENSION graph;` instead of relying on runtime migrations.
</Callout>

## Docker Install Options

pgGraph supports three Docker installation paths:

| Path | Use when |
|---|---|
| Pull the pre-built image from GHCR | You want the fastest start with no build step |
| Build a PostgreSQL image with pgGraph already installed | You want a new container image for Evokoa or local evaluation |
| Install into an existing running PostgreSQL container | You already have a PostgreSQL container and want to add pgGraph to it |

### Pre-built Docker Image

A pre-built image is published on GitHub Container Registry for each release.
This is the fastest Docker path — no build step is needed. Published images are
available for PostgreSQL 14 through 18 and support **linux/amd64** and
**linux/arm64**, so they work on macOS, Linux, and Windows (via Docker Desktop
or WSL2).

```bash
docker pull ghcr.io/evokoa/pggraph:0.1.8
```

| Tag | Description |
|---|---|
| `0.1.8` | Pinned reproducible tag (PostgreSQL 17) — always resolves to the same image digest |
| `latest` | Moving tag that points to the most recent stable PostgreSQL 17 image |
| `pg14-0.1.8` through `pg18-0.1.8` | Versioned image for a specific PostgreSQL major |
| `pg14` through `pg18` | Latest stable image for a specific PostgreSQL major |

Start the container:

```bash
docker run --rm \
  -e POSTGRES_PASSWORD=postgres \
  -e POSTGRES_DB=graph \
  -p 5432:5432 \
  ghcr.io/evokoa/pggraph:0.1.8
```

Verify that `pg_cron` and `graph` are installed and loaded:

```bash
psql -h localhost -U postgres -d graph -c "SELECT extname, extversion FROM pg_extension WHERE extname IN ('pg_cron','graph');"
```

The default image includes PostgreSQL 17, `pg_cron`, and pgGraph. Use the
`pg14-*` through `pg18-*` tags when you need a specific PostgreSQL major. On
first initialization, `docker/init/01-create-extensions-and-schedule.sql`
creates the `pg_cron` and `graph` extensions and schedules
`graph.run_scheduled_maintenance()` every five minutes. For databases beyond
the initial Docker database, create the extension explicitly with
`CREATE EXTENSION graph;`.

### Build A PostgreSQL Image With pgGraph

From the repository root, build the root `Dockerfile` with the PostgreSQL major
that should be installed in the image:

```bash
docker build --build-arg PG_MAJOR=17 -t pggraph-postgres:17 .
```

Start the container:

```bash
docker run \
  --name pggraph-postgres \
  -e POSTGRES_PASSWORD=postgres \
  -e POSTGRES_DB=graph \
  -p 5432:5432 \
  pggraph-postgres:17
```

The root Docker image starts PostgreSQL with `pg_cron` and `graph` in
`shared_preload_libraries`, runs
`docker/init/01-create-extensions-and-schedule.sql` on first database
initialization, and creates:

| Object | Purpose |
|---|---|
| `pg_cron` extension | Enables cron-style scheduling inside the Docker database |
| `graph` extension | Installs pgGraph in the Docker database |
| `pggraph-maintenance` cron job | Runs `graph.run_scheduled_maintenance()` every five minutes |

The init SQL runs only when PostgreSQL initializes a new data directory. If you
reuse an existing Docker volume, recreate the volume before expecting init SQL
changes to apply.

For databases beyond the initial Docker database, create the extension
explicitly:

```sql
CREATE EXTENSION graph;
```

### Install Into An Existing PostgreSQL Container

Use the helper script from the repository root:

```bash
scripts/install_into_docker_postgres.sh CONTAINER [PG_MAJOR] [DB_NAME] [DB_USER]
```

For example, to install pgGraph built for PostgreSQL 17 into a running container
named `my-postgres` and create the extension in `appdb`:

```bash
scripts/install_into_docker_postgres.sh my-postgres 17 appdb postgres
```

The one-shot script builds the matching pgGraph package, copies the extension
control, SQL, and shared library files into the target container, and runs:

```sql
CREATE EXTENSION IF NOT EXISTS graph;
```

The lower-level steps are also available when you want to build once and install
the same package into one or more containers:

```bash
scripts/build_docker_pggraph_package.sh 17 target/docker-packages
scripts/copy_pggraph_package_to_docker_postgres.sh \
  my-postgres target/docker-packages/graph-pg17 17 appdb postgres
```

To build packages for all supported PostgreSQL majors:

```bash
scripts/build_docker_pggraph_package.sh all target/docker-packages
```

Set `SKIP_CREATE_EXTENSION=1` to copy the files without creating the extension:

```bash
SKIP_CREATE_EXTENSION=1 scripts/install_into_docker_postgres.sh my-postgres 17
```

<Callout type="warning">
The PostgreSQL major must match the target container. A PostgreSQL 17 pgGraph
build should not be copied into a PostgreSQL 16 container. The target container
also needs compatible operating-system and CPU architecture assumptions for the
compiled extension.
</Callout>

## shared_preload_libraries

Most functionality works without `shared_preload_libraries`, but setting it lets
PostgreSQL call `_PG_init()` at server startup. `_PG_init()` registers the GUCs
and asks the operating system to pre-warm an existing `.pggraph` file.

```conf
shared_preload_libraries = 'graph'
```

Then restart PostgreSQL.

<Callout type="info">
Pre-warming does not load the engine in every backend. Query backends still load
the graph lazily on first use when `graph.auto_load = true`.
</Callout>

## Verify Installation

```sql
SELECT graph.test_enabled();
SELECT * FROM graph.status();
```

Expected initial state before build:

| Column | Typical value |
|---|---|
| `node_count` | `0` |
| `edge_count` | `0` |
| `sync_mode` | `trigger` unless configured |
| `schema_status` | `current` |

## Development Test Commands

```bash
cd graph
cargo fmt --check
cargo test --features pg17
cargo pgrx test pg17
```

SQLSTATE and ACL boundary tests intentionally run outside `cargo pgrx test`
because they need a normal client/server error boundary:

```bash
cd graph
PG_VERSION_FEATURE=pg17 DBNAME=pggraph_boundary ./tests/heavy/run_sqlstate_acl_boundary.sh
```

## Docker And Packaging Checks

The heavy test suite includes packaging, install smoke, function metadata audit,
backup/restore, Docker smoke, and PostgreSQL major matrix scripts:

```bash
cd graph
PG_VERSION_FEATURE=pg17 ./tests/heavy/package_validate.sh
PG_VERSION_FEATURE=pg17 DBNAME=pggraph_install ./tests/heavy/fresh_install_smoke.sh
PG_VERSION_FEATURE=pg17 DBNAME=pggraph_metadata ./tests/heavy/function_metadata_audit.sh
./tests/heavy/playground_release_gate.sh
./tests/heavy/docker_smoke.sh
```

For the full release gate:

```bash
cd graph
PG_VERSION_FEATURE=pg17 ./tests/heavy/run_release_gate.sh
```

## Upgrading and Migration

If you are upgrading from a pre-named-graph version of pgGraph (Phase 3 or earlier), your installation will migrate automatically to the multi-graph architecture. This section explains how the migration handles existing data.

### Global Catalog to Default Graph

Earlier versions of pgGraph used a single, global catalog for registration (`graph._registered_tables`, etc.). During migration, the extension creates a default graph named `default` in the `public` namespace. All existing global catalog entries are automatically assigned to this `default` graph. Your existing queries continue to work because the legacy selected-graph workflow still targets the default graph when you do not opt into a named graph explicitly.

### Artifact Path Migration

The durable `.pggraph` artifact now lives under `$PGDATA/<graph.data_dir>/<graph_id>/main.pggraph` for each graph. The `graph_id` is the stable directory key; graph name and namespace stay in PostgreSQL catalogs rather than the filesystem path. If you inspect artifacts directly, point your tooling at the graph id and the configured `graph.data_dir` value.

### Projection Generation Migration

If your installation used pre-computed projections, the migration seeds a new generation sequence for the `default` graph and repoints durable metadata at the migrated catalog rows. Existing projections continue to serve until you rebuild or repair them against the new catalog state.

### Rollback and Repair Guidance

If the migration fails (e.g., due to insufficient disk space when moving artifacts), the extension may enter an inconsistent catalog state.

**To recover:**
1. **Restore from Backup**: If you dumped `pg_extension_config_dump` prior to upgrade, restore the catalog tables.
2. **Manual Rebuild**: Run `SELECT * FROM graph.select_graph('default');` followed by `SELECT graph.reset();` and then `SELECT * FROM graph.build();` to recreate the selected graph from your authoritative PostgreSQL source tables.
3. **Artifact Cleanup**: If old artifact files remain under the previous graph data directory, remove them only after the rebuilt default graph is healthy.
4. **Log Inspection**: Check the PostgreSQL logs for `PG009` or `PG018` errors during extension update.
