Types are hard to change on big tables, and the right ones prevent bugs like rounding errors in money.
PostgreSQL has a rich type system; a few choices cover most columns.
- Text: use
text.varchar(n)is the same type with a length check, andchar(n)pads with spaces — avoid it. If you need a limit, aCHECK (length(x) <= n)is easier to change later. Performance is identical. - Integers:
integer(4 bytes, up to about 2.1 billion) andbigint(8 bytes). Usebigintfor primary keys of tables that may grow large; running out ofintegerids is a classic outage.smallintrarely pays off. - Exact decimals:
numeric(p, s)for money and anything that must add up exactly.realanddouble precisionare binary floating point: fast, approximate, fine for measurements. Avoid themoneytype; it depends on thelc_monetarysetting. - boolean:
true,falseorNULL. - Binary:
bytea. For large files, store them in object storage and keep the path. - Dates and times:
date, andtimestamptz(next lessons).
Also useful: uuid, jsonb, arrays, inet/cidr for IP addresses, and range types — covered later. Use the :: operator (or standard CAST) to convert: '42'::int. pg_typeof(expr) tells you the type of any expression, which is handy when an operator complains it doesn't exist for your types.
Example
CREATE TABLE payment (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
reference text NOT NULL CHECK (length(reference) <= 40),
amount numeric(12, 2) NOT NULL,
refunded boolean NOT NULL DEFAULT false,
client_ip inet
);
INSERT INTO payment (reference, amount, client_ip)
VALUES ('INV-1', 0.10, '203.0.113.7'), ('INV-2', 0.20, NULL);
SELECT sum(amount) FROM payment; -- 0.30 (exact)
SELECT 0.1::float8 + 0.2::float8 = 0.3::float8; -- f (binary floats)
SELECT pg_typeof(amount), pg_typeof('42'::int) FROM payment LIMIT 1;
-- numeric | integerRemember
- text everywhere; add a CHECK if you need a max length
- bigint for ids that may grow; numeric for money
- Floats are approximate; never compare them for exact equality
Watch out for
- Using integer primary keys on a fast-growing table and hitting 2,147,483,647.