Compare

VARCHAR vs TEXT

Short answer: on Postgres, VARCHAR (with no length), VARCHAR(n), and TEXT are all stored identically — performance is the same, the only practical difference is that VARCHAR(n) enforces a maximum length. On MySQL, VARCHAR and TEXT are genuinely different — different storage, different indexing rules, different performance. Other engines fall somewhere in between. The "always use TEXT in Postgres" advice is right for Postgres and wrong for MySQL.

Quick comparison #

VARCHAR(n)VARCHAR (no length)TEXT
Postgresenforced length capunlimited; same as TEXTunlimited
Postgres performanceidenticalidenticalidentical
MySQLup to 65535 bytes; can be indexed fullynot allowed without nup to 4 GB; index requires prefix length
MySQL storageinline in rown/astored off-row by default
SQL ServerVARCHAR(n) up to 8000; VARCHAR(MAX) up to 2 GBn/aTEXT is deprecated — use VARCHAR(MAX)
Snowflake / BigQuery / DuckDBboth are aliases for unbounded stringsamesame
Use whenlength limit matters as a constraintunbounded, per-engine semanticswhen the engine treats it differently (mostly MySQL)

See it in action #

Loading SQL editor...

When to use which #

VARCHAR(n) — when length is part of the data contract. A two-letter country code is VARCHAR(2) because the constraint is meaningful: it documents the allowed shape and rejects bad inputs. Don't use VARCHAR(255) as a generic "shortish string" — 255 has no business meaning, and you'll need to migrate it the day someone has a longer name.

VARCHAR (no length) — Postgres-only convention; equivalent to TEXT. Some teams prefer the shorter keyword.

TEXT — Postgres: equivalent to VARCHAR, no real reason to prefer one over the other (style choice). MySQL / older SQL Server: when the value is unbounded and length-cap-enforcement isn't useful. MySQL specifically: TEXT columns can't be in a row index without a prefix length, can't have a default value (until 8.0), and live off-row — which is fine for body text but bad for hot-path columns.

Common mistakes #

  • Defaulting to VARCHAR(255) everywhere "to be safe": 255 isn't safe — it's the legacy MySQL pre-5.0.3 max for indexed varchars. Modern engines have no special meaning for 255. Either pick a real domain limit (VARCHAR(2) for country codes, VARCHAR(50) for usernames if your product enforces it) or use unbounded TEXT / VARCHAR.
  • Believing VARCHAR is faster than TEXT on Postgres: it isn't. They share storage. The myth comes from MySQL, where the difference is real.
  • Using TEXT on SQL Server: deprecated. Use VARCHAR(MAX) or NVARCHAR(MAX) instead.
  • Indexing a long TEXT column on MySQL without a prefix: rejected. CREATE INDEX idx ON t(text_col(255)) to index the first 255 chars; or rethink whether the column should be VARCHAR.

FAQ #

On Postgres, is VARCHAR faster than TEXT?

No — they're stored identically. Same performance, same storage. Use VARCHAR(n) only when the length cap is part of the data contract (e.g., country code = VARCHAR(2)); otherwise TEXT (or unbounded VARCHAR) is fine.

On MySQL, what's the real difference between VARCHAR and TEXT?

Real differences. VARCHAR(n) is row-inline (faster reads), can be fully indexed, has a length cap up to ~65,535 bytes. TEXT is stored off-row (the row holds a pointer), requires a prefix length to be indexed (INDEX(text_col(255))), supports up to 4GB. Use VARCHAR for indexed/queried columns, TEXT for body content.

Why is VARCHAR(255) so common?

Legacy. In MySQL versions ≤5.0.3, that was the maximum length for an indexable VARCHAR. Modern engines have no special meaning for 255 — but the convention persists in old codebases. Pick the bound that matches the actual constraint; don't default to 255 just because.

Should I use TEXT in SQL Server?

No — TEXT is deprecated in SQL Server. Use VARCHAR(MAX) (up to 2GB) or NVARCHAR(MAX) (Unicode) instead. VARCHAR(MAX) behaves like the old TEXT but with full feature support (cannot be indexed normally, but works in modern functions).

What about VARCHAR vs NVARCHAR on SQL Server?

NVARCHAR stores Unicode (2 bytes per character); VARCHAR stores single-byte characters (locale-dependent). For new SQL Server schemas, default to NVARCHAR — Unicode handles every script, emojis, accented characters. The 2x storage cost is rarely material.

Will MySQL VARCHAR(50) and VARCHAR(500) take the same storage?

Almost. Storage is "actual length + 1 or 2 byte length prefix." A VARCHAR(50) column holding "ana" takes 4 bytes; the same value in VARCHAR(500) takes 5 bytes (2-byte prefix). Memory allocation and temp tables can differ — wider VARCHAR may cause MySQL to spill to disk earlier. Pick a sensible bound, not arbitrarily wide.

Tip

**Pick by constraint intent, not by expected length.** "I think this won't be longer than 100 chars" is a guess that ages badly; "this column must always be a 3-letter currency code" is a constraint that documents the model. Use bounded VARCHAR(n) when the bound is real domain knowledge; use unbounded TEXT / VARCHAR when it isn't. The rest is folklore.