Data Types

PostgreSQL's type system goes well beyond the basics — auto-incrementing IDs, arrays as a real column type, and a UUID type are all built in, not bolted on.

SERIAL: auto-incrementing primary keys

SERIAL isn't technically its own type — it's shorthand that creates an INTEGER column backed by a sequence that auto-generates the next value on insert:

SQL storefront=#
CREATE TABLE products (
  id SERIAL PRIMARY KEY,
  name TEXT,
  price NUMERIC(10,2)
);

INSERT INTO products (name, price) VALUES ('Notebook', 4.50), ('Pen', 1.20);
SELECT * FROM products;
Output
 id |   name   | price 
----+----------+-------
  1 | Notebook |  4.50
  2 | Pen      |  1.20
(2 rows)

Neither INSERT mentioned id at all — the underlying sequence handed out 1 and 2 automatically. For a bigger table expecting to outgrow a 32-bit integer's ~2.1 billion ceiling, BIGSERIAL does the same thing backed by a 64-bit BIGINT.

TEXT vs VARCHAR(n)

Unlike most databases, PostgreSQL's TEXT and VARCHAR have no performance difference — VARCHAR(n) only adds a length check, nothing more. Most experienced Postgres users default to plain TEXT and add a CHECK constraint if they genuinely need to cap a length, rather than reaching for VARCHAR(n) out of habit carried over from other databases.

Arrays as a real column type

SQL storefront=#
CREATE TABLE articles (
  id SERIAL PRIMARY KEY,
  title TEXT,
  tags TEXT[]
);

INSERT INTO articles (title, tags) VALUES ('Postgres Basics', ARRAY['sql', 'database', 'postgres']);
SELECT title, tags FROM articles WHERE 'postgres' = ANY(tags);
Output
      title       |          tags           
-------------------+--------------------------
 Postgres Basics   | {sql,database,postgres}
(1 row)

tags TEXT[] stores a whole array of text values in one column. ANY(tags) checks whether a value appears anywhere in that array — here, whether 'postgres' is one of the tags.

UUID

SQL storefront=#
CREATE TABLE sessions (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_email TEXT
);

INSERT INTO sessions (user_email) VALUES ('jamie@example.com');
SELECT * FROM sessions;
Output
                  id                  |     user_email      
---------------------------------------+----------------------
 3f2a91c4-8b1d-4e6a-9c3f-1a2b3c4d5e6f | jamie@example.com
(1 row)
Note: gen_random_uuid() is built into PostgreSQL 13 and later. On older versions it requires CREATE EXTENSION pgcrypto first — extensions are covered in the last lesson of this course. UUIDs are a common choice for primary keys in distributed systems, where generating IDs on multiple servers without coordinating means a simple auto-incrementing integer can't guarantee uniqueness.