# Configuration reference

> Required and high-impact runtime settings: io_method default vs sync, max_stack_depth, RUST_MIN_STACK, ulimit -s, listen_addresses, and build-time PGRUST_* path env vars.

- Repository: malisper/pgrust
- GitHub: https://github.com/malisper/pgrust
- Human docs: https://grok-wiki.com/public/docs/malisper-pgrust-7e0c8e82bc21
- Complete Markdown: https://grok-wiki.com/public/docs/malisper-pgrust-7e0c8e82bc21/llms-full.txt

## Source Files

- `crates/backend/utils/misc/guc_tables/src/tables.rs`
- `crates/backend/utils/misc/guc_tables/src/consts.rs`
- `crates/backend/storage/buffer/bufmgr/src/buf_aio.rs`
- `crates/backend/utils/init/miscinit/src/boot_paths.rs`
- `.cargo/config.toml`
- `docker/entrypoint.sh`
- `scripts/run-recovery-tap`

---

---
title: "Configuration reference"
description: "Required and high-impact runtime settings: io_method default vs sync, max_stack_depth, RUST_MIN_STACK, ulimit -s, listen_addresses, and build-time PGRUST_* path env vars."
---

pgrust boots a Postgres 18.3-shaped GUC table plus a small set of process and build-time knobs that the stock binary defaults do not safely satisfy. High-impact settings are applied as postmaster command-line `-c` / `--NAME=VALUE` overrides, `postgresql.conf` / `TEMP_CONFIG` lines, process environment (`RUST_MIN_STACK`), OS stack rlimit (`ulimit -s`), and compile-time `PGRUST_*` path env vars baked via `option_env!`.

## Required launch profile

Every supported local, Docker, and regression path pins the same core set:

| Layer | Setting | Value used in-tree | When applied |
| --- | --- | --- | --- |
| GUC | `io_method` | `sync` | Postmaster start (`PGC_POSTMASTER`) |
| GUC | `max_stack_depth` | `60000` (or `7000kB` in some TAP harnesses) | Superuser-settable (`PGC_SUSET`); harnesses set at start |
| Env | `RUST_MIN_STACK` | `33554432` (32 MiB) | Process environment before `postgres` exec |
| OS | stack rlimit | `ulimit -s 65520` | Shell / entrypoint before start |
| GUC | `listen_addresses` | empty (socket-only) or `*` (Docker public) | Postmaster start |

<RequestExample>
```bash
ulimit -s 65520

RUST_MIN_STACK=33554432 target/release/postgres \
  -D /tmp/pgrust-data \
  -F \
  -c listen_addresses= \
  -k /tmp \
  -p 5432 \
  -c io_method=sync \
  -c max_stack_depth=60000
```
</RequestExample>

Docker injects the same GUCs automatically via `PGRUST_SERVER_OPTS` and always appends `listen_addresses='*'` for the public server (temp init server uses `listen_addresses=''`).

```text
┌─────────────────────────────────────────────────────────────┐
│  Host process                                                │
│   ulimit -s 65520                                            │
│   RUST_MIN_STACK=33554432                                    │
│   postgres -D … -c io_method=sync -c max_stack_depth=60000  │
│              -c listen_addresses=…  (-h / -i / -k / -p)     │
└─────────────────────────────────────────────────────────────┘
         │ compile-time bake
         ▼
   PGRUST_PGSHAREDIR → share/timezone, timezonesets, templates
   (initdb also needs -L when binary layout ≠ share layout)
```

## `io_method`

| Field | Value |
| --- | --- |
| Name | `io_method` |
| Type | enum |
| Context | `PGC_POSTMASTER` (start-time only) |
| Group | resources / I/O |
| Boot default | `worker` (`IOMETHOD_WORKER = 1`) |
| Enum options | `sync` (`0`), `worker` (`1`) |
| Assign hook | `assign_io_method` |

Boot default matches Postgres (`DEFAULT_IO_METHOD = IOMETHOD_WORKER`). Operational launches **must** set `-c io_method=sync`:

- README, Docker entrypoint (`PGRUST_SERVER_OPTS`), `scripts/run-regression`, serial/isolation harnesses, and recovery TAP all force `sync`.
- Buffer AIO documentation treats synchronous inline transfer as the supported path under `io_method = sync`.
- Selecting `io_uring` is not an exposed option (no `IOMETHOD_IO_URING_ENABLED` build); resolving that method panics with a message to run `io_method = sync`.

Related: `io_workers` (default `3`) applies only when `io_method=worker`.

### Failure without override

Leaving the boot default (`worker`) has historically broken postmaster start in harnesses that do not inject config. Recovery TAP writes:

```conf
io_method = sync
max_stack_depth = 7000kB
```

into `TEMP_CONFIG` for every `PostgreSQL::Test::Cluster` node.

## Stack depth: GUC, Rust, and OS rlimit

Three independent limits interact. Raise **all** of them for multi-user / regression work.

### `max_stack_depth`

| Field | Value |
| --- | --- |
| Name | `max_stack_depth` |
| Type | integer, unit **kB** (`GUC_UNIT_KB`) |
| Context | `PGC_SUSET` |
| Boot default | **`2048`** (2 MiB) — intentional pgrust divergence from C’s `100` |
| Min / max | `100` … `MAX_KILOBYTES` (`2147483647`) |
| Hooks | `check_max_stack_depth`, `assign_max_stack_depth` |

C default 100 kB is too small for pgrust: larger Rust frames, seam indirection, and panic-based `ereport(ERROR)` chains overflow on deep catalog work (for example `\d` can fail with `stack depth limit exceeded`). Boot value `2048` matches the sample-config recommendation.

Harness overrides:

| Consumer | Value |
| --- | --- |
| README / Docker / main regress / isolation | `60000` (kB) |
| recovery / auth / ldap TAP `TEMP_CONFIG` | `7000kB` |

`check_max_stack_depth` rejects values that would leave less than `STACK_DEPTH_SLOP` (512 KiB) under the process stack rlimit, with hint:

> Increase the platform's stack depth limit via "ulimit -s" or local equivalent.

### `RUST_MIN_STACK`

| Field | Value |
| --- | --- |
| Name | `RUST_MIN_STACK` |
| Kind | process environment (Rust runtime) |
| Default in-tree | `33554432` bytes (32 MiB) |

Set **before** starting the binary. Docker entrypoint: `export RUST_MIN_STACK="${RUST_MIN_STACK:-33554432}"`. Regression and isolation scripts export the same default.

This is not a GUC. It sizes Rust thread stacks independently of Postgres’s `max_stack_depth` accounting.

### `ulimit -s`

| Field | Value |
| --- | --- |
| Command | `ulimit -s 65520` |
| Meaning | soft `RLIMIT_STACK` in **kB** (shell units) |

Entrypoint and harnesses run `ulimit -s 65520 2>/dev/null || true` so restricted environments do not abort. Without enough OS stack headroom, raising `max_stack_depth` fails the GUC check hook even when the number would otherwise be valid.

Backend code also re-anchors stack base at `PostgresMain` command-loop entry so inherited postmaster depth does not consume the entire GUC budget on the first statement.

## Network and listen settings

### `listen_addresses`

| Field | Value |
| --- | --- |
| Name | `listen_addresses` |
| Type | string list (`GUC_LIST_INPUT`) |
| Context | `PGC_POSTMASTER` |
| Boot default | `localhost` |
| CLI | `-c listen_addresses=…`, `-h VALUE`, `-i` → `*` |

| Mode | Setting | Use |
| --- | --- | --- |
| Local socket-only | `listen_addresses=` (empty) | README / regression: TCP off; connect via Unix socket (`-k` / `unix_socket_directories`) |
| Docker public server | `listen_addresses='*'` | Final entrypoint `exec` |
| Docker temp init server | `listen_addresses=''` | First-boot catalog setup only |

### Related listen knobs

| Name | Boot default | Notes |
| --- | --- | --- |
| `port` | `5432` (`DEF_PGPORT`) | CLI `-p` |
| `unix_socket_directories` | `/tmp` | CLI `-k`; Docker forces `/var/run/postgresql` for Debian `psql` defaults |
| `unix_socket_permissions` | `0777` | Postmaster |

Empty `listen_addresses` with `-k /tmp -p 5432` is the documented local-dev pattern; connect with `psql -h /tmp -p 5432 …`.

## Build-time `PGRUST_*` path env vars

Install paths are **compile-time** strings from `option_env!("PGRUST_…")` in `boot_paths` (and timezone resolution). They are **not** runtime env vars after the binary is linked.

| Build env var | Default if unset | Role |
| --- | --- | --- |
| `PGRUST_PGSHAREDIR` | `/usr/local/pgsql/share` | Share dir: templates, samples, **timezone / timezonesets** |
| `PGRUST_PGBINDIR` | `/usr/local/pgsql/bin` | Anchor for relative path derivation |
| `PGRUST_PKGLIBDIR` | `/usr/local/pgsql/lib` | Package lib dir |
| `PGRUST_SYSCONFDIR` | `/usr/local/pgsql/etc` | Sysconf |
| `PGRUST_INCLUDEDIR` | `/usr/local/pgsql/include` | Includes |
| `PGRUST_PKGINCLUDEDIR` | `/usr/local/pgsql/include` | Package includes |
| `PGRUST_INCLUDEDIRSERVER` | `/usr/local/pgsql/include/server` | Server includes |
| `PGRUST_LIBDIR` | `/usr/local/pgsql/lib` | Lib dir |
| `PGRUST_LOCALEDIR` | `/usr/local/pgsql/share/locale` | Locale |
| `PGRUST_DOCDIR` | `/usr/local/pgsql/share/doc` | Docs |
| `PGRUST_HTMLDIR` | `/usr/local/pgsql/share/doc` | HTML docs |
| `PGRUST_MANDIR` | `/usr/local/pgsql/share/man` | Man pages |

`.cargo/config.toml` bakes a workspace default:

```toml
[env]
PGRUST_PGSHAREDIR = "/tmp/pgrust_share"
```

`force` is false: an explicit shell export overrides the cargo config. README’s recommended source build:

```bash
PGRUST_PGSHAREDIR="$PWD/vendor/postgres-18.3/share" \
cargo build --release --locked --bin postgres
```

Docker build sets `ENV PGRUST_PGSHAREDIR=${PG_SHAREDIR}` (`/usr/share/postgresql/18`) so the image binary’s tz tree matches the packaged share; a symlink maps `${PG_SHAREDIR}/timezone` → `/usr/share/zoneinfo` when the PGDG package omits zoneinfo.

### Runtime share override for initdb

Baked `PGRUST_PGSHAREDIR` does not replace `--initdb -L <share>` when the binary install layout cannot derive the vendored share tree. Always pass `-L` for out-of-tree / clone layouts:

```bash
target/release/postgres --initdb \
  -D /tmp/pgrust-data \
  -L "$PWD/vendor/postgres-18.3/share" \
  ...
```

Wrong share/tz paths break boot (missing timezone data or bootstrap SQL).

## How to set configuration

### Command line

| Form | Effect |
| --- | --- |
| `-c name=value` | Set GUC from argv (`PGC_S_ARGV` when secure) |
| `--name=value` | Same long-option path |
| `-h ADDR` | `listen_addresses` |
| `-i` | `listen_addresses=*` |
| `-k DIR` | `unix_socket_directories` |
| `-p N` | `port` |
| `-D DIR` | Data directory (not a GUC write; postmaster data dir) |
| `-F` | `fsync=false` (regress / local convenience) |

`postgres --describe-config` dumps the full visible GUC catalog and exits.

### Config file / TAP

| Mechanism | Example |
| --- | --- |
| `postgresql.conf` | `io_method = sync` |
| Recovery/auth TAP | `TEMP_CONFIG` with `io_method` + `max_stack_depth` |

`io_method` and `listen_addresses` are postmaster-context: change requires restart, not `SIGHUP` alone.

### Docker injection

`PGRUST_SERVER_OPTS` always includes:

```text
-c io_method=sync
-c max_stack_depth=60000
-c unix_socket_directories=/var/run/postgresql
```

Final server: those opts + `-c listen_addresses='*'`. User CMD flags are appended after.

## Quick verification

| Check | Signal |
| --- | --- |
| Server accepts connections | `psql` connects; `SELECT version()` |
| I/O method | `SHOW io_method;` → `sync` when launched with override |
| Stack GUC | `SHOW max_stack_depth;` matches launch override |
| Listen | Empty string → Unix socket only; `*` / host → TCP |
| Share/tz | No timezone load errors at start; initdb completes with success text |

## Common failure modes

| Symptom | Likely misconfig |
| --- | --- |
| Postmaster panic / AIO method error at start | Missing `-c io_method=sync` |
| `stack depth limit exceeded` on trivial or catalog queries | Low `max_stack_depth`, missing `RUST_MIN_STACK`, or small `ulimit -s` |
| GUC reject for `max_stack_depth` with ulimit hint | OS rlimit too low for requested kB + 512 KiB slop |
| Wrong timezone / missing share files | Bad bake-in `PGRUST_PGSHAREDIR` or missing initdb `-L` |
| Clients cannot connect on TCP | `listen_addresses=` empty; use socket path or set addresses / `-i` |
| Docker `psql` cannot find socket | Expect `/var/run/postgresql` (entrypoint overrides boot `/tmp`) |

## Related pages

<CardGroup>
  <Card title="Run the server" href="/run-server">
    Start postmaster with `-D`, socket/TCP flags, and the mandatory stack + `io_method` profile.
  </Card>
  <Card title="Install paths and share directory" href="/install-paths">
    `PGRUST_PGSHAREDIR`, runtime `-L`, vendored share tree, and tz path failures.
  </Card>
  <Card title="postgres CLI reference" href="/cli-reference">
    Flags, must-be-first dispatch options, and `-c` / `--NAME=VALUE` GUC overrides.
  </Card>
  <Card title="Docker environment reference" href="/docker-reference">
    `POSTGRES_*` env, init scripts, and injected server opts.
  </Card>
  <Card title="Troubleshooting" href="/troubleshooting">
    Known failure modes: missing `io_method=sync`, stack overflows, wrong share/tz paths.
  </Card>
  <Card title="Quickstart" href="/quickstart">
    Shortest local path: build, initdb with `-L`, start with required settings, connect with `psql`.
  </Card>
</CardGroup>
