PostgreSQL Data Types
Every column in a PostgreSQL table must have a data type. A data type tells PostgreSQL what kind of value a column will hold — a number, a piece of text, a date, or something else. Choosing the right data type ensures data is stored efficiently, validated automatically, and queried accurately.
Why Data Types Matter
Imagine storing someone's age as text instead of a number. PostgreSQL would not be able to perform math on it, like calculating an average age. Using the correct data type prevents this kind of problem and also saves storage space by using the most efficient format for each value.
Categories of Data Types
PostgreSQL data types fall into several categories: numeric, character (text), boolean, date and time, and a few special types. Each is covered below.
Numeric Data Types
Numeric types store numbers. The choice depends on whether the number is a whole number or has a decimal, and how large it can get.
Integer Types
| Type | Storage | Range | Use Case |
|---|---|---|---|
SMALLINT | 2 bytes | -32,768 to 32,767 | Small counters, age |
INTEGER or INT | 4 bytes | -2.1 billion to 2.1 billion | General purpose IDs, counts |
BIGINT | 8 bytes | Very large numbers | Large IDs, population data |
Auto-Incrementing Integer Types
| Type | Description |
|---|---|
SERIAL | Auto-incrementing 4-byte integer. Commonly used for primary keys. |
BIGSERIAL | Auto-incrementing 8-byte integer. Used when very large IDs are expected. |
Decimal and Floating-Point Types
| Type | Description | Use Case |
|---|---|---|
NUMERIC(p, s) | Exact decimal. p = total digits, s = decimal places. | Money, precise calculations |
DECIMAL(p, s) | Same as NUMERIC. | Money, financial data |
REAL | 6-digit precision floating-point. | Scientific measurements |
DOUBLE PRECISION | 15-digit precision floating-point. | High-precision scientific data |
For financial data, always use NUMERIC or DECIMAL. Floating-point types can introduce tiny rounding errors that are unacceptable in money calculations.
Character (Text) Data Types
These types store text — letters, symbols, words, and sentences.
| Type | Description | Use Case |
|---|---|---|
CHAR(n) | Fixed-length string. Pads with spaces if shorter than n. | Codes like country codes (IN, US) |
VARCHAR(n) | Variable-length string with a maximum of n characters. | Names, email addresses, titles |
TEXT | Variable-length string with no limit. | Long descriptions, articles, comments |
In PostgreSQL, TEXT and VARCHAR perform identically in terms of speed. Use VARCHAR(n) when a maximum length should be enforced, and TEXT when there is no reasonable limit.
Boolean Data Type
The BOOLEAN type stores one of two values: true or false. It is useful for flags and yes/no fields.
is_active BOOLEANAccepted input values for true: TRUE, 't', 'yes', 'on', 1
Accepted input values for false: FALSE, 'f', 'no', 'off', 0
Date and Time Data Types
PostgreSQL has rich support for storing dates and times.
| Type | Description | Example Value |
|---|---|---|
DATE | Stores a calendar date (year, month, day) | 2024-03-15 |
TIME | Stores time of day without a date | 14:30:00 |
TIMESTAMP | Stores both date and time, no timezone | 2024-03-15 14:30:00 |
TIMESTAMPTZ | Stores date and time with timezone awareness | 2024-03-15 14:30:00+05:30 |
INTERVAL | Stores a duration of time | '3 days', '2 hours 30 minutes' |
For applications that span multiple time zones, use TIMESTAMPTZ. It stores the time in UTC internally and converts to the local timezone when displaying.
UUID Data Type
UUID (Universally Unique Identifier) stores a 128-bit value that is globally unique. It looks like this: a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11. UUIDs are commonly used as primary keys in distributed systems where multiple databases must generate IDs without conflicts.
Array Data Type
PostgreSQL allows a column to store an array (a list) of values of any type. For example, a column that stores multiple phone numbers for a person:
phone_numbers TEXT[]An array value would look like: {'9876543210', '9123456789'}
JSON and JSONB Data Types
PostgreSQL can store JSON (JavaScript Object Notation) data directly in a column.
JSON— stores the raw JSON text exactly as enteredJSONB— stores JSON in a binary format that is faster to query and supports indexing
For most use cases, JSONB is preferred. JSON and JSONB are covered in detail in a later topic.
NULL — The Absence of a Value
NULL is not a data type — it is a special marker meaning "no value" or "unknown." Any column of any type can contain NULL unless restricted by a NOT NULL constraint. NULL is different from zero or an empty string. It literally means the value does not exist.
Example: Choosing Data Types for a Products Table
Consider a table that stores product information:
CREATE TABLE products (
product_id SERIAL,
product_name VARCHAR(100),
description TEXT,
price NUMERIC(10, 2),
in_stock BOOLEAN,
created_on DATE
);Breaking this down:
SERIAL— auto-generates a unique product IDVARCHAR(100)— limits the product name to 100 charactersTEXT— allows an unlimited descriptionNUMERIC(10, 2)— stores prices like 9999999.99 (10 digits, 2 decimal places)BOOLEAN— indicates whether the product is availableDATE— stores the date the product was added
Key Points
- Every column requires a data type that defines what kind of data it stores.
- Use
INTEGERorSERIALfor whole numbers,NUMERICfor exact decimals like money. - Use
VARCHAR(n)for text with a length limit,TEXTfor unlimited text. - Use
TIMESTAMPTZfor timestamps when timezone awareness is needed. NULLmeans a value is absent — it is not the same as zero or empty text.- Choosing the right data type improves storage efficiency, query speed, and data accuracy.
