default_text_search_config names the text search configuration that PostgreSQL’s full-text-search functions use when you don’t hand them one explicitly. The default is set by initdb from the cluster’s locale; the context is user. A text search configuration bundles a parser (which breaks text into tokens) with a chain of dictionaries (which fold tokens into lexemes — stemming “running” to “run”, dropping stopwords like “the”), and every to_tsvector and to_tsquery call needs one to do its work. This parameter is the one they reach for when the call omits it.

That sounds like convenience, and it mostly is, but it sits on top of one of the more elegant constraints in PostgreSQL, and the constraint is the post.

Why you can’t index with the default

to_tsvector comes in two forms. The two-argument to_tsvector('english', body) names its configuration and is therefore immutable — same inputs, same output, forever. The one-argument to_tsvector(body) reads default_text_search_config, which is a GUC a session can change, so it is only stable: its result can vary as that setting varies. That distinction has teeth, because expression indexes require immutable expressions. An index records lexemes computed once, at insert time; if the function that computed them could produce different lexemes later because someone changed a GUC, the index would silently disagree with reality. So PostgreSQL forbids it. Try to build a GIN index over to_tsvector(body) and you get an error about functions needing to be immutable, and the only fix is to name the configuration:

1CREATE INDEX docs_fts ON docs USING gin (to_tsvector('english', body));

The docs state the principle directly: only text search functions that specify a configuration name can be used in expression indexes, because the index contents must be unaffected by default_text_search_config. This is not a limitation so much as the system refusing to let you build an index whose meaning depends on a mutable setting. The mutability of this parameter is exactly why the functions that read it are stable rather than immutable, and that stability is exactly why you must be explicit when indexing. The whole thing is consistent; it just surprises people at CREATE INDEX time.

The trap that follows

Because you hardcoded 'english' in the index, you’ve now created a second obligation: your queries must use the same configuration, or they won’t match the index — and worse, won’t match the data, because a tsquery built under one configuration produces different lexemes than a tsvector built under another. Index the stemmed-English lexeme run, search with the simple configuration that doesn’t stem, and your query for running looks for running, which isn’t in the index, and you get zero rows and no error. Searches that silently return nothing are the signature failure of full-text search, and a configuration mismatch between index and query is the usual cause.

There are two clean ways out. Be explicit everywhere — name 'english' in both the index expression and every query — which is verbose but impossible to get wrong. Or use a generated column, which is the approach the docs themselves now steer you toward:

1ALTER TABLE docs ADD COLUMN body_fts tsvector
2 GENERATED ALWAYS AS (to_tsvector('english', body)) STORED;
3CREATE INDEX docs_fts ON docs USING gin (body_fts);

The configuration is pinned once, in the column definition; the index covers the column; and queries can use the bare default-config functions against that column and still match, because the matching happens on stored lexemes rather than on a recomputation that would have to agree about configuration. It’s the rare case where leaning on default_text_search_config in your queries is actually safe.

What to set it to

initdb derives it from lc_ctype through a lookup table — an English locale yields pg_catalog.english, German yields german, and so on. The trap is the fallback: a locale the table doesn’t recognize lands you on pg_catalog.simple, which lowercases and tokenizes but does no stemming and drops no stopwords, so a cluster initialized under an unusual locale can do full-text search that quietly never matches running to run. If your searches feel oddly literal, SHOW default_text_search_config is the first thing to check.

Set it, per-database or per-role, to whatever language your content is actually in and your indexes actually use — that alignment is the entire point. But understand that setting it well buys you correct behavior only for the unindexed, ad-hoc, default-config path and for the generated-column pattern above. The moment you build a real full-text index, the configuration lives in the index expression, this parameter steps aside, and your only remaining job is to make sure your queries name the same one.