12 Text Types
PostgreSQL has three character types: text (unbounded), varchar(n) (variable up to n characters), and char(n) (fixed n characters, space-padded). For almost all use cases, text is the right choice. PostgreSQL’s text and varchar have identical performance characteristics — unlike MySQL, there is no benefit to capping the length unless you want the database to enforce a maximum.
What you’ll learn
- The three text types and when each makes sense
- Why
textis the default in PostgreSQL - Length functions:
length,char_length,octet_length - The basics of collation — how text sorts and compares
- Encoding: PostgreSQL stores text in the database’s encoding (usually UTF-8)
Example
text is the workhorse. It stores strings of any length and is what most application columns should use. Internally, PostgreSQL stores text and varchar the same way — using TOAST (the Oversized Attribute Storage Technique) for large values so the main table stays compact.
varchar(n) is text with a length check. Use it only when you have a real reason to cap length (e.g. integration with a system that requires it). varchar without a length is exactly text.
char(n) is the historical fixed-width type. It pads values with spaces to length n on storage and trims them in some operations — which leads to surprises. Avoid char(n) unless you have a very specific reason (e.g. interfacing with a system that requires fixed-length codes).
Run the example
To run:
Common pitfalls
- Choosing
varchar(255)from habit: it does nothing useful in PostgreSQL. Usetext. If the application needs a length cap, enforce it in the application or with aCHECKconstraint. char(n)padding silently changes your values.'foo'::char(10)is stored as'foo '.- Multibyte characters:
length('café')returns 4 (characters), butoctet_lengthreturns 5 (bytes in UTF-8). Match the function to the question you are asking. - Sorting comparisons depend on the database’s
LC_COLLATE. To get byte-order sorting (often faster, and predictable), useCOLLATE "C".
For case-insensitive text columns, consider the citext extension (CREATE EXTENSION citext) — it lets = and LIKE behave case-insensitively at the column level, so your queries do not have to call LOWER() everywhere.
Compare lengths: SELECT length('x'::text), length('x'::char(3));. Both lengths are 1: length(character) ignores trailing padding. Use octet_length('x'::char(3)) to observe the three stored bytes. Then try SELECT 'foo '::char(6) = 'foo'::char(3); — the answer is true because char comparisons ignore trailing spaces.
Downloads
SQL file: text-types.sql · All lesson files · Setup guide