MySQL ENUM Type
debt(d5/e5/b5/t7)
Closest to 'specialist tool catches it' (d5). The detection_hints list semgrep as the tool, which is a SAST/specialist tool rather than a default linter. It can detect ENUM column patterns on status/state fields, but won't catch all misuse (e.g. silent empty-string corruption in non-strict mode or ORDER BY surprises at runtime).
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix says to replace ENUM with VARCHAR+CHECK or a lookup table. A lookup table refactor touches schema migration, application code referencing the column type, ORM models, and queries — more than a single-line patch but not necessarily a cross-cutting architectural rewrite. This sits at e5.
Closest to 'persistent productivity tax' (b5). The choice couples business logic into the database schema — every time a status value must be added, an ALTER TABLE migration is required. This slows multiple work streams (backend changes, migrations, deployments) but is localised to tables that use ENUM rather than shaping the whole system architecture.
Closest to 'serious trap' (t7). The misconception field states the canonical trap: developers believe ENUM is 'just a VARCHAR with validation' but it stores integers and ORDER BY sorts by definition index, not alphabetically. Additionally, non-strict mode silently coerces invalid values to empty strings causing data corruption. These behaviours contradict how similar concepts (VARCHAR, CHECK constraints) work elsewhere, placing this squarely at t7.
Also Known As
TL;DR
Explanation
ENUM('active', 'inactive', 'pending') stores values as 1-byte integers mapped to the string list. Advantages: compact storage, enforced value set. Disadvantages: adding or removing values requires ALTER TABLE which can lock the table on large datasets; the allowed values are baked into the schema; invalid values silently become empty string in non-strict mode. SET is similar but allows multiple values stored as a bitmask.
Watch Out
Common Misconception
Why It Matters
Common Mistakes
- Using ENUM for status fields that change frequently — adding values requires ALTER TABLE.
- Relying on ENUM's invalid-value-to-empty-string behaviour in non-strict mode — silent data corruption.
- Expecting ORDER BY on an ENUM to sort alphabetically — it sorts by index position.
Avoid When
- Never use ENUM for status fields that change as the business evolves — adding values requires ALTER TABLE.
- Avoid ENUM with strict mode disabled — invalid values become empty string silently.
When To Use
- Use ENUM only for truly static values that will never change — e.g. gender (M/F/X) or day_of_week.
- Prefer MySQL 8 CHECK constraints or a lookup table for values that may grow.
Code Examples
-- ENUM — adding 'refunded' requires ALTER TABLE (locks large tables)
status ENUM('pending', 'paid', 'shipped', 'cancelled') NOT NULL DEFAULT 'pending'
-- Preferred: lookup table for flexible values
CREATE TABLE order_statuses (id TINYINT UNSIGNED PRIMARY KEY, name VARCHAR(50) NOT NULL);
INSERT INTO order_statuses VALUES (1,'pending'),(2,'paid'),(3,'shipped'),(4,'cancelled');
CREATE TABLE orders (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
status_id TINYINT UNSIGNED NOT NULL DEFAULT 1,
FOREIGN KEY (status_id) REFERENCES order_statuses(id)
);
-- Or: MySQL 8 CHECK constraint
status VARCHAR(20) CHECK (status IN ('pending','paid','shipped','cancelled'))