PostgreSQL Rules Overview
This section reads like a list of arbitrary instructions: use snake_case, run EXPLAIN before merging, set lock_timeout in migrations, never connect the application as superuser.
Each one is really the compressed residue of something that already went wrong once, generalized into an instruction cheap enough to follow without relearning the original incident.
Summary
- Core Idea: A PostgreSQL rule is a specific, previously-learned failure mode, turned into an instruction the next engineer can follow without rediscovering the problem firsthand.
- Why It Matters: Treating every rule as equally arbitrary or equally mandatory misses the real question, which is how much a specific violation actually costs if it happens.
- Key Concepts: rule vs. preference, enforcement tier, checkability, ADR (Architecture Decision Record), rule rot.
- When to Use: Deciding whether a new convention deserves a written rule, choosing how strictly to enforce one, or evaluating whether an old rule still earns its place.
- Limitations / Trade-offs: Rules trade individual judgment for consistency, and a rules document that only grows and is never revisited becomes friction instead of protection.
- Related Topics: naming and style conventions, migration safety, index and query standards, security hardening.
Foundations
Every durable rule in this section starts from the same place: a query took down a table, a migration hung behind a lock, or a schema hit an ambiguity nobody had settled in advance.
The instruction that follows, "run EXPLAIN before merging a new query" or "set lock_timeout in every migration," is cheaper to state and follow than the incident was to live through, which is the entire point of writing rules down at all.
That framing separates a rule from a style preference, even though both can live in the same document and look similarly terse on the page.
A style preference, like singular versus plural table names, has no failure mode behind it at all; nothing breaks either way, so the only cost of inconsistency is readability and search friction across the codebase.
A rule, in the sense this section uses the word, exists because getting it wrong has a real, describable cost, an outage, a security gap, or a multi-hour migration that should have taken seconds.
A useful analogy: a rules document is a codebase's scar tissue made legible, each scar marking a place the team was actually injured, still protecting against a repeat long after the original cut is forgotten.
Mechanics & Interactions
Not every rule deserves the same amount of enforcement force, and matching enforcement to actual cost is most of what separates a useful rules document from a list nobody reads.
Rules in this section sit on a rough spectrum from documented convention, expected in review but not mechanically checked, to code-review-enforced, where a human is expected to catch it, to CI-enforced, where a lint rule or test fails the build automatically.
incident happens
│
▼
lesson written down ── documented convention
│ (pattern recurs, is checkable)
▼
reviewers watch for it ── code-review-enforced
│ (a tool can express it)
▼
mechanical gate blocks it ── CI-enforcedA rule generally starts at the top of that chain, because someone just learned the lesson and wrote it down, and earns its way down toward a CI gate only once the team confirms two things: the pattern genuinely recurs, and it is the kind of thing a mechanical check can detect reliably.
Forcing a judgment-dependent rule straight into a CI gate before it is reliably checkable produces false positives, and false positives teach engineers to route around the gate rather than trust it.
The Postgres Project Rules Checklist is the concrete, tiered version of this idea applied at project scale: its 25 items are grouped by how launch-blocking they are, which is itself an application of "not every rule deserves the same urgency."
Advanced Considerations & Applications
An exception process is what keeps a mechanically-enforced rule from becoming brittle bureaucracy the first time it meets a legitimate edge case it did not anticipate.
Without one, a team either breaks the rule silently, undermining it for everyone who trusted the gate, or blocks a genuinely valid change, undermining trust in the process itself.
The ADR Template for Postgres exists for exactly this situation: an Architecture Decision Record makes a deviation from the default rule visible and deliberate instead of invisible.
Rules also accumulate a specific kind of decay worth naming directly, rule rot, where an instruction keeps being enforced well after the situation that justified it has changed.
A hand-checked index-usage rule written before pg_stat_statements was standard in every environment might no longer earn its keep once automated query review runs on every PR, not because the rule was wrong, but because better tooling now covers the same underlying goal.
Rules that name the specific failure they prevent age better than rules stated as pure instruction, because a team revisiting "why do we do this" can actually judge whether that failure is still a live risk before deciding to keep, relax, or automate the rule further.
| Enforcement tier | Strength | Weakness | Best Fit |
|---|---|---|---|
| Documented convention | Cheap to write; preserves judgment for genuine edge cases | Depends on memory and culture; erodes under deadline pressure | Context-dependent decisions a linter cannot evaluate |
| Code-review-enforced | Catches nuance a mechanical check would miss | Inconsistent across reviewers and available review time | Judgment-heavy rules with high enough stakes to need a second reviewer |
| CI-enforced gate | Applies uniformly to every contributor, every time | Only works for genuinely checkable patterns; false positives erode trust | High-cost, clearly-detectable violations like missing indexes or superuser app roles |
Common Misconceptions
- "This section's rules are just style preferences with extra steps." A style choice like plural table names has no failure mode behind it; a rule like "no superuser application role" exists specifically because violating it has a real, describable cost.
- "Writing a rule down is the same as enforcing it." An unenforced rule holds only as long as every engineer remembers and chooses to follow it, which is precisely the gap enforcement tiers exist to close.
- "Every rule in this section should eventually become a CI gate." Only genuinely checkable patterns belong there; a judgment-dependent rule forced into a mechanical gate produces false positives that teach engineers to distrust the gate.
- "A rule without exceptions is a stronger rule." An absolute rule with no escape hatch just relocates the exception from "visible and deliberate" to "silently violated," which is worse for anyone auditing the schema later.
- "Old rules in this list are always still worth following exactly as written." A rule can outlive the situation that justified it, especially once better tooling supersedes it, which is why periodic review belongs in the same process that created the rule.
FAQs
What's the actual difference between a "rule" and a "style preference" in this section?
A style preference, like singular versus plural table names, has no failure mode behind it; a rule exists specifically because getting it wrong has a real, describable cost such as an outage or a security gap.
Why does this section bother explaining "why" a rule exists instead of just listing the rule?
A rule stated only as required behavior gets followed or silently dropped without anyone able to judge whether it still applies; naming the failure it prevents lets a future engineer actually evaluate that.
How does a convention move from "documented" to "enforced in CI"?
It earns that promotion once the pattern genuinely recurs and a mechanical check can detect it reliably without false positives; rules that still need real judgment stay at code-review enforcement.
Why not just make every important rule a hard CI gate immediately?
Because CI gates only work well for patterns a tool can check reliably, and forcing a judgment-dependent rule into a gate produces false positives that teach engineers to bypass or distrust it.
What's the purpose of an exception process, like an ADR, for a rule?
It gives a legitimate edge case a visible, deliberate path around the default instead of forcing a silent violation or blocking a genuinely valid change outright.
What is "rule rot," and why does it matter for a PostgreSQL rules document?
It is when a rule keeps being enforced after the situation that justified it has changed, such as a manual index-review rule superseded by automated pg_stat_statements monitoring, and it accumulates as friction without a matching benefit.
Should every rule in this section apply with equal urgency to every project?
Not necessarily - the Postgres Project Rules Checklist groups rules by how launch-blocking they are, since a security rule and an operational-maturity rule do not carry equal risk if left unaddressed.
Who decides whether a new convention becomes an official team rule?
In practice, whoever owns the incident or the pattern's recurring cost, but the decision should be documented and visible rather than left in one engineer's memory.
How is a naming convention like snake_case different from a rule like "index before merge"?
Naming is a pure style choice with no failure mode; "index before merge" exists because an unindexed production query has directly caused outages, which is why one belongs to a linter and the other to review.
Does having a large rules document mean an engineering team is more mature?
Only if each rule still names a real, current failure and has enforcement matched to its actual cost; a document that only grows and is never revisited is the bureaucratic version of the same artifact.
Can a rule be relaxed once the tooling that made it necessary improves?
Yes, and it should be revisited rather than left in place indefinitely - a rule that has been superseded by better automated tooling is a candidate for retirement, not permanent enforcement.
Where do security-specific rules fit relative to the rest of this section?
They generally sit at the highest enforcement urgency, since a violated security rule (like a superuser application role) tends to carry outsized, hard-to-reverse cost compared to a style or naming inconsistency.
Related
- Postgres Project Rules Checklist - the concrete, tiered 25-rule audit this model underlies
- Naming & Style Rules - where style preference and rule intersect
- Index & Query Rules - a concrete, high-enforcement rule set
- Migration Safety Rules - lock and statement timeout conventions
- ADR Template for Postgres - how exceptions to a rule get recorded deliberately
Stack versions: This page is conceptual and not tied to a specific stack version.