Developer tools · Database sizing
Postgres table size calculator.
List your columns, enter a row count, and see the bytes per row, rows per page and heap size, padding included.
Inputs
Estimated heap size
Enter the values.
How big is a PostgreSQL table?
PostgreSQL stores a table as 8 kB pages. Each page starts with a 24 byte header, then a 4 byte item identifier per row. Each row has a 23 byte header, rounded up to a multiple of 8 (more if there is a null bitmap), followed by the column data. Each column starts at a multiple of its own alignment (a bigint at a multiple of 8, an integer at 4, a smallint at 2), so ordering wide fixed-size columns first removes padding. A text value of up to 126 bytes costs 1 byte of overhead; longer values cost 4.
Worked example. A bigint, a timestamptz and a text value averaging 20 bytes: data is 8 + 8 + 21 = 37 bytes, the header is 24, so the tuple is 61 bytes, which rounds to 64 plus a 4 byte line pointer = 68 bytes per row. That fits 120 rows per page, so 1,000,000 rows need 8,334 pages, about 65.1 MiB.
This models the main heap only. It ignores TOAST (large values moved out of line), dead rows from updates and deletes, free space map and visibility map files, and indexes. Run SELECT pg_relation_size('your_table') on real data to compare.
Frequently asked questions
How do I estimate the size of a Postgres table?
Add the 23 byte row header (rounded to 8), the column data with each column aligned to its type, and a 4 byte line pointer; divide the 8 kB page by that to get rows per page, then multiply pages by 8 kB. This calculator does that from your column list.
Does column order change PostgreSQL row size?
Yes. Each column is aligned to a multiple of its type alignment, so a smallint before a bigint wastes 6 bytes of padding. Put 8 byte columns first, then 4 byte, then smaller ones, and variable-length columns last.
Why is my real table bigger than the estimate?
The estimate covers the heap only. Real tables also hold dead rows until vacuum, TOASTed values, and bloat from updates, and the fillfactor leaves space on each page. Check pg_relation_size and pg_total_relation_size.
How many bytes is a uuid or timestamptz in Postgres?
A uuid is 16 bytes with no alignment requirement, a timestamptz is 8 bytes aligned to 8, a bigint is 8, an integer is 4 and a date is 4.
Sources
Checked
- PostgreSQL docs: Database Page Layout
- PostgreSQL docs: Numeric Types
- PostgreSQL docs: Date/Time Types
- PostgreSQL docs: Character Types
- PostgreSQL source: pg_type.dat (uuid and int8 length and alignment)
- PostgreSQL docs: pg_type (typalign)
- PostgreSQL docs: CREATE TABLE (fillfactor)
Page, header and type sizes are from the PostgreSQL documentation and source, for a default 64-bit build with 8 kB pages. The text length is your average, not measured. Runs entirely in your browser. Nothing you type is sent or stored.
Scope
Planning estimates, not guarantees. Real systems add overhead this model leaves out and behave differently under load. Measure on your own data and load-test before committing to a design or a bill.