Sass map.merge() Function

Beginner
⏱️ 12 min read
📚 Updated: Jul 2026
🎯 5 Examples
sass:map · Dart Sass

What You’ll Learn

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

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.

📝 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

ParameterTypeRequiredDescription
$map1MapYesBase map. Shared keys keep the same relative order as in $map1.
$keys...KeysNoOptional path into a nested map (Dart Sass 1.27+). Omitted for a top-level merge.
$map2MapYesOverlay 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

TypeSituationResult
MapNo $keysNew map combining $map1 and $map2 (shallow)
MapWith $keysCopy of $map1 where the nested target is shallow-merged with $map2

📦 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.

🔢 Key Order & Conflicts

Official behavior is predictable once you remember three rules:

RuleWhat happens
Conflict$map2’s value replaces $map1’s for the same key
Order of shared keysSame order as in $map1
New keys from $map2Appended at the end of the result
styles.scss
@use "sass:map";

$a: ("primary": #336699, "radius": 8px);
$b: ("primary": #1d4ed8, "shadow": true);

map.merge($a, $b);
// ("primary": #1d4ed8, "radius": 8px, "shadow": true)

🔗 Nested Path Merge

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.

styles.scss
@use "sass:map";

$fonts: (
  "Helvetica": (
    "weights": (
      "lightest": 100,
      "light": 300
    )
  )
);
$heavy-weights: ("medium": 500, "bold": 700);

map.merge($fonts, "Helvetica", "weights", $heavy-weights);
// Helvetica → weights now has lightest, light, medium, and bold
💡
Path merge vs deep-merge

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.

📋 map.merge vs map.deep-merge

Same top-level idea; different treatment of nested maps. The official Helvetica sample shows the trap clearly.

map.mergemap.deep-merge
Nested mapsReplaced wholesaleMerged recursively
Flat mapsCombine keys; $map2 winsSame idea as merge
Best forSimple one-level maps & targeted path updatesTheme / config trees
Legacy globalmap-mergeNone—module only
Deep helper sinceLong-standing (module since 1.23+)Dart Sass 1.27+

🛠 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-mergeNested path merge
Dart Sass (1.23+)Yes — preferredYes1.27+ only
LibSassNo built-in modulesYes (legacy)No
Ruby SassNo built-in modulesYes (legacy)No

Prefer Dart Sass for new work. Use current Dart Sass (1.27+) if you need nested path merge or map.deep-merge.

⚡ Quick Reference

GoalCode
Import map@use "sass:map";
Shallow mergemap.merge($base, $overrides)
Nested path mergemap.merge($map, "a", "b", $overlay)
Deep recursive mergemap.deep-merge($base, $overrides)
Read a valuemap.get($merged, "primary")
Keep result$config: map.merge($config, $layer);
Legacy global callmap-merge($base, $overrides)

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.

styles.scss
@use "sass:map";
@use "sass:meta";

$light-weights: ("lightest": 100, "light": 300);
$heavy-weights: ("medium": 500, "bold": 700);

@debug map.merge($light-weights, $heavy-weights);
// ("lightest": 100, "light": 300, "medium": 500, "bold": 700)

.weights {
  --merged: #{meta.inspect(map.merge($light-weights, $heavy-weights))};
}

How It Works

No shared keys, so every entry survives. Keys from $light-weights come first; keys from $heavy-weights are appended.

Example 2 — $map2 Wins on Conflicts

Override a shared token while keeping keys unique to the base map.

styles.scss
@use "sass:map";

$base: (
  "primary": #336699,
  "radius": 8px,
  "gap": 16px
);
$brand: (
  "primary": #1d4ed8,
  "accent": #e67e22
);
$theme: map.merge($base, $brand);

.btn {
  color: map.get($theme, "primary");
  border-radius: map.get($theme, "radius");
  gap: map.get($theme, "gap");
  outline-color: map.get($theme, "accent");
}

How It Works

primary is overridden by the brand map. radius and gap stay from the base; accent is new.

📈 Practical Patterns

Nested targets, theme layers, and shallow vs deep behavior.

Example 3 — Nested Path Merge (Official Docs)

Walk into Helvetica → weights, then merge heavier weights there.

styles.scss
@use "sass:map";
@use "sass:meta";

$fonts: (
  "Helvetica": (
    "weights": (
      "lightest": 100,
      "light": 300
    )
  )
);
$heavy-weights: ("medium": 500, "bold": 700);
$merged: map.merge($fonts, "Helvetica", "weights", $heavy-weights);

.font {
  --weights: #{meta.inspect(map.get($merged, "Helvetica", "weights"))};
}

How It Works

The keys "Helvetica" and "weights" locate the nested map. Only that target is merged with $heavy-weights; the rest of $fonts is copied.

Example 4 — Theme Defaults + Overrides

Reassign so a config variable keeps the merged result (maps are immutable).

styles.scss
@use "sass:map";

$config: (
  "space": 1rem,
  "line": 1.5
);
$overrides: (
  "space": 1.25rem,
  "max": 72ch
);

$config: map.merge($config, $overrides);

.prose {
  padding: map.get($config, "space");
  line-height: map.get($config, "line");
  max-width: map.get($config, "max");
}

How It Works

Without $config: map.merge(...), the original variable would stay unchanged. Reassignment stores the new map for later map.get calls.

Example 5 — Shallow Merge Drops Nested Siblings

When both sides nest a "weights" map, shallow merge keeps only $map2’s branch.

styles.scss
@use "sass:map";
@use "sass:meta";

$helvetica-light: (
  "weights": (
    "lightest": 100,
    "light": 300
  )
);
$helvetica-heavy: (
  "weights": (
    "medium": 500,
    "bold": 700
  )
);

.compare {
  --shallow: #{meta.inspect(map.merge($helvetica-light, $helvetica-heavy))};
  --deep: #{meta.inspect(map.deep-merge($helvetica-light, $helvetica-heavy))};
}

How It Works

Shallow merge replaces the entire "weights" map. Deep merge keeps all four weight keys. Choose based on whether nested siblings must survive.

🚀 Real-World Use Cases

  • Flat design tokens — merge brand colors onto a default palette.
  • 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.

⚠️ Common Pitfalls

  • Expecting deep merge — nested colliding maps are replaced, not combined. Use map.deep-merge when siblings must survive.
  • Forgetting to reassignmap.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 @usemap.merge is undefined until you load sass:map (or use legacy map-merge).

💡 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

Key Takeaways

Knowledge Unlocked

Five things to remember about map.merge()

Shallow combine—$map2 wins; returns a new map.

5
Core concepts
📦 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.

Conclusion

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.

Continue with map.remove() or the Sass introduction.

Next: remove map keys

Learn map.remove() to drop top-level tokens from a map.

map.remove() →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

5 people found this page helpful