Null, missing, empty string, and empty collection should have field-specific meanings, not a universal equivalence rule. Define those meanings in the API contract and preserve them through parsing, domain types, persistence, and partial updates. Most accidental data loss occurs when one layer silently collapses states another layer distinguishes.
Start with operations, not types
For each field, answer five questions. What happens when it is omitted on create? How does a client leave it unchanged on update? How is it explicitly cleared? Is an empty value valid data? Can the value be unknown? A required display name may reject null and empty string. An optional middle name may use null to mean known absence. A list of notification channels may use an empty array to mean deliberately none.
JSON itself permits null values and omitted members, but patch formats assign semantics. JSON Merge Patch, RFC 7396, treats null in a patch as removal and leaves absent members unchanged. That makes it unsuitable for directly setting a target member to JSON null without an additional convention. JSON Patch, RFC 6902 expresses explicit add, remove, replace, move, copy, and test operations, preserving the distinction through operation names. Choose deliberately and document media types.
A conventional partial object can also work if presence is tracked separately from value. In TypeScript, field?: string | null contains three conceptual states, but careless destructuring, default parameters, or value || fallback can collapse empty string and null. Use presence checks and nullish coalescing only when its exact behavior matches the field contract. Parse transport data into domain commands such as LeaveUnchanged, Clear, and Set(value) before business logic.
Keep SQL’s third truth value visible
SQL null represents unknown or absent information and ordinary equality comparisons with null do not return true. PostgreSQL documents these behaviors and provides predicates such as IS NULL and IS DISTINCT FROM. A filter translated from field = null can therefore produce surprising results. Define repository methods around domain intent, and test nullable uniqueness, ordering, aggregates, and indexes for the database in use.
Avoid storing empty strings merely because a column is non-nullable. That erases the difference between missing information and an intentionally empty value and spreads cleanup rules through queries. Conversely, do not turn every empty string into null globally; an empty search query or text area can be a valid user choice. Normalize at the field boundary.
Make forms preserve intent
A blank form control cannot by itself tell whether a user cleared a value or never edited it. Track dirty state and build update commands from touched fields. For checkboxes and multi-select controls, browsers may omit values entirely; the server should not interpret omission as clearing unless the form contract says so. On validation failure, return the submitted state without applying create defaults again.
Version changes need care. Making a formerly optional field required can break stored rows and old clients. Adding a default may change whether omission means server choice or a durable value. Backfill explicitly, then decide whether the default is materialized or computed.
Pick one frequently patched resource and create a matrix with create omission, update omission, null, empty, and normal value for every optional field. Add round-trip tests through JSON, domain types, and SQL. The first ambiguous cell is a contract decision to make before the next client implements its own interpretation.
Include observability and exports
Analytics, audit events, and CSV exports often collapse null and empty after the main API is correct. Define representations there too. A changed-field event should distinguish cleared from untouched; an export should preserve unknown when round-trip matters. Add contract fixtures consumed by every serializer and verify import reverses them. Dashboards should not count missing telemetry as an empty business value, and log enrichment must not invent defaults absent from the original event.
Reviewed September 2026.
Sources are linked throughout this guide. Product capabilities can change; consult the linked documentation for your deployment.
Read our editorial approach ↗