Database Setup
Preparing PostgreSQL for Gold Lapel. Most of it is optional — all of it is worth knowing.
Gold Lapel works with any standard PostgreSQL installation. These optional configurations unlock additional capabilities — faster startup, better write detection, broader index types, and instant matview refresh. If you have five minutes before your first run, this page will help you spend them well.
Nothing here is required. Gold Lapel will start, proxy queries, and begin optimizing without any of these settings in place. It will also tell you, clearly, what it could not do and exactly how to enable it. But if you prefer to prepare the ground before the first connection, this is the complete checklist.
Extensions
Three PostgreSQL extensions give Gold Lapel access to capabilities it cannot replicate on its own. Each one is independent — install whichever ones your environment supports.
Gold Lapel auto-creates these extensions at startup when the connected user has sufficient privileges. If it cannot, it logs the exact command you would need to run. The information below is for those who prefer to set things up in advance, or whose environment requires manual extension management.
pg_stat_statements — Query History Bootstrap
This extension tracks execution statistics for every SQL statement that runs against your database — call count, total time, mean time, rows returned. PostgreSQL maintains this data across restarts.
When Gold Lapel connects to a database with pg_stat_statements available, it reads your historical query stats immediately. Your hottest queries are identified before Gold Lapel observes a single live request. Materialized views can be created for high-impact patterns within the first refresh cycle — no warm-up period.
Without it: Gold Lapel learns query patterns from scratch by observing live traffic through the proxy. For busy applications this takes seconds. For quieter ones, perhaps a few minutes. The extension simply provides a head start.
Install
-- 1. Add to postgresql.conf:
shared_preload_libraries = 'pg_stat_statements'
-- 2. Restart PostgreSQL
-- 3. Create the extension:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements; Part of the PostgreSQL contrib package — available on virtually every provider and installation. Requires shared_preload_libraries and a PostgreSQL restart because it needs to allocate shared memory at startup. Many managed providers enable it by default — you may find it already installed.
pg_trgm — Trigram Indexes for LIKE/ILIKE
Enables GIN trigram indexes for LIKE, ILIKE, and %pattern% queries. Standard B-tree indexes are useless for leading-wildcard searches — PostgreSQL must fall back to a sequential scan every time. Trigram indexes solve this by indexing three-character subsequences, allowing the planner to use an index for patterns that would otherwise require reading every row.
When Gold Lapel detects wildcard text searches hitting the same columns repeatedly, it creates trigram indexes that make those searches dramatically faster. A WHERE name ILIKE '%smith%' that previously scanned the entire table can use an index instead.
Without it: LIKE and ILIKE queries are proxied to PostgreSQL as normal. They work, but wildcard searches remain sequential scans. The queries are not broken — they are simply slower than they need to be.
Install
CREATE EXTENSION IF NOT EXISTS pg_trgm; Part of the PostgreSQL contrib package. Available on all major providers. No restart required — this is the easiest of the three to install.
pg_ivm — Instant Materialized View Refresh
This is the extension I would most encourage you to install, if your environment supports it. Standard materialized views in PostgreSQL are static snapshots — they must be explicitly refreshed to reflect new data. pg_ivm changes this entirely. It maintains materialized views via triggers on the base tables: every INSERT, UPDATE, or DELETE immediately updates the matview. Zero staleness.
A write to your orders table instantly updates any materialized view that depends on orders. Reads always return current data, with no rebuild delay and no refresh cycle to wait for.
Without it: Gold Lapel refreshes materialized views on a configurable polling cycle (default: every 60 seconds). When a write is detected, the affected matview is marked stale and subsequent reads route directly to PostgreSQL until the next refresh completes. Gold Lapel never serves stale data — it routes around it. This works reliably, but pg_ivm eliminates the staleness window entirely.
Install
-- 1. Install the pg_ivm package on your PostgreSQL server
-- 2. Add to postgresql.conf:
shared_preload_libraries = 'pg_ivm'
-- 3. Restart PostgreSQL
-- 4. Create the extension:
CREATE EXTENSION IF NOT EXISTS pg_ivm; Third-party extension — not bundled with PostgreSQL. Requires both a package installation on the server and a shared_preload_libraries entry with a restart. Available on some managed providers; check your provider's extension list. If yours does not offer it, Gold Lapel's polling refresh handles the duty capably.
Multiple shared_preload_libraries
If you are installing both pg_stat_statements and pg_ivm, combine them in a single shared_preload_libraries entry. One restart covers both:
shared_preload_libraries = 'pg_stat_statements, pg_ivm' The order does not matter. PostgreSQL loads all listed libraries at startup regardless of sequence.
For detailed information about each extension — what Gold Lapel does with them, how it behaves without them, and what to expect at startup — see the dedicated Postgres Extensions page.
WAL Configuration
PostgreSQL's Write-Ahead Log (WAL) records every change to your data before it is applied. Gold Lapel can subscribe to these changes via logical decoding to detect writes from any source — your application, a migration script, a cron job, a colleague running SQL in psql, another service entirely. This is the most comprehensive write detection available.
Setting wal_level to logical
Logical decoding requires wal_level = logical. This is the highest WAL level in PostgreSQL, and it includes all the information needed for Gold Lapel to see exactly which tables were modified by any transaction, regardless of where that transaction originated.
First, check your current setting:
SHOW wal_level; wal_level
-----------
logical
(1 row) If your WAL level is replica (the default) or minimal, you will need to change it:
-- In postgresql.conf:
wal_level = logical
-- Then restart PostgreSQL:
sudo systemctl restart postgresql This requires a PostgreSQL restart. Plan accordingly — on production systems, coordinate this with a maintenance window. The restart itself is fast; the configuration change is what requires planning.
What happens without logical WAL
Gold Lapel does not require wal_level = logical. When logical decoding is unavailable, Gold Lapel falls back to NOTIFY-based write detection automatically. This mode installs lightweight triggers on tracked tables that send a PostgreSQL NOTIFY event on each write. It catches the vast majority of external writes without any server configuration changes.
The NOTIFY fallback works well for most deployments. Logical decoding provides broader coverage — it catches writes from sources that bypass triggers (such as COPY commands, logical replication subscribers, or bulk operations with triggers disabled). If your write sources are primarily your application and standard migrations, the NOTIFY fallback is likely sufficient.
For a complete comparison of both detection modes, their trade-offs, and guidance on which to choose, see Write Detection.
Permissions
Gold Lapel creates database objects on your behalf — materialized views, indexes, a metadata schema, and optionally extensions. The database user it connects as needs sufficient privileges to perform this work.
What Gold Lapel creates
_goldlapelschema — all Gold Lapel objects live in a dedicated schema, cleanly separated from your application's tables- Materialized views — pre-computed query results in
_goldlapel.mv_<hash> - Indexes — targeted indexes on both base tables and matviews in
_goldlapel.idx_<hash> - Metadata tables —
_goldlapel.metaand_goldlapel.index_metafor tracking what was created and why - Extensions —
CREATE EXTENSIONfor pg_trgm, pg_stat_statements, and pg_ivm if not already present
Recommended privileges
The simplest and most reliable approach: make the Gold Lapel user the owner of the target database. This grants all necessary privileges without fine-grained permission management:
-- Option A: Make the GL user the database owner (recommended)
ALTER DATABASE mydb OWNER TO goldlapel;
-- Option B: Grant specific privileges
GRANT CREATE ON DATABASE mydb TO goldlapel;
GRANT CREATE ON SCHEMA public TO goldlapel; If database ownership is not possible, the minimum privileges Gold Lapel needs are:
CREATEon the database — to create the_goldlapelschemaCREATEon thepublicschema — to create indexes on your tablesSELECTon application tables — to read data for matview creation and shadow verificationCREATE EXTENSIONprivilege — to install extensions if not already present (optional; you can install them manually)
Gold Lapel never modifies your application tables or data. It reads from them to build materialized views and creates its own objects in a separate schema. The goldlapel clean command removes everything Gold Lapel created, leaving your database exactly as it was.
Checking current privileges
Connect as the user Gold Lapel will use and run:
-- Check current user's privileges on the database
SELECT has_database_privilege(current_user, current_database(), 'CREATE');
-- Check schema creation privilege
SELECT has_schema_privilege(current_user, 'public', 'CREATE');
-- Check if the user owns the database (ideal)
SELECT d.datname, pg_catalog.pg_get_userbyid(d.datdba) AS owner
FROM pg_catalog.pg_database d
WHERE d.datname = current_database(); If any of these return f (false), you will need to grant the corresponding privilege before Gold Lapel can fully optimize. Gold Lapel still starts and proxies queries without these privileges — it simply cannot create the database objects that power its optimizations.
Provider-Specific Notes
Managed PostgreSQL providers each have their own mechanisms for configuring extensions, server parameters, and WAL settings. The essentials are the same everywhere — the details of how to apply them differ.
AWS RDS / Aurora
RDS manages PostgreSQL configuration through parameter groups. You cannot edit postgresql.conf directly — instead, you modify the parameter group attached to your instance.
-- In your RDS parameter group:
shared_preload_libraries = 'pg_stat_statements'
rds.logical_replication = 1
-- Then reboot the RDS instance for changes to take effect.
-- After reboot, connect and create the extensions:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
CREATE EXTENSION IF NOT EXISTS pg_trgm; Extensions: pg_stat_statements and pg_trgm are available on all RDS PostgreSQL versions. pg_ivm is not available on RDS at this time.
shared_preload_libraries: Set in your custom parameter group. The default parameter group is read-only — create a custom one if you have not already. After changing this value, reboot the instance.
wal_level: Set rds.logical_replication = 1 in the parameter group. This sets wal_level = logical and enables the required replication slots. Requires a reboot.
Permissions: The master user has sufficient privileges. If using a separate Gold Lapel user, grant it rds_superuser role or specific CREATE privileges on the target database.
Supabase
Supabase provides a web dashboard for managing extensions and has several configuration defaults that work in Gold Lapel's favor.
-- Extensions dashboard: Database → Extensions
-- Or via SQL:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
CREATE EXTENSION IF NOT EXISTS pg_trgm; Extensions: pg_stat_statements and pg_trgm are available via the Extensions dashboard or SQL. pg_ivm is not currently available on Supabase.
wal_level: Already set to logical by default on Supabase. No action needed — Gold Lapel's logical decoding works out of the box.
Permissions: The postgres role has sufficient privileges. If creating a dedicated Gold Lapel user, grant it the privileges described above.
Connection pooling: Supabase uses Supavisor for connection pooling. Gold Lapel auto-detects Supavisor by hostname and disables its own pool to avoid stacking poolers. Use the direct connection string (port 5432), not the pooled connection string (port 6543), for Gold Lapel's upstream.
Neon
Neon's serverless PostgreSQL has a few considerations around connection limits and auto-suspend that are worth knowing about.
-- Extensions available via SQL:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
CREATE EXTENSION IF NOT EXISTS pg_trgm; Extensions: pg_stat_statements and pg_trgm are available. pg_ivm is not currently available on Neon.
wal_level: Set to logical by default on Neon. No action needed.
Auto-suspend: Gold Lapel auto-detects Neon and manages its management connection to allow your compute to scale to zero when idle. No special configuration required.
Connection limits: Neon's connection limits vary by plan — Free (20), Launch (100), Scale (500+). Gold Lapel uses one management connection plus one connection per pool slot. If you are on the Free plan, consider setting --pool-size to a conservative value.
Connection pooling: Neon provides built-in connection pooling. Gold Lapel auto-detects it and adjusts accordingly. Use the direct endpoint for the upstream connection.
Heroku Postgres
Heroku's extension availability depends on your plan tier.
-- Standard and Premium plans:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
CREATE EXTENSION IF NOT EXISTS pg_trgm; Extensions: pg_stat_statements is available on Standard and Premium plans (not Essential). pg_trgm is available on all plans. pg_ivm is not available on Heroku.
shared_preload_libraries: Managed by Heroku — pg_stat_statements is pre-loaded on Standard and Premium plans. You only need to run CREATE EXTENSION.
wal_level: Standard and Premium plans support logical replication. Essential plans do not. Check with SHOW wal_level; to confirm your plan's setting.
Permissions: The default database credential has sufficient privileges for Gold Lapel's needs.
Google Cloud SQL
Cloud SQL uses database flags for server configuration, accessible via the Cloud Console, gcloud CLI, or Terraform.
-- In Cloud SQL flags:
-- cloudsql.enable_pg_stat_statements = on
-- Then:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
CREATE EXTENSION IF NOT EXISTS pg_trgm; Extensions: pg_stat_statements and pg_trgm are available. Enable pg_stat_statements via the cloudsql.enable_pg_stat_statements flag. pg_ivm is not currently available on Cloud SQL.
wal_level: Set the cloudsql.logical_decoding flag to on in your instance's database flags. This enables wal_level = logical. Requires an instance restart.
Permissions: The default postgres user has sufficient privileges. Cloud SQL does not grant true superuser access, but the cloudsql.pg_admin role provides everything Gold Lapel needs.
Verification Checklist
Once you have made your changes — or if you simply want to confirm the current state of your database — this single block checks everything. Connect as the user Gold Lapel will use and run:
-- 1. Check installed extensions
SELECT extname, extversion
FROM pg_extension
WHERE extname IN ('pg_trgm', 'pg_ivm', 'pg_stat_statements');
-- 2. Check WAL level
SHOW wal_level;
-- 3. Check CREATE privilege on the database
SELECT has_database_privilege(current_user, current_database(), 'CREATE');
-- 4. Check if shared_preload_libraries includes what you need
SHOW shared_preload_libraries;
-- 5. Confirm the _goldlapel schema can be created
SELECT has_schema_privilege(current_user, 'public', 'CREATE'); On a fully configured database, the results will look like this:
-- Extensions
extname | extversion
--------------------+-----------
pg_stat_statements | 1.10
pg_trgm | 1.6
pg_ivm | 1.9
-- WAL level
wal_level
-----------
logical
-- CREATE privilege
has_database_privilege
------------------------
t
-- Shared preload libraries
shared_preload_libraries
--------------------------
pg_stat_statements, pg_ivm
-- Schema privilege
has_schema_privilege
----------------------
t Not everything needs to show t or be present for Gold Lapel to work. Here is what each result means:
- Extensions present — Gold Lapel uses whatever is available. Missing extensions mean specific features are disabled, not that Gold Lapel cannot run. See Postgres Extensions for what each one enables.
- wal_level = logical — enables WAL-based write detection. If
replicaorminimal, Gold Lapel falls back to NOTIFY triggers automatically. See Write Detection for the full comparison. - CREATE privilege = t — required for Gold Lapel to create its schema, matviews, and indexes. If
f, Gold Lapel still proxies and observes queries but cannot create optimization objects. - shared_preload_libraries — confirms that extensions requiring preload (pg_stat_statements, pg_ivm) are loaded. If an extension is not listed here,
CREATE EXTENSIONwill fail for it. - Schema privilege = t — confirms Gold Lapel can create indexes on tables in the public schema.
Gold Lapel also runs these checks itself at startup and logs the results clearly — what is available, what is missing, and what to do about it. If you prefer to let Gold Lapel tell you what it needs, simply start it and read the logs.