How to Deep Merge Nested Dicts Recursively in Python

Recursively merge two Python dictionaries, with overlay values taking precedence while preserving nested structures.

Medium Python 3.9+ Aug 9, 2026 Dictionaries & sets 14 views 0 copies

Python code

40 lines
Python 3.9+
def deep_merge(base, overlay):
    """
    Recursively merge two dictionaries.
    Values in 'overlay' take precedence over 'base'.
    """
    result = base.copy()
    
    for key, value in overlay.items():
        if key in result and isinstance(result[key], dict) and isinstance(value, dict):
            result[key] = deep_merge(result[key], value)
        else:
            result[key] = value
    
    return result


if __name__ == "__main__":
    base = {
        "server": {
            "host": "localhost",
            "port": 8080,
            "tls": {"enabled": False, "cert": "base.crt"}
        },
        "logging": {"level": "INFO", "file": "app.log"}
    }
    
    overlay = {
        "server": {
            "port": 9090,
            "tls": {"enabled": True}
        },
        "logging": {"level": "DEBUG"},
        "new_key": "added"
    }
    
    merged = deep_merge(base, overlay)
    
    # Pretty-print for clear demonstration
    import json
    print(json.dumps(merged, indent=2))

Output

stdout
{
  "server": {
    "host": "localhost",
    "port": 9090,
    "tls": {
      "enabled": true,
      "cert": "base.crt"
    }
  },
  "logging": {
    "level": "DEBUG",
    "file": "app.log"
  },
  "new_key": "added"
}

How it works

The deep_merge function starts by copying the base dictionary, ensuring the original isn't mutated. For each key-value pair in the overlay, it checks if the key already exists in the result and both values are dictionaries — if so, it recurses into the nested dicts. Otherwise, the overlay value simply overwrites or adds the key. This handles arbitrarily deep nesting because the recursion descends whenever both sides are dicts. The str() function in the print statement explicitly converts the output for display.

Common mistakes

  • Forgetting to copy the base dict, which mutates the original input
  • Not checking whether both values are dicts before recursing, leading to type errors
  • Overwriting nested dicts entirely instead of merging them when keys overlap

Variations

  1. Use `collections.ChainMap` for one-level merges without nested recursion
  2. Add a guard to handle lists by concatenating or replacing them based on your use case

Real-world use cases

  • Combining config files from different environments (dev, staging, prod) where later ones override defaults.
  • Merging user-provided settings into an application's default configuration during startup.
  • Applying incremental patches to API response payloads without losing unmodified nested fields.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Dictionaries & sets

Related tutorials and quizzes for this topic.