map.deep-merge() belongs to the built-in sass:map module. It merges two maps and recursively merges nested maps. This page covers deep vs shallow map.merge, theme overrides, immutability, Dart Sass 1.27+ support, and five compiled examples.
01
Concept
Recursive merge
02
Module
@use "sass:map"
03
vs merge
Deep vs shallow
04
Conflicts
$map2 wins
05
Since
Dart Sass 1.27+
06
Practice
5 examples
Concept
What Is map.deep-merge()?
Design systems often store config as nested maps—fonts, colors, breakpoints. You want a base map plus overrides without wiping an entire nested branch. Official docs: map.deep-merge is identical to map.merge, except nested map values are also recursively merged.
Both maps keep top-level keys that do not collide
When both have a map at the same key, those maps are merged together
When values are not both maps, $map2’s value replaces $map1’s
💡
Beginner tip
Think of two folders with the same name: deep-merge opens both and combines files inside. Shallow map.merge throws away the first folder and keeps only the second.
Foundation
📝 Syntax
Load the map module, then call the function:
styles.scss
@use "sass:map";
map.deep-merge($map1, $map2)
Parameters
Parameter
Type
Required
Description
$map1
Map
Yes
Base map. Keys that also appear here keep their relative order in the result.
$map2
Map
Yes
Overlay map. New keys are appended; conflicting non-map values replace $map1.
Return value
Type
Result
Map
A new map with top-level and nested keys combined recursively
Modules
📦 Loading sass:map
styles.scss
// Recommended — namespaced
@use "sass:map";
$config: map.deep-merge($base, $overrides);
// Optional — bring members into scope
@use "sass:map" as *;
$config: deep-merge($base, $overrides);
// Optional — custom namespace
@use "sass:map" as m;
$config: m.deep-merge($base, $overrides);
⚠️
No legacy global deep-merge()
Unlike older helpers such as map-merge, there is no separate global deep-merge() outside the module API. Use sass:map.
Details
🔍 map.deep-merge vs map.merge
This is the key beginner trap. Official Helvetica weights sample shows it clearly.
styles.scss
@use "sass:map";
$helvetica-light: (
"weights": (
"lightest": 100,
"light": 300
)
);
$helvetica-heavy: (
"weights": (
"medium": 500,
"bold": 700
)
);
// deep-merge keeps all four weight keys
map.deep-merge($helvetica-light, $helvetica-heavy);
// merge replaces the whole "weights" map with $helvetica-heavy’s only
map.merge($helvetica-light, $helvetica-heavy);
map.deep-merge
map.merge
Nested maps
Merged recursively
Replaced wholesale
Flat maps
Same idea as merge
Combine keys; $map2 wins
Best for
Theme / config trees
Simple one-level maps
Since
Dart Sass 1.27+
Long-standing (module since 1.23+)
Compare
📋 When Values Are Not Both Maps
Recursion only happens when both sides store a map at that key. If $map2 puts a color, number, or other scalar where $map1 had a map, the scalar wins.
styles.scss
@use "sass:map";
$left: ("token": ("size": 16px));
$right: ("token": 1rem);
map.deep-merge($left, $right);
// ("token": 1rem) — not a nested merge
Support
🛠 Compatibility
This is about Sass compilers, not browsers. Compiled CSS only contains the finished values you read from the merged map (for example with map.get).
Implementation
map.deep-merge()
Notes
Dart Sass (1.27+)
Yes — required
Deep map helpers landed in 1.27.0
LibSass
No
No modern sass:map deep API
Ruby Sass
No
Legacy—prefer Dart Sass
Cheat Sheet
⚡ Quick Reference
Goal
Code
Import map
@use "sass:map";
Deep merge
map.deep-merge($base, $overrides)
Shallow merge
map.merge($base, $overrides)
Read nested
map.get($merged, "colors", "primary")
Keep result
$config: map.deep-merge($config, $layer);
Minimum Dart Sass
1.27+
Hands-On
Examples Gallery
Each example uses @use "sass:map". Open View Compiled CSS for verified Dart Sass output (official samples where noted).
📚 Getting Started
Official docs sample: deep merge vs shallow merge.
Example 1 — Helvetica Weights (Official Docs)
Deep merge keeps light and heavy weights; shallow merge drops the light ones.
Both maps use the nested key "weights". Deep merge combines the four weight entries. Shallow merge replaces the entire nested map with the heavy map only.
Example 2 — Theme Override Layer
Merge a base design token map with brand overrides, then read nested colors.
Component configs — merge partial option maps without losing siblings.
Multi-brand builds — deep-merge per-brand token files into one config.
Plugin / mixin APIs — accept user maps and merge onto safe defaults.
Nested typography scales — combine weight/size branches like the docs sample.
🧠 How Compilation Works
1
Write SCSS
Call map.deep-merge($map1, $map2) after @use "sass:map".
Source
2
Walk both maps
Dart Sass merges top-level keys and recurses when both values are maps.
Compile
3
Return a new map
Read values with map.get (including nested key paths).
Result
4
✓
CSS sees tokens
Only the finished colors, sizes, or shadows you emit remain.
Watch Out
⚠️ Common Pitfalls
Using merge by habit — shallow merge drops nested siblings you meant to keep.
Forgetting to reassign — deep-merge returns a copy; it does not mutate in place.
Scalar overrides — a non-map in $map2 replaces a whole nested map.
Old Dart Sass — need 1.27+ for map.deep-merge.
Expecting a global name — there is no legacy deep-merge() outside sass:map.
Pro Tips
💡 Best Practices
✅ Do
Use @use "sass:map" and map.deep-merge() for nested configs
Put defaults in $map1 and overrides in $map2
Read results with nested map.get($map, $k1, $k2, …)
Reassign when updating a stored config variable
Prefer Dart Sass 1.27+
❌ Don’t
Expect the browser to evaluate map.deep-merge
Use shallow map.merge when nested keys must survive
Assume originals mutate without reassignment
Rely on LibSass for deep map helpers
Pass a scalar overlay if you still need the nested map
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about map.deep-merge()
Recursive nested merge—$map2 wins conflicts; returns a new map.
5
Core concepts
📝01
Call
map.deep-merge($map1, $map2)
API
📦02
Module
sass:map
@use
🔢03
Nested maps
merge recursively
Rule
❓04
vs merge
shallow replaces branch
Safe
✓05
Prefer
Dart Sass 1.27+
Tooling
❓ Frequently Asked Questions
map.deep-merge($map1, $map2) returns a new map combining both maps. Nested map values are merged recursively—unlike map.merge(), which replaces a whole nested map when keys collide.
Official docs: identical to map.merge(), except nested map values are also recursively merged. Shallow merge replaces the nested "weights" map entirely; deep-merge keeps keys from both nested maps.
For non-map values, $map2 wins. For nested maps on both sides, keys are combined and $map2’s nested values still override matching nested keys.
No. It returns a new map. Reassign if you need to keep the result: $config: map.deep-merge($config, $overrides).
No. Use map.deep-merge() after @use "sass:map" (or @use "sass:map" as * and call deep-merge()).
Dart Sass 1.27+. LibSass and Ruby Sass do not provide this deep helper the same way—prefer current Dart Sass.
Did you know?
Official Sass docs highlight deep operations because libraries and design systems often share nested configuration maps. Helpers like map.get with multiple keys, map.deep-remove, and map.deep-merge are built for that pattern.
map.deep-merge() recursively merges nested Sass maps so theme and config layers keep sibling keys. Load it through sass:map, prefer it over shallow map.merge for nested trees, and reassign to keep the returned copy.