PostgreSQL provides a powerful configuration system called GUC (Grand Unified Configuration). It is the internal framework that manages all runtime parameters such as shared_buffers, work_mem, log_statement, and many others. If you are working with the PostgreSQL source code, learning how to add your own custom configuration parameter is an excellent way to understand the internals of the database engine.
Why Learn Custom Configuration Parameters
Adding a custom parameter helps you understand:
- How PostgreSQL stores runtime settings
- How parameters are generated from metadata
- How GUC contexts work
- How PostgreSQL integrates source code variables with SQL-visible settings
- How to extend PostgreSQL for custom features
This is useful for contributors, database engineers, and developers building customized PostgreSQL distributions.
Add the Parameter in guc_parameters.dat
In PostgreSQL 19, configuration parameters are defined in a metadata file instead of being manually written into source arrays. This file is:
src/backend/utils/misc/guc_parameters.dat
Add the following entry:
{ name => 'custom_log_enabled', type => 'bool', context => 'PGC_USERSET', group => 'CUSTOM_OPTIONS',
short_desc => 'A custom postgres configuration parameter for learning the way of implementing it in latest postgres source code',
flags => '0',
variable => 'custom_log_enabled',
boot_val => 'false',
},Understanding Each Field
name => 'custom_log_enabled'
This is the SQL-visible parameter name.
You will use it like this:
SHOW custom_log_enabled;
SET custom_log_enabled = on;
type => 'bool'
This defines the data type.
Since we are using a boolean type, PostgreSQL accepts:
on / off
true / false
1 / 0
yes / no
context => 'PGC_USERSET'
This defines who can change the parameter and when it can be changed.
PostgreSQL supports multiple parameter contexts:
typedef enum
{
PGC_INTERNAL,
PGC_POSTMASTER,
PGC_SIGHUP,
PGC_SU_BACKEND,
PGC_BACKEND,
PGC_SUSET,
PGC_USERSET,
} GucContext;
Meaning of Important Contexts
- PGC_INTERNAL: Internal only. Users cannot modify it.
- PGC_POSTMASTER: Requires server restart.
- PGC_SIGHUP: Change in config file + reload.
- PGC_SUSET: Only superusers can change it.
- PGC_USERSET: Any user can change it anytime.
We selected:
PGC_USERSET
So anyone can modify it during a session.
group => 'CUSTOM_OPTIONS'
This decides where the parameter appears in configuration views.
Available groups include categories such as memory, WAL, logging, vacuum, replication, and custom options.
PostgreSQL internally defines groups like:
CUSTOM_OPTIONS
DEVELOPER_OPTIONS
LOGGING_WHAT
WAL_SETTINGS
RESOURCES_MEM
VACUUM_AUTOVACUUM
We used:
CUSTOM_OPTIONS
So it appears under:
Customized Options
In postgres there are nearly 48 categories for the postgres configuration parameters
postgres=# select distinct(category) from pg_settings ;
category
-------------------------------------------------------------------
Connections and Authentication / TCP Settings
Version and Platform Compatibility / Other Platforms and Clients
Vacuuming / Automatic Vacuuming
Query Tuning / Planner Method Configuration
Query Tuning / Other Planner Options
Client Connection Defaults / Statement Behavior
File Locations
Write-Ahead Log / Settings
Client Connection Defaults / Shared Library Preloading
Replication / Subscribers
Client Connection Defaults / Locale and Formatting
Reporting and Logging / What to Log
Write-Ahead Log / Checkpoints
Reporting and Logging / When to Log
Resource Usage / Background Writer
Resource Usage / I/O
Write-Ahead Log / Recovery Target
Error Handling
Resource Usage / Disk
Query Tuning / Genetic Query Optimizer
Preset Options
Statistics / Monitoring
Resource Usage / Time
Resource Usage / Kernel Resources
Statistics / Cumulative Query and Index Statistics
Lock Management
Customized Options
Resource Usage / Memory
Replication / Sending Servers
Version and Platform Compatibility / Previous PostgreSQL Versions
Write-Ahead Log / Archive Recovery
Resource Usage / Worker Processes
Developer Options
Write-Ahead Log / Summarization
Write-Ahead Log / Archiving
Replication / Primary Server
Connections and Authentication / Authentication
Write-Ahead Log / Recovery
Vacuuming / Cost-Based Vacuum Delay
Replication / Standby Servers
Connections and Authentication / SSL
Reporting and Logging / Process Title
Client Connection Defaults / Other Defaults
Query Tuning / Planner Cost Constants
Connections and Authentication / Connection Settings
Vacuuming / Default Behavior
Vacuuming / Freezing
Reporting and Logging / Where to Log
(48 rows)
short_desc
This description is shown in pg_settings.
short_desc => 'A custom postgres configuration parameter for learning the way of implementing it in latest postgres source code'
flags => '0'
Flags modify parameter behavior.
PostgreSQL supports flags such as:
GUC_REPORT
GUC_NO_SHOW_ALL
GUC_SUPERUSER_ONLY
GUC_NOT_IN_SAMPLE
GUC_ALLOW_IN_PARALLEL
Since we do not need any special behavior, we use:
flags => '0'
variable => 'custom_log_enabled'
This links the configuration parameter to a C global variable.
boot_val => 'false'
This is the default value when PostgreSQL starts.
Important Note: Keep Alphabetical Order
When adding a new entry in guc_parameters.dat, place it in the correct alphabetical order.
For example:
custom_log_enabled
must be inserted in the proper sorted location.
If not, PostgreSQL may fail during code generation or compilation.
Create the Header File
Create a new header file:
src/include/utils/custom_logs.h
Add:
#ifndef CUSTOM_LOGS_H
#define CUSTOM_LOGS_H
extern bool custom_log_enabled;
extern void enable_custom_logs(void);
#endif /* CUSTOM_LOGS_H */
Here we use the extern keyword to specify the compiler that this boolean variable and this function is declared somewhere in source code
Purpose of Header Guards
These lines:
#ifndef CUSTOM_LOGS_H
#define CUSTOM_LOGS_H
...
#endif
prevent multiple inclusion of the same header file.
Without header guards, if the file is included more than once, compilation errors such as duplicate declarations can happen.
Header guards ensure the file is processed only once per compilation unit.
Create the Source File
Create:
src/backend/utils/misc/custom_log.c
Add:
#include "postgres.h"
#include "utils/custom_logs.h"
bool custom_log_enabled = false;
void enable_custom_logs(void)
{
if(custom_log_enabled)
{
ereport(LOG,errmsg("Custom logs are enabled."));
}
};
Code Explanation
Global Variable
bool custom_log_enabled = false;
This stores the current value of the parameter.
When PostgreSQL reads:
custom_log_enabled = on
the variable becomes:
true
Logging Function
enable_custom_logs()
This checks whether the parameter is enabled.
If true, PostgreSQL writes:
Custom logs are enabled.
to the server log.
Add the New Source File to the Makefile
Open the Makefile inside:
src/backend/utils/misc/Makefile
Add custom_log.o to the object list:
OBJS = \
conffiles.o \
guc.o \
guc-file.o \
guc_funcs.o \
guc_tables.o \
help_config.o \
injection_point.o \
pg_config.o \
pg_controldata.o \
pg_rusage.o \
ps_status.o \
queryenvironment.o \
rls.o \
sampling.o \
stack_depth.o \
superuser.o \
timeout.o \
tzparser.o \
custom_log.o
This ensures the new file is compiled and linked into PostgreSQL.
Include the Header File
Include the header in:
guc_tables.c
postinit.c
Add:
#include "utils/custom_logs.h"
Call the Function During Startup
Inside postinit.c, locate:
InitPostgres()
At the end of that function, add:
enable_custom_logs();
Now PostgreSQL will check the parameter whenever a backend initializes.
Rebuild PostgreSQL
After source changes:
make clean
make
sudo make install
Then restart the server.
Generated Code in PostgreSQL 19
You do not manually edit guc_tables.c.
PostgreSQL automatically generates internal code from guc_parameters.dat.
Your parameter becomes part of generated structures such as:
struct config_generic ConfigureNames[] =
{
{
.name = "custom_log_enabled",
.context = PGC_USERSET,
.group = CUSTOM_OPTIONS,
.short_desc = gettext_noop("A custom postgres configuration parameter for learning the way of implementing it in latest postgres source code"),
.vartype = PGC_BOOL,
._bool = {
.variable = &custom_log_enabled,
.boot_val = false,
},
},
};
This is one of the major architectural improvements in newer PostgreSQL versions.
Instead of manually maintaining large arrays, metadata now drives code generation.
Verify the Parameter in SQL
Run:
SHOW custom_log_enabled;
Output:
custom_log_enabled
--------------------
off
Query pg_settings:
SELECT * FROM pg_settings WHERE name = 'custom_log_enabled';
Example output:
name | custom_log_enabled
setting | off
category | Customized Options
short_desc | A custom postgres configuration parameter for learning the way of implementing it in latest postgres source code
context | user
vartype | bool
source | default
boot_val | off
reset_val | off
pending_restart | f
This confirms PostgreSQL fully recognizes your custom parameter.
Add it to postgresql.conf
Check config file path:
SHOW config_file;
Example:
/home/cybrosys/cybro_postgres/odoo_data/postgresql.conf
Now, add inside the customized options section:
#------------------------------------------------------------------------------
# CUSTOMIZED OPTIONS
#------------------------------------------------------------------------------
custom_log_enabled = 'on'
# Add settings for extensions here
Restart PostgreSQL
Restart the server:
bin/pg_ctl -D odoo_data/ -l logfile "-o -p 5440" restart
Connect:
bin/psql postgres -p 5440
Check the Log File
tail -f logfile
You should see:
2026-04-19 11:30:33.692 IST LOG: starting PostgreSQL 19devel ...
2026-04-19 11:30:33.705 IST LOG: database system is ready to accept connections
2026-04-19 11:30:52.795 IST LOG: Custom logs are enabled.
That means your custom configuration parameter successfully controlled internal PostgreSQL behavior.
The newer PostgreSQL architecture uses metadata-driven generation for GUC definitions. This reduces manual maintenance and keeps parameter definitions cleaner and more structured.
For developers working on PostgreSQL internals, understanding this design is extremely valuable.
Implementing a custom PostgreSQL configuration parameter is one of the best beginner-friendly ways to explore PostgreSQL source code internals. In PostgreSQL 19, the process is cleaner because parameter metadata is centralized in guc_parameters.dat, and internal code is generated automatically. By creating custom_log_enabled, connecting it to a C variable, and using it in backend startup logic, you built a real server-level feature that behaves like a native PostgreSQL setting. This knowledge creates a strong foundation for advanced customization such as performance tuning options, debugging switches, feature toggles, or entirely new database behaviors.