Skip to content

PostgreSQL 14+

Subset and anonymize PostgreSQL into safe staging databases in seconds.

Replace brittle full-database dump and restore scripts with a PostgreSQL-aware CLI. Subveil follows foreign-key relationships, masks PII as rows are read, and writes a connected subset directly to your target database.

subveil.yaml — PostgreSQL excerpt
version: 1engine: postgressource:  dsn_env: SUBVEIL_SOURCE_DSNtarget:  dsn_env: SUBVEIL_TARGET_DSN

Why pg_dump scripts and in-place masking break down

Full dumps move more data than a staging slice needs

A regular pg_dump and restore copies whole tables before your team can use a smaller dataset. Subveil computes a subset through PostgreSQL foreign-key relationships and reads the chosen rows from a read-only REPEATABLE READsnapshot. With one reader it streams rows through masking; -j 4 uses snapshot-sharing readers and temporary spools before dependency-ordered loading.

UPDATE-based anonymization still rewrites production rows

In-place UPDATE masking changes the source, creates WAL and dead tuples, and can trigger replication and vacuum work. Subveil never updates the source: it transforms values before writing them to the target. Use a least-privilege, read-only source role.

With --create-schema, PostgreSQL schema-only DDL is prepared using a compatible pg_dump client; row data is read and loaded by Subveil.

PostgreSQL-native behavior

Configure the engine explicitly and keep PostgreSQL-specific column types and schema behavior in view as you prepare a safe target.

subveil.yaml
version: 1engine: postgres​source:  dsn_env: SUBVEIL_SOURCE_DSN​target:  dsn_env: SUBVEIL_TARGET_DSN​masking:  seed_env: SUBVEIL_SEED​subset:  roots:    - table: public.accounts      where: "status = 'active'"​tables:  public.customers:    columns:      email:        transformer: email      profile:        transformer: jsonb        paths:          - path: "$.customer.email"            transformer: email      last_ip:        transformer: ip

JSONB paths, UUIDs, INET and CIDR

Mask selected JSON/JSONB keys with JSONPath rules, preserve JSON fields that are not selected, and choose deterministic transformers for UUID and IP-address columns. The ip transformer emits valid IPv4 or IPv6 values suitable for PostgreSQL inet/cidr and text columns.

Sequences and foreign-key cycles

PostgreSQL SERIAL and identity sequences are synchronized after loading so subsequent inserts continue beyond the imported keys. The graph planner orders referenced tables and resolves nullable self-references or cycles with a deferred second pass where the schema allows it.

Connect to PostgreSQL where it runs

Subveil uses PostgreSQL connections from the machine or runner where the CLI runs. It can connect to self-hosted PostgreSQL 14+ and PostgreSQL-compatible endpoints on AWS RDS, Aurora PostgreSQL, Supabase, Neon, and Google Cloud SQL, provided network access, TLS settings, and database permissions are configured for that environment.

Create a PostgreSQL pull-request preview in GitHub Actions

This example uses the same PostgreSQL major for its service and schema client. Set the SUBVEIL_VERSION repository variable to a published CLI version, and store the source DSN and masking seed as repository secrets. Keep the source reachable from the runner.

.github/workflows/postgresql-preview.yml
name: PostgreSQL masked previewon:  pull_request:    types: [opened, synchronize, reopened]​jobs:  preview:    runs-on: ubuntu-latest    services:      postgres:        image: postgres:17        env:          POSTGRES_PASSWORD: subveil        ports: ["5432:5432"]        options: >-          --health-cmd "pg_isready -U postgres"          --health-interval 5s --health-timeout 5s --health-retries 12    env:      SUBVEIL_VERSION: ${{ vars.SUBVEIL_VERSION }}      SUBVEIL_SOURCE_DSN: ${{ secrets.SUBVEIL_SOURCE_DSN }}      SUBVEIL_TARGET_DSN: postgresql://postgres:subveil@localhost:5432/postgres?sslmode=disable      SUBVEIL_SEED: ${{ secrets.SUBVEIL_SEED }}    steps:      - uses: actions/checkout@v4      - name: Install Subveil and PostgreSQL client        run: curl -fsSL https://subveil.dev/install.sh | sh -s -- --version "$SUBVEIL_VERSION" --pg-client 17      - name: Build masked preview        run: subveil pull --config subveil.yaml --create-schema -j 4

PostgreSQL data masking FAQ

How do I anonymize a PostgreSQL database without copying all production data?

Define root tables and optional row filters in subveil.yaml, review the selection with subveil plan, then run subveil pull. Subveil follows foreign-key relationships from the selected rows and masks configured columns as it reads them, so you load a referentially connected subset rather than a full production dump.

How does Subveil mask PII inside PostgreSQL JSONB columns?

Configure the column with transformer: jsonb and list JSONPath rules such as $.customer.email with an in-process transformer like email. Matching values are masked while unlisted JSON fields are retained.

Does Subveil require pg_dump?

A compatible pg_dump client is required when using --create-schema or --recreate-schema to copy PostgreSQL DDL. It is not used to dump table rows. Without those flags, prepare the target schema separately and Subveil streams the selected rows into it.

Can I run Subveil with RDS, Aurora, Supabase, Neon, or Cloud SQL?

Subveil connects to PostgreSQL endpoints using a PostgreSQL DSN. RDS for PostgreSQL, Aurora PostgreSQL, Supabase, Neon, and Google Cloud SQL can be used when the endpoint is reachable from the CLI host and the database role has the required access. Check provider-specific network and permission settings.

Read the full CLI documentation