The essentials
Quick reference
One focused task per row. Jump to the related section for complete, working examples.
| Use | Syntax | Examples |
|---|---|---|
| Inventory available collations | SELECT collname,
collprovider,
collisdeterministic,
collversion
FROM pg_collation
ORDER BY collname; | View examples |
| Decode provider metadata | SELECT collname,
CASE collprovider WHEN 'b' THEN 'builtin' WHEN 'c' THEN 'libc' WHEN 'i' THEN 'icu' END
FROM pg_collation; | View examples |
| Create a deterministic ICU collation | CREATE COLLATION app.en_sort (provider = icu, locale = 'en-US'); | View examples |
| Create a builtin collation alias | CREATE COLLATION app.unicode_fast (provider = builtin, locale = 'PG_UNICODE_FAST'); | View examples |
| Copy a known collation | CREATE COLLATION app.bytewise FROM pg_catalog."C"; | View examples |
| Create case-insensitive comparison | CREATE COLLATION app.case_insensitive (provider = icu, locale = 'und-u-ks-level2', deterministic = false); | View examples |
| Ignore accent differences | CREATE COLLATION app.base_letter (provider = icu, locale = 'und-u-ks-level1-kc-true', deterministic = false); | View examples |
| Set a column collation | display_name text COLLATE app.en_sort NOT NULL | View examples |
| Override one expression | SELECT display_name
FROM app.people
ORDER BY display_name COLLATE app.en_sort; | View examples |
| Resolve mixed-collation input | SELECT left_text COLLATE app.en_sort < right_text COLLATE app.en_sort
FROM app.comparisons; | View examples |
| Enforce insensitive uniqueness | CREATE UNIQUE INDEX users_name_ci_key
ON app.users (name COLLATE app.case_insensitive); | View examples |
| Index a specific sort order | CREATE INDEX people_name_en_idx
ON app.people (display_name COLLATE app.en_sort); | View examples |
| Detect collation version drift | SELECT collname
FROM pg_collation
WHERE collversion IS DISTINCT
FROM pg_collation_actual_version(oid); | View examples |
| Rebuild collation-dependent indexes | REINDEX INDEX CONCURRENTLY app.people_name_en_idx; | View examples |
| Record the current provider version | ALTER COLLATION app.en_sort REFRESH VERSION; | View examples |
| Delegate collation creation | GRANT USAGE, CREATE ON SCHEMA app TO locale_admin; | View examples |
A PostgreSQL collation determines how collatable text is ordered and, for nondeterministic ICU collations, which byte-distinct strings compare as equal. Treat that behavior as part of the data model: choose a provider deliberately, bind important expressions and indexes to schema-qualified collations, and rehearse provider upgrades because changed sort rules can invalidate stored index ordering.
Step by step
Detailed examples
Choose a provider whose stability matches the contract
PostgreSQL 18 exposes builtin, ICU, and libc providers. ICU offers BCP 47 language tags and rich Unicode tailoring but requires an ICU-enabled build; libc names and behavior are operating-system dependent. The builtin provider accepts C, C.UTF-8, or PG_UNICODE_FAST, with PG_UNICODE_FAST new in PostgreSQL 18, available only for UTF8 databases, and stable within a PostgreSQL major version. Inspect the actual server rather than assuming a locale name exists on every deployment.
SELECT n.nspname AS schema_name, c.collname,
CASE c.collprovider
WHEN 'b' THEN 'builtin'
WHEN 'c' THEN 'libc'
WHEN 'i' THEN 'icu'
WHEN 'd' THEN 'database default'
END AS provider,
c.collisdeterministic, c.collencoding, c.collversion
FROM pg_collation AS c
JOIN pg_namespace AS n ON n.oid = c.collnamespace
ORDER BY n.nspname, c.collname; Create stable, schema-qualified application names
A collation is a schema object and CREATE COLLATION requires CREATE on the destination schema. Put user-defined collations in an application-owned schema so pg_dump preserves them, and schema-qualify use sites to avoid search_path ambiguity. IF NOT EXISTS proves only that a name exists, not that its provider, locale, rules, or determinism match. CREATE COLLATION is transactional, but it takes a self-conflicting SHARE ROW EXCLUSIVE lock on pg_collation, so serialize migration batches that create collations.
BEGIN;
CREATE SCHEMA IF NOT EXISTS app AUTHORIZATION app_owner;
CREATE COLLATION app.en_sort (
provider = icu,
locale = 'en-US'
);
CREATE COLLATION app.unicode_fast (
provider = builtin,
locale = 'PG_UNICODE_FAST'
);
COMMIT; Use nondeterministic ICU collations only for intentional equivalence
Setting deterministic = false stops PostgreSQL from breaking provider-equal strings with a bytewise tie-breaker. With a suitable ICU tag this supports case-insensitive, accent-insensitive, or normalization-aware equality without lowercasing stored data. It is supported only by ICU. The performance tradeoffs are real: comparisons cost more, B-tree deduplication is disabled, and some pattern-matching operations or operator/index combinations may be unavailable. Test every operator used by the workload on the target PostgreSQL major and ICU version.
CREATE COLLATION app.case_insensitive (
provider = icu,
locale = 'und-u-ks-level2',
deterministic = false
);
SELECT 'Résumé' COLLATE app.case_insensitive = 'RÉSUMÉ' AS same_casefold,
U&'\0061\0308' COLLATE app.case_insensitive = U&'\00E4' AS same_normalized; Bind comparison semantics at the narrowest useful scope
A column collation becomes the implicit collation of expressions derived from that column. An explicit COLLATE clause overrides implicit rules and is often safer for one report or cross-locale sort. Combining expressions with incompatible implicit collations can leave the result indeterminate and cause an error when an ordering or comparison operator needs a collation. Apply one explicit, schema-qualified collation to resolve that conflict rather than relying on session search_path.
CREATE TABLE app.people (
person_id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
display_name text COLLATE app.en_sort NOT NULL
);
SELECT person_id, display_name
FROM app.people
ORDER BY display_name COLLATE pg_catalog."C", person_id; Make index collation match the query and uniqueness rule
A B-tree index has a collation as part of its definition. The planner can use it for compatible comparisons and ordering, but a query using another collation generally needs another index or a sort. A unique index under a nondeterministic collation enforces the provider's equality relation, so visually or bytewise distinct values may conflict. Foreign-key text columns in PostgreSQL 18 must use deterministic collations or the same nondeterministic collation; confirm cross-version behavior before mixed-major migrations.
CREATE INDEX people_name_en_idx
ON app.people (display_name COLLATE app.en_sort);
CREATE UNIQUE INDEX people_name_ci_key
ON app.people (display_name COLLATE app.case_insensitive);
EXPLAIN (COSTS OFF)
SELECT display_name
FROM app.people
ORDER BY display_name COLLATE app.en_sort; Rebuild dependents before refreshing a changed version
ICU, libc, and some database-default collations record provider versions. An operating-system, ICU, or major-version upgrade can change sort rules while an index still reflects the old order, risking wrong results or apparent corruption. Detect mismatches, identify dependencies, rebuild each affected index or materialized ordering, validate the application, and only then run REFRESH VERSION. REFRESH VERSION changes catalog metadata; it does not inspect or rebuild dependents. REINDEX CONCURRENTLY reduces write blocking but takes longer, uses extra space, and has transaction-block restrictions.
SELECT n.nspname, c.collname, c.collversion AS recorded_version,
pg_collation_actual_version(c.oid) AS actual_version
FROM pg_collation AS c
JOIN pg_namespace AS n ON n.oid = c.collnamespace
WHERE c.collversion IS DISTINCT FROM pg_collation_actual_version(c.oid);
SELECT pg_describe_object(d.refclassid, d.refobjid, d.refobjsubid) AS collation,
pg_describe_object(d.classid, d.objid, d.objsubid) AS dependent_object
FROM pg_depend AS d
JOIN pg_collation AS c ON d.refclassid = 'pg_collation'::regclass AND d.refobjid = c.oid
WHERE c.collversion IS DISTINCT FROM pg_collation_actual_version(c.oid)
ORDER BY 1, 2; -- Run outside a transaction block when using CONCURRENTLY.
REINDEX INDEX CONCURRENTLY app.people_name_en_idx;
-- Refresh only after every dependent object has been rebuilt and checked.
ALTER COLLATION app.en_sort REFRESH VERSION; Treat locale DDL as privileged, versioned infrastructure
Do not let untrusted roles create collations in schemas used by application search paths. Own application collations with a migration role, grant only the required schema privileges, and qualify both the schema and collation name in DDL. Collation objects replicate through logical DDL only if your deployment system applies that DDL; PostgreSQL logical replication does not copy schema changes. Physical standbys inherit catalog and WAL changes, but every server must provide compatible locale libraries. Record server major, provider, locale, rules, and actual version in deployment evidence.
REVOKE CREATE ON SCHEMA app FROM PUBLIC;
GRANT USAGE, CREATE ON SCHEMA app TO locale_admin;
SELECT current_setting('server_version') AS server_version,
n.nspname, c.collname, c.collprovider, c.collisdeterministic,
c.collversion, pg_collation_actual_version(c.oid) AS actual_version
FROM pg_collation AS c
JOIN pg_namespace AS n ON n.oid = c.collnamespace
WHERE n.nspname = 'app'
ORDER BY c.collname; Sources and further reading
References
Authoritative documentation used to verify and expand this cheat sheet.
- PostgreSQL Global Development GroupPostgreSQL 18: Collation Supportpostgresql.org
- PostgreSQL Global Development GroupPostgreSQL 18: CREATE COLLATIONpostgresql.org
- PostgreSQL Global Development GroupPostgreSQL 18: ALTER COLLATIONpostgresql.org
- PostgreSQL Global Development GroupPostgreSQL 18: pg_collationpostgresql.org
- PostgreSQL Global Development GroupPostgreSQL 18: REINDEXpostgresql.org
Help us improve
Found a typo or missing example?
Tell us what would make this cheat sheet clearer, more complete, or more useful.



