A parameter most operators have never knowingly used, even though every PostgreSQL dump file they have ever inspected sets it. check_function_bodies controls whether PostgreSQL validates the body of a CREATE FUNCTION or CREATE PROCEDURE at creation time. Default on. Context is user.
What validation actually means
When you CREATE FUNCTION foo() ... AS $$ ... $$ LANGUAGE plpgsql, PostgreSQL hands the body string to the language’s validator function. The PL/pgSQL validator parses the body, checks the syntax, resolves the names of referenced tables and functions, and verifies the types of column references. The function is not executed — there’s no way to do that without actually calling it — but its surface structure is checked. Errors get raised immediately rather than discovered the first time someone calls the function in production.
This is, generally, a good thing. PL/pgSQL’s late binding already makes plenty of mistakes survive until runtime; catching the cheap ones at creation time is a small but real win.
The mechanism extends to any procedural language with a validator: PL/pgSQL, PL/Python, PL/Perl, PL/Tcl, and most third-party PLs. LANGUAGE sql functions get a different (and stricter) parse-time check that this GUC does not govern. SQL functions are always parsed and bound at creation time, regardless.
Why turn it off
Two reasons, both legitimate:
Restoring from a dump. This is where you’ve seen the parameter. The first thing in any pg_dump-produced SQL file is a block of SET statements:
1 SET statement_timeout = 0;
2 SET client_encoding = 'UTF8';
3 SET standard_conforming_strings = on;
4 SET check_function_bodies = false;
5 SET client_min_messages = warning;
6 ...
The reason is dependency ordering. A dump file restores objects in topological order, but functions can reference other functions, tables, and types in ways that don’t reduce to a clean dependency graph — forward references, circular references, references to objects in other schemas being loaded in the same transaction. With check_function_bodies = on, a function that references an as-yet-unrestored table would fail to load. With it off, the function body is stored as a string and validated lazily when it’s first called. By that point everything is in place.
Loading functions written by other users. The docs flag this explicitly as a security consideration: the validation process can be tricked into executing code chosen by the function’s author. The validator runs with the privileges of the role doing the CREATE FUNCTION, not the author, so a function with a maliciously-crafted body could exploit the validator to run code in the loading role’s context. Setting check_function_bodies = off before loading untrusted function definitions sidesteps the issue — the body is stored verbatim and only parsed when called, at which point it runs as whatever role invoked it.
This is the same reason pg_dump sets the parameter: dump files are sometimes restored by a different role than the one that created the objects, and you don’t want a malicious dump to do anything during restore that wouldn’t happen during normal operation.
Tuning
You don’t tune this in postgresql.conf. Two scopes that matter in practice:
- Per-session, when you’re loading a SQL file with forward references and getting tired of
ERROR: relation "x" does not exist.SET check_function_bodies = false;at the top of your script and proceed. - Per-role, for an account that exists specifically to bulk-load functions from external sources.
ALTER ROLE loader SET check_function_bodies = false;makes the setting durable for that role’s sessions without affecting anyone else.
Setting it globally to off is rarely the right move. The default exists for good reason: most function definitions benefit from immediate validation, and disabling it cluster-wide trades that benefit away in exchange for handling an edge case that almost always wants per-session scope anyway.
Recommendation: Leave at on globally. Set it per-session when loading scripts that have forward references. Trust that pg_dump will handle the restore case for you. The next time you see SET check_function_bodies = false at the top of a dump file, you now know exactly why it’s there — both reasons.