VillageSQL is a drop-in replacement for MySQL with extensions.
All examples in this guide work on VillageSQL. Install Now →
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
Reading JSON Fields
UseJSON_EXTRACT(column, path) or the -> shorthand:
"Acme" with quotes. To get a plain string without quotes, use ->> (which is shorthand for JSON_UNQUOTE(JSON_EXTRACT(...))):
$.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
->> returns a string, so comparing to '16' (not 16) is correct unless you cast explicitly: CAST(attributes ->> '$.ram_gb' AS UNSIGNED).
Modifying JSON
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: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. ForJSON_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
- Choosing MySQL Data Types — when to use JSON vs normalized columns
- Generated Columns in MySQL — indexing JSON fields with virtual generated columns
- Making HTTP Requests from SQL — parsing JSON from HTTP API responses

