Files
util.nix/package/db-tool

db-tool

PostgreSQL development database management tool. Drop-in replacement for per-project database.sh / postgres-init.sh / postgres-cleanup.sh scripts. Provides database, postgres-init, and postgres-cleanup binaries.

Provided Binaries

Binary Description
database Main script for managing migrations, deployments, and logs.
postgres-init Ephemeral PostgreSQL cluster initialization and startup.
postgres-cleanup Graceful shutdown and cleanup of the PostgreSQL cluster.

Required Environment Variables

These variables must be set for db-tool to function.

Variable Description
LOCAL_DIR Absolute path to the project root directory.
DB_URL Full PostgreSQL connection string (e.g., postgresql://user@localhost/dbname?host=$PG_WORKING_DIR).
PG_WORKING_DIR Directory where the PostgreSQL cluster data and sockets are stored.

Optional Environment Variables

Variable Default Value Description
DATABASE_DIR ${LOCAL_DIR}/db Root directory for database-related files.
MIGRATION_DIR ${DATABASE_DIR}/migration Directory containing SQL migration files.
DATABASE_SOURCE ${DATABASE_DIR}/src Directory containing source SQL files for hydration.
PG_URL_VAR PGURL The name of the environment variable where the computed PG URL will be exported.
PG_LOG_PATH (unset) Path to redirect PostgreSQL server logs.
PG_CONF_FILE (unset) Path to a postgresql.conf file. When set, replaces the script-generated config entirely on fresh init. port and unix_socket_directories are still appended at runtime (always overridden). When set, PG_DISABLE_LOGGING and PG_SHARED_PRELOAD_LIBRARIES are ignored.
PG_SHARED_PRELOAD_LIBRARIES pg_cron Comma-separated shared_preload_libraries value. Set to empty string to disable. Ignored when PG_CONF_FILE is set.
PG_DISABLE_LOGGING 0 Set to 1 to disable PostgreSQL logging collector. Ignored when PG_CONF_FILE is set.
PG_HECTIC_INHERITANCE 1 Apply the hectic inheritance bundle to the target database after init. Set to 0 to disable.
HECTIC_INHERITANCE_SQL (auto) Override path to the SQL file applied by PG_HECTIC_INHERITANCE=1. Defaults to the SQL shipped with postgres-init.
PATCH_LOG (stdout) Path to log the output of database patches.
HYDRATE_LOG (stdout) Path to log the output of database hydration.

Postgres Package Override

By default, db-tool/postgres-init/postgres-cleanup use plain postgresql_17 from nixpkgs. If you need extensions (e.g. pg_cron), override the postgres package per-output:

let
  myPg = pkgs.postgresql_17.withJIT.withPackages (_: [
    pkgs.postgresql_17.pkgs.pg_cron
  ]);
in {
  packages = [
    (pkgs.hectic."db-tool".override          { postgresql = myPg; })
    (pkgs.hectic."postgres-init".override    { postgresql = myPg; })
    (pkgs.hectic."postgres-cleanup".override { postgresql = myPg; })
  ];
}

pull_staging Contract

The pull_staging subcommand allows importing data from a remote staging environment into the local test-data.sql file. This functionality requires four specific environment variables to be defined:

  1. STAGING_SSH_HOST: The SSH destination for the staging server.
  2. STAGING_DB_URL: The PostgreSQL connection string for the remote staging database.
  3. STAGING_DUMP_TABLES: A space-separated list of tables to include in the data dump.
  4. STAGING_DUMP_FLAGS: Additional flags to pass to pg_dump (e.g., --column-inserts).

If any of these variables are missing when pull_staging is invoked, the tool will exit with code 3 and print the name of the missing variable to stderr.

Subcommands

  • deploy: Execute the full deployment flow (hydrate + patch). Supports --cleanup to teardown after success.
  • log: Inspect database logs. Supports list and index-based selection.
  • test: Execute database tests located in ${DATABASE_DIR}/test/test.sql.
  • check: Run a deployment validation in an isolated, temporary PostgreSQL cluster.
  • cleanup: Stop the local database cluster and remove the PG_WORKING_DIR.
  • pull_staging: Import data from the staging environment based on the env contract.
  • init: Wrapper around postgres-init to start the cluster.
  • migrator: Directly invoke the migration tool with the correct environment context.

shellHook Example

To use db-tool in a Nix development shell, add the following to your flake.nix or shell.nix:

{
  # ...
  devShells.default = pkgs.mkShell {
    packages = [
      pkgs.hectic.db-tool
      pkgs.hectic.postgres-init
      pkgs.hectic.postgres-cleanup
    ];

    shellHook = ''
      export LOCAL_DIR="$PWD"
      export DATABASE_DIR="$LOCAL_DIR/db"
      export MIGRATION_DIR="$DATABASE_DIR/migration"
      export DATABASE_SOURCE="$DATABASE_DIR/src"
      export PG_WORKING_DIR="$LOCAL_DIR/focus/postgresql"
      export DB_URL="postgresql://user@localhost/dbname?host=$PG_WORKING_DIR&port=5432"
      
      # for other non-db scripts (deploy.sh, task.sh, etc.):
      export HECTIC_LIB="${pkgs.hectic.helpers.posix-shell.log}"

      # Initialize and start the ephemeral database cluster
      . ${pkgs.hectic.postgres-init}/bin/postgres-init
    '';
  };
}

hectic Inheritance Bundle

pkgs.hectic.hectic-inheritance ships a SQL artifact that bootstraps a hectic schema with two parent tables and DDL event triggers:

  • hectic.created_at(created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()) — every user table must INHERITS (hectic.created_at). The event trigger hectic_enforce_created_at_inheritance raises an exception on CREATE TABLE otherwise.
  • hectic.updated_at(updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()) — optional. Any table that inherits from it automatically gets a BEFORE UPDATE FOR EACH ROW trigger calling hectic.set_updated_at() attached by hectic_attach_updated_at_trigger.

Always-exempt schemas: hectic, information_schema, anything matching pg_*. Declarative partitions (relispartition = true) and temporary tables are also auto-exempt.

Per-database opt-out for additional schemas via the hectic.inheritance_extra_excluded_schemas GUC (comma-separated):

ALTER DATABASE mydb SET hectic.inheritance_extra_excluded_schemas = 'legacy,etl';

Apply via postgres-init

Applied automatically. Set PG_HECTIC_INHERITANCE=0 to opt out.

Apply via migrator or any psql pipeline

# in your devshell
shellHook = ''
  export HECTIC_INHERITANCE_SQL=${pkgs.hectic.hectic-inheritance}/share/hectic/hectic-inheritance.sql
'';
psql "$DB_URL" -v ON_ERROR_STOP=1 -f "$HECTIC_INHERITANCE_SQL"

The SQL is also exposed via self.lib.hecticInheritance.sql (string) and self.lib.hecticInheritance.path (Nix path) for inline pipelines.

Exit Codes

Code Meaning
1 Generic error.
2 Ambiguous arguments or state.
3 Missing required argument or environment variable.
5 Provided table does not exist.
9 Argument or command not found.
13 Program bug or unexpected system state.
127 Command not found (missing dependency).