Skip to content

Backward Compatibility

DodaTech 2 min read

title: "Backward Compatibility — Making Non-Breaking API Changes" description: "Backward compatibility ensures new API versions work with existing clients by adding optional fields, avoiding removals, and following additive change patterns." date: 2026-06-28 lastmod: 2026-06-28 weight: 19 tags: [apis, versioning] }

Backward compatibility means new API versions continue working for existing clients without changes, enabling additive evolution through new fields and endpoints.

What You'll Learn

  • What makes a change backward compatible
  • Additive vs breaking changes
  • Testing for backward compatibility

Why It Matters

Maintaining backward compatibility allows clients to upgrade on their schedule. Breaking changes force immediate migration, causing friction and churn.

Compatibility Rules

# Backward compatible changes

# 1. Adding optional fields is safe
# v1 response:
{"id": 1, "name": "Alice"}
# v2 response (adds optional field):
{"id": 1, "name": "Alice", "email": "alice@example.com"}

# 2. Adding new endpoints is safe
# v1: GET /users
# v2 adds: GET /users/{id}/posts

# 3. Relaxing input validation is safe
# v1: POST /users { "name": "..." }  # name required
# v2: POST /users { "name": "...", "nickname": "..." }  # nickname optional

# 4. Changing response order is NOT safe if clients rely on field order
# v1: {"id": 1, "name": "Alice"}
# v2: {"name": "Alice", "id": 1}  # BREAKING for clients using positional access

# 5. Adding enum values is safe
from enum import Enum
class Status(Enum):
    ACTIVE = "active"
    INACTIVE = "inactive"
    PENDING = "pending"  # Added in v2, safe for existing clients
// Backward compatibility checker
function isBackwardCompatible(oldSchema, newSchema) {
  // Check: no removed fields
  for (const field of Object.keys(oldSchema.properties)) {
    if (!newSchema.properties[field]) {
      return false; // Removed field
    }
  }

  // Check: existing field types haven't changed
  for (const field of Object.keys(newSchema.properties)) {
    if (oldSchema.properties[field]) {
      if (oldSchema.properties[field].type !== newSchema.properties[field].type) {
        return false; // Changed type
      }
      // Required field can't become more restrictive
      if (newSchema.required?.includes(field) && !oldSchema.required?.includes(field)) {
        return false; // Field became required
      }
    }
  }

  return true;
}

Common Mistakes

1. Removing Fields

Once a field is in the response, it must stay (or be explicitly deprecated).

2. Making Optional Fields Required

Adding required to an existing field breaks all clients that don't send it.

3. Changing Field Types

A field returning string that suddenly returns number breaks clients.

4. Renaming Fields

Create a new field and deprecate the old one. Never rename.

5. Changing Enum Values

Removing enum values breaks clients using them.

Practice Questions

  1. Is adding a new field backward compatible?
  2. Is removing a field backward compatible?
  3. Is changing a field type backward compatible?
  4. What is the additive change rule?
  5. How do you deprecate a field safely?

Answers:

  1. Yes, if it's optional (no required constraint).
  2. No, always breaking.
  3. No, always breaking.
  4. Only add, never remove or change existing behavior.
  5. Add the new field, document the old field as deprecated, remove in the next major version.

Challenge: Review your API response schemas. Identify changes that are not backward compatible and create a migration plan.

FAQ

Can I change field names?

: Not directly. Add the new name as a field, deprecate the old one.

Is adding a new endpoint backward compatible?

: Yes, additive endpoint changes are always safe.

Can I change error messages?

: Yes, but don't change error codes or response structure.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro