Chapter 15 · Semi-Structured and Polymorphic Data

When JSON Belongs in a Relational Database

Decide when JSON is appropriate inside a relational database, preserve relational integrity around flexible payloads, and avoid turning structured entities into unvalidated blobs.

Beginner70–95 minutesJSON + relational boundariesLast reviewed: August 2026

Learning outcomes

Modern relational databases often support JSON as a native data type. That does not mean every flexible-looking object belongs in JSON. The key question is semantic: which facts need relational identity, constraints, joins, and independent lifecycle, and which facts are legitimately semi-structured?

01

Identify valid JSON use cases in a relational schema.

02

Recognize when JSON hides relationships that should be modeled relationally.

03

Apply validation and indexing to frequently queried JSON attributes.

04

Design a safe JSON boundary for WorkshopHub.

JSON is a storage format, not a modeling exemption

A JSON document can be convenient, but it does not remove the need to define:

  • ownership;
  • row grain;
  • required fields;
  • uniqueness;
  • references;
  • history;
  • query patterns.

Good JSON candidate: external diagnostic payload

model · example
DiagnosticCapture(  capture_id,  work_order_id,  source_system,  captured_at,  payload_json)

If payload shape differs by diagnostic device and the raw response must be preserved, JSON can be a sensible boundary.

Bad JSON candidate: hidden foreign keys

json · document
{  "technician_ids": [17, 23, 44],  "part_ids": [91, 105]}

If these IDs participate in relationships, joins, integrity, or lifecycle, they should generally be represented by WorkOrderAssignment and PartUsage rows rather than hidden arrays.

Relational rule

Do not use JSON to bypass foreign keys for relationships the database is responsible for protecting.

Good JSON candidate: sparse vendor metadata

A Part may receive optional manufacturer-specific metadata:

json · document
{  "torque_rating_nm": 120,  "seal_material": "FKM",  "vendor_family": "X7"}

If only some Part families expose these fields and they do not justify independent entities, JSON may be practical.

When stable fields should become columns

If every query needs:

model · example
payload->>'serial_number'payload->>'manufacturer_code'payload->>'status'

those fields may no longer be genuinely semi-structured. Promote stable, business-critical attributes into typed columns or related tables.

Type safety

Relational columns provide clear domains:

model · example
quantity INTEGERunit_price NUMERIC(12,2)occurred_at TIMESTAMP

JSON can contain unexpected strings, nulls, arrays, or type changes unless validation exists.

Schema validation for JSON

Validation can live in:

  • application schemas;
  • database CHECK constraints;
  • JSON Schema validation where supported;
  • generated/computed columns;
  • ingestion pipelines.

Version the payload shape

json · document
{  "schema_version": 3,  "temperature_c": 81.4,  "vibration": {...}}

Without a version, old and new payloads become difficult to interpret safely.

Indexing JSON

Frequently queried JSON paths may need expression, path, GIN/inverted, or engine-specific indexes. Index only paths tied to real access patterns.

Promoted columns

A hybrid row can use:

model · example
DiagnosticCapture(  capture_id,  work_order_id,  captured_at,  severity_code,  payload_json)

severity_code is promoted because it is common, constrained, and frequently filtered; the rest remains flexible.

Do not duplicate without ownership

If severity exists both as a column and inside JSON, define which is authoritative and how they remain consistent. Better yet, avoid duplicate representation unless it solves a measured need.

JSON and normalization

JSON can contain nested structures without violating the physical capabilities of the DBMS, but from a modeling perspective ask whether nested arrays represent independent repeating facts. If so, relational decomposition may still be preferable.

JSON and history

Immutable event snapshots are strong JSON candidates because preserving the exact original payload may be more important than normalizing every field.

WorkshopHub JSON map

DataLikely representation
WorkOrder core statusRelational column/reference
Technician assignmentsRelational association rows
Raw diagnostic responseJSON snapshot
Rare vendor-specific Part metadataJSON or subtype table
Frequently queried manufacturerRelational reference

Practice: JSON or relation?

Repair checklist answers

Each WorkOrder has a checklist whose questions vary by service type. Answers are mostly displayed as submitted, but some fields drive compliance reports. How might you design it?

Review answer

Use a versioned checklist definition and a flexible JSON answer payload if forms vary heavily, but promote compliance-critical fields or model them relationally when they need typed constraints, joins, or frequent reporting. Preserve checklist version so answers remain interpretable.

Summary and next lesson

JSON is valuable for semi-structured, sparse, or externally shaped data, especially immutable snapshots. It becomes dangerous when used to hide relational identity, foreign keys, or frequently queried stable facts. The next lesson compares schema-on-write with flexible attribute strategies more broadly.

References

  • Martin Kleppmann, Designing Data-Intensive Applications.
  • PostgreSQL documentation on JSON/JSONB and indexing.
  • DBMS documentation for JSON validation and generated columns.

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only assets compatible with the Ethereum/ERC-20 network. Do not send TRC-20/TRON assets.