Find PostgreSQL Headers and Build Flags with pg_config
pg_config tells you exactly which PostgreSQL headers, libraries and compiler flags a build should use, instead of you guessing a distribution path. Reach for it the moment a C extension, native client or build system says it cannot find PostgreSQL, or when you need to check which installation a build is actually using.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about ten minutes. You need a shell and the libpq-dev package, or an equivalent PostgreSQL development package. The commands below only read installation metadata: no service starts, stops, reconfigures or needs elevated privileges.
1. Confirm which pg_config you are running
Start with the executable path, package version and PostgreSQL version. This catches the common mistake of asking one installation for metadata while compiling against another.
$ command -v pg_config
/usr/bin/pg_config
$ dpkg-query -W -f='${Package} ${Version}\n' libpq-dev
libpq-dev 16.15-0ubuntu0.24.04.1
$ pg_config --version
PostgreSQL 16.15 (Ubuntu 16.15-0ubuntu0.24.04.1)
The exact package revision will vary. What matters is that the command is the one you intended, and its reported PostgreSQL major version matches the headers and libraries you plan to use.
Checkpoint
If command -v reports an unexpected path, fix your PATH or use the absolute path to the intended pg_config before continuing. Do not solve an ambiguous path by copying headers between installations.
2. Read one value at a time
Each option prints one path or value. The most useful locations for ordinary client development and extension builds:
$ pg_config --bindir --includedir --includedir-server --libdir --pgxs
/usr/lib/postgresql/16/bin
/usr/include/postgresql
/usr/include/postgresql/16/server
/usr/lib/x86_64-linux-gnu
/usr/lib/postgresql/16/lib/pgxs/src/makefiles/pgxs.mk
- Multiple options print in the order supplied, one item per line, with no labels. Keep the option list short or assign each result separately in a script.
--includediris for client interface headers.--includedir-serveris for server programming, and is not automatically the right include path for a libpq client.--bindirnormally holds PostgreSQL user executables such aspsql.--libdiridentifies object-code libraries.--pgxsidentifies the makefile used by the PostgreSQL extension build system.
3. Use the paths in a build without guessing
For a small C client, ask pg_config for the include and library directories instead of hard-coding a distribution-specific path. This compiles client.c into client:
cc \\
-I"$(pg_config --includedir)" \\
client.c \\
-L"$(pg_config --libdir)" -lpq \\
-o client
This assumes client.c is your source file and that the compiler can find the library's runtime dependencies. It does not create a database connection by itself. If the link step reports that -lpq cannot be found, inspect --libdir, confirm the development package is installed, and check the compiler is targeting the same architecture as the installed libraries.
For an extension built with PGXS, use the makefile path directly:
$ make -f "$(pg_config --pgxs)"
Run that from the extension source directory and follow its own build instructions. A successful build does not mean installation is complete.
Warning
Installing into a system PostgreSQL directory changes state and may need elevated privileges, so review the destination before running any make install target. Back up or record the previous version if you need a rollback.
4. Inspect all labelled values when the installation is unclear
With no option, pg_config prints every known item with a label, which is easier to audit than a long positional command:
$ pg_config
BINDIR = /usr/lib/postgresql/16/bin
DOCDIR = /usr/share/doc/postgresql-doc-16
HTMLDIR = /usr/share/doc/postgresql-doc-16
INCLUDEDIR = /usr/include/postgresql
PKGINCLUDEDIR = /usr/include/postgresql
INCLUDEDIR-SERVER = /usr/include/postgresql/16/server
LIBDIR = /usr/lib/x86_64-linux-gnu
PKGLIBDIR = /usr/lib/postgresql/16/lib
LOCALEDIR = /usr/share/locale
MANDIR = /usr/share/postgresql/16/man
SHAREDIR = /usr/share/postgresql/16
SYSCONFDIR = /etc/postgresql-common
PGXS = /usr/lib/postgresql/16/lib/pgxs/src/makefiles/pgxs.mk
The full output continues with build configuration and compiler variables. Paths are installation facts, not a promise that every file exists or that every binary on your PATH belongs to this installation. Check a specific path with test when a build depends on it:
includedir=$(pg_config --includedir)
libdir=$(pg_config --libdir)
test -d "$includedir" && test -d "$libdir" && printf '%s\n' 'PostgreSQL client paths exist'
5. Capture compiler and linker settings carefully
The build metadata options describe how this PostgreSQL package was built, which helps when comparing installations or diagnosing a native build:
$ pg_config --cc --cppflags --cflags --ldflags --libs
gcc
-Wdate-time -D_FORTIFY_SOURCE=3 -D_GNU_SOURCE -I/usr/include/libxml2
-Wall -Wmissing-prototypes ...
-Wl,-Bsymbolic-functions ...
-lpgcommon -lpgport ... -lpq ...
The long lines are shortened above because flags are host-specific. Do not paste these values blindly into a different compiler command: --cppflags, --cflags, --ldflags and --libs come from the PostgreSQL build, not a universal replacement for the flags your own project documents. The output can contain paths, optimisation choices and libraries appropriate to this package's build but not to your application.
Use --configure to inspect the options passed to PostgreSQL's configure step:
$ pg_config --configure
'--build=x86_64-linux-gnu' '--prefix=/usr' ... '--with-openssl' ...
Package builds can carry distribution patches or packaging choices, so this output is evidence about the build, not a recipe that guarantees an identical rebuild. It can also contain shell quoting: treat it as diagnostic data, not as an unreviewed command to execute.
6. Separate pg_config problems from compiler problems
If the command is missing, install the development package for your distribution. If it exists but a build fails, run the relevant option by itself and inspect the result:
$ pg_config --includedir
/usr/include/postgresql
$ test -f "$(pg_config --includedir)/libpq-fe.h" && printf '%s\n' 'libpq header found'
libpq header found
$ test -f "$(pg_config --pgxs)" && printf '%s\n' 'PGXS makefile found'
PGXS makefile found
- A missing header usually points to an absent or mismatched development package.
- A missing library can point to the library directory, architecture or linker configuration.
- A failed database connection is a separate runtime problem:
pg_configdoes not test server availability, credentials, sockets or network access.
Do not use sudo for these read-only checks. Reserve elevated privileges for a separately reviewed installation step, and know which PostgreSQL version and destination that step will modify.
Done means
- Installation confirmed.
command -v pg_configandpg_config --versionidentify the intended installation. - Paths obtained, not guessed. Client headers via
--includedir, libraries via--libdir, PGXS via--pgxs. - Build uses discovered paths rather than a guessed distribution layout.
- Output format understood: no-option output is labelled, multiple options are unlabelled and in order.
- Compiler flags and
--configuretreated as diagnostic metadata, not blindly executable instructions. - Nothing changed. No service, database, persistent configuration or package state was touched.