default_transaction_deferrable sets the default value of the DEFERRABLE transaction attribute for new transactions. The default is off, the context is user, and the attribute it defaults does nothing at all unless two other things are also true — which is what makes this parameter worth a few hundred words rather than a sentence.
When it does nothing, which is usually
DEFERRABLE has no effect unless the transaction is also SERIALIZABLE and READ ONLY. All three together is the only combination where the flag means anything. A deferrable read-write transaction: nothing. A deferrable read-committed read-only transaction: nothing. Since most workloads never run SERIALIZABLE at all — PostgreSQL defaults to READ COMMITTED — this parameter is inert for the large majority of databases, and toggling it changes nothing they will ever notice. To explain what it does in the one case where it matters, we need a paragraph on SSI.
Safe snapshots, briefly
PostgreSQL’s SERIALIZABLE is implemented with Serializable Snapshot Isolation, the Ports-and-Grittner work that landed in 9.1. SSI lets serializable transactions run at nearly snapshot-isolation speed by tracking read/write dependencies between concurrent transactions and aborting one if it detects a “dangerous structure” that could produce an anomaly. The tracking has a cost: serializable transactions take SIREAD locks — predicate locks recording what they read — and those locks must persist until every concurrent transaction finishes, which is precisely why a long-running serializable report is doubly painful. It accumulates enormous numbers of SIREAD locks, and it pins everyone else’s locks in memory until it commits.
The optimization that rescues this is the safe snapshot. The SSI implementation can recognize moments when a read-only transaction’s snapshot is provably safe — when there’s no way it could ever suffer a serialization failure or cause anyone else to suffer one. At that point, as EDB’s writeup puts it, PostgreSQL “effectively silently drops the current transaction from SERIALIZABLE to REPEATABLE READ”: it stops tracking dependencies, takes no SIREAD locks, and runs at plain snapshot-isolation speed with zero abort risk. The result is identical because it’s been proven identical.
What DEFERRABLE actually buys
A deferrable transaction is one that waits for a safe snapshot rather than starting immediately. When a SERIALIZABLE READ ONLY DEFERRABLE transaction begins, PostgreSQL acquires a snapshot but blocks the transaction from running until that snapshot is known safe — which means waiting for the concurrent read-write transactions that could make it unsafe to commit. Once a safe snapshot is in hand, the transaction proceeds with no SSI overhead, takes no predicate locks, can never be canceled by a serialization failure, and can never contribute to canceling anyone else’s. The docs’ summary is exact: the transaction “may block when first acquiring its snapshot, after which it is able to run without the normal overhead of a SERIALIZABLE transaction and without any risk of contributing to or being canceled by a serialization failure.”
That is a genuinely good deal for exactly one kind of work: long-running read-only reports and backups against a serializable OLTP system. Such a transaction is the worst possible SSI citizen — and deferring it converts it into the best one, at the cost of a startup wait that has no fixed upper bound (you wait until the conflicting writers clear, however long that takes).
What to set it to
Leave the global default off. The reason isn’t that deferrable transactions are bad — it’s that the GUC’s scope is almost always wrong. You want deferrable behavior for specific long reports, not for every transaction the session opens, and the natural place to ask for it is per-transaction: BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE READ ONLY DEFERRABLE, or SET TRANSACTION once inside the block. Setting the session or global default to deferrable would impose the safe-snapshot wait on transactions that don’t need it and, because the flag is silently ignored unless they’re also serializable and read-only, would do nothing for most of them anyway.
The one place a non-default value earns its keep is a connection or role dedicated to reporting against a serializable workload — a read-replica analytics login, a backup role — where you genuinely want every transaction to be serializable, read-only, and deferrable. There, ALTER ROLE reporting SET default_transaction_deferrable = on (alongside the isolation and read-only defaults) makes the whole posture ambient for that role and nobody else. Outside that specific shape, this is a per-transaction keyword wearing a GUC’s clothing, and the keyword is where it belongs.