JSON
JSONEncoder
nil value
null encoding
Swift

Encode nil value as null with JSONEncoder

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Swift's synthesized Encodable implementation omits optional properties whose value is nil. If your API contract requires "field": null instead of omitting the key, you need to take control of encoding for that property and call encodeNil.

Why the default encoder omits nil

JSONEncoder does not have a global "encode all optionals as null" switch. When Swift synthesizes Encodable for a type, optional properties that are nil are usually skipped entirely.

That behavior is often fine, but some APIs distinguish between a missing field and a field explicitly set to null. In that case, omission and null are different signals, so the default synthesis is not enough.

Encode nil explicitly with a custom encode(to:)

The standard solution is to implement encode(to:) yourself and use encodeNil(forKey:) when the optional is absent.

swift
1import Foundation
2
3struct UserProfile: Encodable {
4    let name: String
5    let nickname: String?
6
7    enum CodingKeys: String, CodingKey {
8        case name
9        case nickname
10    }
11
12    func encode(to encoder: Encoder) throws {
13        var container = encoder.container(keyedBy: CodingKeys.self)
14        try container.encode(name, forKey: .name)
15
16        if let nickname {
17            try container.encode(nickname, forKey: .nickname)
18        } else {
19            try container.encodeNil(forKey: .nickname)
20        }
21    }
22}
23
24let profile = UserProfile(name: "Avery", nickname: nil)
25let encoder = JSONEncoder()
26encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
27
28let data = try encoder.encode(profile)
29print(String(data: data, encoding: .utf8)!)

The output contains nickname with a null value instead of omitting it.

Apply the same pattern selectively

You do not have to take over encoding for the whole type unless you want to. A custom encode(to:) method can still delegate ordinary fields to the keyed container and only special-case the optionals that must become null.

That makes the intent very clear. Fields that can be omitted keep the default-style behavior you choose to implement, while fields required by the server contract are always present.

When this matters in real APIs

Some backends interpret a missing field as "do not change this value" and null as "clear this value." Patch-style endpoints are a common example. In that situation, sending null intentionally is part of the protocol, not just a formatting preference.

This is why the correct answer is usually not "make JSONEncoder smarter." The correct answer is "encode the semantic difference explicitly where the API needs it."

The same approach works for nested models as well. If a nested object contains a few optional fields that must be emitted as null, custom encoding can live in that nested type without forcing every surrounding model to adopt special-case logic. Keeping the customization close to the field that needs it makes the serialization rules much easier to maintain.

That explicitness is valuable in API code reviews. Anyone reading the model can see immediately which fields are intentionally nullable in the wire format and which fields are simply absent when not provided. That is much easier to trust than relying on hidden serialization behavior.

Common Pitfalls

  • Assuming JSONEncoder has a built-in strategy that converts every nil into null.
  • Relying on synthesized Encodable when the server requires the key to be present.
  • Overriding encode(to:) and accidentally forgetting to encode one of the non-optional properties.
  • Treating omitted keys and null values as equivalent when the API contract distinguishes them.
  • Adding custom encoding everywhere when only one or two fields actually need explicit null.

Summary

  • Synthesized Encodable usually omits optional properties whose value is nil.
  • To emit JSON null, implement encode(to:) and call encodeNil(forKey:).
  • Use this pattern only for fields where the API contract truly requires explicit nulls.
  • Missing keys and null values often carry different meanings on the server side.
  • Manual encoding is the straightforward way to preserve that distinction.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.