map.merge() belongs to the built-in sass:map module. It combines two maps into one new map. This page covers overrides, key order, nested path merge, shallow vs map.deep-merge, the legacy map-merge name, and five compiled examples.
01
Concept
Shallow merge
02
Module
@use "sass:map"
03
Conflicts
$map2 wins
04
Nested path
Dart Sass 1.27+
05
vs deep-merge
Shallow vs recursive
06
Practice
5 examples
Concept
What Is map.merge()?
A Sass map is a collection of keys and values—like a small dictionary for design tokens. map.merge() builds a new map that contains every key from both inputs:
Keys only in $map1 are kept
Keys only in $map2 are added at the end
Keys in both maps use the value from $map2
The merge is shallow. If both maps store another map under the same key, $map2’s whole nested map replaces $map1’s. To combine nested maps key-by-key, use map.deep-merge().
💡
Beginner tip
Think of two sticky notes with settings. Merge copies both onto a fresh note. When the same setting appears twice, the second sticky note wins. Nested sections are replaced as one block—not opened and mixed file-by-file.
Foundation
📝 Syntax
Load the map module, then call the function:
styles.scss
@use "sass:map";
// Two-argument form (most common)
map.merge($map1, $map2)
// Nested path form (Dart Sass 1.27+)
map.merge($map1, $keys..., $map2)
Parameters
Parameter
Type
Required
Description
$map1
Map
Yes
Base map. Shared keys keep the same relative order as in $map1.
$keys...
Keys
No
Optional path into a nested map (Dart Sass 1.27+). Omitted for a top-level merge.
$map2
Map
Yes
Overlay map. New keys are appended; conflicting values replace $map1’s.
⚠️
Argument naming note
Official docs describe nested calls as map.merge($map1, $keys..., $map2) for clarity. In practice Sass receives them as map.merge($map1, $args...)—the last argument must be the overlay map.
Return value
Type
Situation
Result
Map
No $keys
New map combining $map1 and $map2 (shallow)
Map
With $keys
Copy of $map1 where the nested target is shallow-merged with $map2
Modules
📦 Loading sass:map
Modern Sass groups map helpers into a module. Load it with @use, then call map.merge. The older global name map-merge still works for two-argument merges.
styles.scss
// Recommended — namespaced
@use "sass:map";
$config: map.merge($base, $overrides);
// Optional — bring members into the current namespace
@use "sass:map" as *;
$config: merge($base, $overrides);
// Optional — custom namespace
@use "sass:map" as m;
$config: m.merge($base, $overrides);
// Legacy global (two maps only)
$config: map-merge($base, $overrides);
⚠️
Put @use first
@use rules must appear before most other rules. Keep @use "sass:map"; near the top of the file.
Details
🔢 Key Order & Conflicts
Official behavior is predictable once you remember three rules:
With Dart Sass 1.27+, you can pass keys between the two maps. Sass walks those keys to find a nested map, then shallow-merges $map2 into that target. Missing keys along the path become empty maps so the path can be created.
Nested path map.merge still does a shallow merge at the target. It is perfect when you already know the nested location. Prefer map.deep-merge when you want whole config trees combined recursively.
Compare
📋 map.merge vs map.deep-merge
Same top-level idea; different treatment of nested maps. The official Helvetica sample shows the trap clearly.
map.merge
map.deep-merge
Nested maps
Replaced wholesale
Merged recursively
Flat maps
Combine keys; $map2 wins
Same idea as merge
Best for
Simple one-level maps & targeted path updates
Theme / config trees
Legacy global
map-merge
None—module only
Deep helper since
Long-standing (module since 1.23+)
Dart Sass 1.27+
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
@use "sass:map"
Global map-merge
Nested path merge
Dart Sass (1.23+)
Yes — preferred
Yes
1.27+ only
LibSass
No built-in modules
Yes (legacy)
No
Ruby Sass
No built-in modules
Yes (legacy)
No
Prefer Dart Sass for new work. Use current Dart Sass (1.27+) if you need nested path merge or map.deep-merge.
Cheat Sheet
⚡ Quick Reference
Goal
Code
Import map
@use "sass:map";
Shallow merge
map.merge($base, $overrides)
Nested path merge
map.merge($map, "a", "b", $overlay)
Deep recursive merge
map.deep-merge($base, $overrides)
Read a value
map.get($merged, "primary")
Keep result
$config: map.merge($config, $layer);
Legacy global call
map-merge($base, $overrides)
Hands-On
Examples Gallery
Each example uses @use "sass:map". Open View Compiled CSS to see what Dart Sass emits (maps inspected via meta.inspect where needed).
📚 Getting Started
Official docs sample and everyday override rules.
Example 1 — Merge Two Flat Maps (Official Docs)
Combine light and heavy font weights into one map.
Component defaults — accept a user options map and overlay it on safe defaults.
Build-time themes — combine shared and per-page token maps before emitting CSS variables.
Targeted nested updates — path merge into one branch without rewriting the whole tree.
Legacy migrations — replace map-merge with namespaced map.merge.
🧠 How Compilation Works
1
Write SCSS
Add @use "sass:map"; and call map.merge($map1, $map2).
Source
2
Dart Sass merges
Keys combine; conflicts prefer $map2; nested maps replace if colliding.
Compile
3
New map returned
Read tokens with map.get (or nested key paths).
Result
4
✓
CSS sees values
Browsers never see map.merge—only the finished CSS you emit.
Watch Out
⚠️ Common Pitfalls
Expecting deep merge — nested colliding maps are replaced, not combined. Use map.deep-merge when siblings must survive.
Forgetting to reassign — map.merge returns a copy; originals stay unchanged unless you assign the result.
Wrong overlay order — put defaults first and overrides second so $map2 wins.
Nested path on old Sass — more than two arguments needs Dart Sass 1.27+.
Forgetting @use — map.merge is undefined until you load sass:map (or use legacy map-merge).
Pro Tips
💡 Best Practices
✅ Do
Use @use "sass:map" and map.merge() in new SCSS
Put defaults in $map1 and overrides in $map2
Choose map.deep-merge for nested theme trees
Reassign when updating a stored config variable
Prefer Dart Sass for modules and nested path merge
❌ Don’t
Expect the browser to evaluate map.merge
Use shallow merge when nested sibling keys must remain
Assume originals mutate without reassignment
Pass overrides as the first map if you want them to win
Rely on LibSass for nested path merge
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about map.merge()
Shallow combine—$map2 wins; returns a new map.
5
Core concepts
📝01
Call
map.merge($map1, $map2)
API
📦02
Module
sass:map
@use
🔢03
Conflicts
$map2 wins
Rule
❓04
Nested maps
replaced (shallow)
Safe
✓05
Legacy
map-merge still works
Tooling
❓ Frequently Asked Questions
map.merge($map1, $map2) returns a new map with all keys from both maps. If both share a key, $map2’s value wins. Nested map values are replaced wholesale—not merged recursively (use map.deep-merge for that).
No. It returns a new map. Reassign if you need to keep the result: $config: map.merge($config, $overrides).
map.merge is shallow: a nested map at a colliding key is replaced entirely by $map2’s value. map.deep-merge recursively merges nested maps so sibling keys inside both branches survive.
Yes. map-merge($map1, $map2) is the older global name. Prefer map.merge after @use "sass:map". Nested path merge with extra keys needs Dart Sass 1.27+ and the module API.
Yes on Dart Sass 1.27+: map.merge($map, $key1, $key2, ..., $overlay) walks the keys, then shallow-merges $overlay into that nested target.
$map2 always wins for that key. Keys that only exist in $map1 keep their values and relative order; new keys from $map2 are appended at the end.
Did you know?
Official Sass docs show the same Helvetica weights sample for both map.merge and map.deep-merge so you can compare shallow replace with recursive merge side by side—one of the clearest teaching examples in the map module.
map.merge() is the everyday way to combine Sass maps: defaults first, overrides second, $map2 wins on conflicts, and the result is always a new map. Use it for flat tokens and targeted nested updates; switch to map.deep-merge when nested siblings must survive.