Skip to main content

VillageSQL is a drop-in replacement for MySQL with extensions.

All examples in this guide work on VillageSQL. Install Now →
MySQL’s native JSON column type validates JSON on insert, stores it in a binary format for efficient access, and provides a set of functions for reading and modifying individual fields without parsing the full document.

Storing JSON

MySQL validates the JSON on insert. Inserting malformed JSON raises an error.

Reading JSON Fields

Use JSON_EXTRACT(column, path) or the -> shorthand:
Both return a JSON value — the string "Acme" with quotes. To get a plain string without quotes, use ->> (which is shorthand for JSON_UNQUOTE(JSON_EXTRACT(...))):
Path syntax:
  • $.key — access an object field
  • $.array[0] — access array element by index
  • $.array[*] — all elements of an array
  • $.** — recursive wildcard (all values at any depth)

Filtering on JSON Fields

Note that ->> returns a string, so comparing to '16' (not 16) is correct unless you cast explicitly: CAST(attributes ->> '$.ram_gb' AS UNSIGNED).

Modifying JSON

The key functions:

Indexing JSON Fields

The JSON column itself can’t be indexed directly. To index a specific JSON field, create a generated column and index that:
Now WHERE attributes ->> '$.brand' = 'Acme' can use idx_brand. MySQL recognizes that the generated column expression matches the query condition. This is covered in more detail in Choosing MySQL Data Types — it’s the recommended pattern whenever you query a JSON field frequently enough to need an index.

JSON vs Normalized Columns

Use JSON when the structure is genuinely variable (user-configurable attributes, event metadata, third-party API payloads). Use normalized columns when the structure is fixed and you need to filter, join, or aggregate on the fields.

Frequently Asked Questions

Can I index a JSON array for containment queries?

Not directly with a standard index. For JSON_CONTAINS queries, the only option is a full table scan unless you extract the array into a separate child table (normalized) or use a full-text index on a generated column that flattens the array. For high-throughput containment queries, normalization is the better path.

What’s the difference between -> and ->>?

-> returns a JSON value (strings include surrounding quotes). ->> returns the unquoted string. For comparisons and WHERE clauses, ->> is usually what you want — comparing "Acme" (with quotes) to the string Acme won’t match.

Does storing JSON hurt performance?

Reading a single field from a large JSON document requires parsing the binary structure, which is faster than parsing text but slower than reading a native column. For frequently accessed fields, the generated column + index pattern brings read performance in line with native columns.

Troubleshooting

See also