SQLCharacter & Text Types

Character & Text Types

Almost every schema stores free-form text somewhere — names, emails, addresses, product descriptions, comments. SQL gives you three main ways to declare a text column, and the difference between them is mostly about whether a maximum length is enforced and how the storage engine pads or trims the value.

CHAR(n) — fixed-length

CHAR(n) always reserves exactly n characters of storage. If the value you insert is shorter than n, the database pads it with trailing spaces up to the declared length; if it's longer, it is rejected (or silently truncated, depending on the dialect and settings).

CHAR pads short values with spaces

SQL
CREATE TABLE country_codes (
    code CHAR(2)   -- always exactly 2 characters, e.g. 'US', 'DE'
);

INSERT INTO country_codes (code) VALUES ('US');
-- Stored internally padded to the declared length in some engines,
-- and comparisons/trailing-space handling vary by dialect.
Warning
The padding behavior of `CHAR` is a common source of subtle bugs: depending on the dialect, trailing spaces may or may not be trimmed when the value is read back, and string concatenation or length checks (`LENGTH(code)`) can return unexpected results if you assumed no padding. Unless every value truly has the same fixed length (like a 2-letter country code or a fixed-format status code), avoid `CHAR`.
VARCHAR(n) — variable-length with a limit

VARCHAR(n) stores only the characters you actually insert (no padding) but enforces a maximum length of n characters. This is the default choice for most text columns — names, emails, titles — where you know a reasonable upper bound but values vary in length.

VARCHAR only stores what you give it

SQL
CREATE TABLE users (
    id    SERIAL PRIMARY KEY,
    email VARCHAR(255) NOT NULL,
    name  VARCHAR(100) NOT NULL
);

INSERT INTO users (email, name) VALUES ('a@example.com', 'Ana');
-- 'Ana' is stored as exactly 3 characters, no padding
TEXT — unbounded text

TEXT stores text of essentially unlimited length (subject to the database's own hard limits, which are typically gigabytes). Use it for content whose length you cannot reasonably bound up front — blog posts, comments, JSON blobs, free-form descriptions.

TEXT for unbounded content

SQL
CREATE TABLE articles (
    id      SERIAL PRIMARY KEY,
    title   VARCHAR(200) NOT NULL,
    body    TEXT NOT NULL   -- could be a few words or tens of thousands
);
Comparing the three

Type

Storage behavior

When to use

CHAR(n)

Fixed length, padded with trailing spaces

Truly fixed-width codes: 2-letter country codes, fixed status codes

VARCHAR(n)

Variable length, stores only what you insert, capped at n

Most text columns with a sensible, enforceable max length

TEXT

Variable length, effectively unbounded

Long-form content where a max length isn't meaningful

PostgreSQL treats unbounded VARCHAR specially
In PostgreSQL, `VARCHAR` written without a length (just `VARCHAR`) is equivalent to `TEXT` — unlimited length, no enforced cap. This is different from MySQL and SQL Server, where `VARCHAR` generally requires an explicit length. Because of this, many PostgreSQL codebases use plain `TEXT` for unbounded fields and reserve `VARCHAR(n)` only for columns where the length limit is intentional and meaningful (like `VARCHAR(2)` for a country code), rather than as a performance optimization — in PostgreSQL, `VARCHAR(n)`, unbounded `VARCHAR`, and `TEXT` all have essentially the same performance characteristics.