A parameter you cannot change. block_size lives in the “Preset Options” section of the docs, alongside its read-only cousins like data_checksums, wal_block_size, and server_version. It reports the size of a PostgreSQL page — the fundamental unit of on-disk storage and buffer-pool accounting. Default is 8192 bytes. It is read-only at runtime, settable only when PostgreSQL is compiled, and changing it after the fact means starting over with a fresh cluster.

So why is it in pg_settings at all? Because everything in the database is measured in units of it.

What 8KB actually means

shared_buffers = 4GB? That’s 524,288 pages of 8KB each. pg_class.relpages for a 100MB table? 12,800. EXPLAIN’s costs counted in “page accesses”? Same unit. The 1GB-then-TOAST threshold on row width? Derived from block size. The maximum row width before TOAST kicks in (~2KB)? One quarter of a page. The maximum number of B-tree index tuples per page? A function of block size and tuple size. Everything in PostgreSQL is, at some level, an integer count of pages, and the page is 8KB.

This is why the parameter is in pg_settings. Tools, extensions, and operators all need to know what unit they are working in. The parameter exposes the answer.

When you might want to change it

In practice: never. In theory:

  • Larger blocks (16KB, 32KB) mean fewer pages per relation, fewer index levels, better sequential I/O batching, and lower per-page accounting overhead. Some analytics-focused PostgreSQL forks have shipped with 32KB defaults for exactly these reasons. The cost is more wasted space on partially-filled pages, higher TOAST threshold (longer rows stay inline, which sometimes helps and sometimes hurts), and incompatibility with every standard PostgreSQL package, replication setup, and backup tool you might want to use.
  • Smaller blocks (1KB, 2KB, 4KB) are mostly of historical interest. They were useful when disk sectors were small and memory was scarce. Today they offer essentially no benefit and a lot of additional overhead.

The legal values, per --with-blocksize at compile time, are 1, 2, 4, 8, 16, and 32 KB. The default has been 8KB for the entire history of PostgreSQL anyone reading this is likely to remember.

Why almost nobody changes it

Three reasons, in escalating severity:

  1. It is compile-time. Distribution packages (Debian, Red Hat, EDB, RDS, Aurora) ship with 8KB. Changing it means compiling PostgreSQL yourself and giving up package management.
  2. It is incompatible with everything. You cannot upgrade an 8KB cluster to a 32KB cluster in place. You cannot stream replication between clusters with different block sizes. pg_dump/pg_restore works, but that is your only migration path, and your tooling must support it.
  3. Extensions assume 8KB. Many extensions hard-code assumptions about page size, tuple layout, or TOAST behavior. The further you stray from the default, the more interesting your extension compatibility matrix becomes.

Recommendation: Look at the value. Confirm it is 8192. Move on. The block_size parameter exists so that monitoring tools, query planners, and operators can know the unit they are working in — not so that you can change it. If you find yourself genuinely wanting a different value, you are doing something specialized enough that this blog post is not where you should be getting your advice.