Lodash _.mapKeys() method

Beginner
⏱️ 7 min read
📚 Updated: May 2026
🎯 3 Code examples
🚀 3 Try-it labs
Lodash

What you’ll learn

  • How _.mapKeys(object, [iteratee]) rewrites every key while keeping its value intact.
  • The iteratee signature (value, key, object) and the four shorthand forms.
  • The silent last-write-wins behavior when transformed keys collide.
  • How to pair _.mapKeys with _.mapValues() for full object reshaping.

Prerequisites

Comfortable with Lodash iteratee shorthands and the idea that object keys must be unique strings.

  • Keys, not values: use _.mapValues if you only want to transform values.
  • Pure function: a new object is returned; the source stays the same.
  • Own enumerable only: inherited and symbol-keyed properties are skipped.

Overview

_.mapKeys iterates the source’s own enumerable string-keyed properties, calls the iteratee with (value, key, object), and uses the returned string as the new key. Values are copied through unchanged. The result is the fast path for renaming, normalizing, and namespacing keys without rebuilding objects by hand.

Rename in one pass

Convert snake_case to camelCase, prefix keys, or apply a lookup table.

Last-write-wins

Collisions silently overwrite. Encode uniqueness into the iteratee output.

Pure transform

A new object is returned. The input is never mutated.

Syntax

javascript
_.mapKeys(object, [iteratee=_.identity])
  • object: source to iterate over. Only own enumerable string-keyed properties are visited.
  • iteratee (optional): function, property name string, [path, value], or matcher object. Receives (value, key, object).
  • Returns: a new object with the same values and the iteratee-produced keys.
1

Uppercase & prefix keys

The simplest form—return a transformed key string from the iteratee. The iteratee receives (value, key, object), but you usually only need key.

javascript
import mapKeys from "lodash/mapKeys";

const counts = { a: 1, b: 2, c: 3 };

mapKeys(counts, (value, key) => key.toUpperCase());
// -> { A: 1, B: 2, C: 3 }

mapKeys(counts, (value, key) => "n_" + key);
// -> { n_a: 1, n_b: 2, n_c: 3 }

counts;
// -> { a: 1, b: 2, c: 3 }
//    Source is unchanged.
Try it Yourself
2

Normalize snake_case to camelCase

A real-world use case: converting API responses to JavaScript conventions in one pass.

javascript
import mapKeys from "lodash/mapKeys";

const apiUser = {
  first_name: "John",
  last_name:  "Doe",
  email_address: "john@example.com",
  is_verified: true
};

const camelize = (str) =>
  str.replace(/_([a-z])/g, (_, ch) => ch.toUpperCase());

mapKeys(apiUser, (value, key) => camelize(key));
// -> {
//      firstName: "John",
//      lastName:  "Doe",
//      emailAddress: "john@example.com",
//      isVerified: true
//    }

// Renaming a specific key with a lookup table:
const aliases = { is_verified: "verified" };
mapKeys(apiUser, (value, key) => aliases[key] || key);
// -> { first_name: "John", last_name: "Doe", email_address: "...", verified: true }
Try it Yourself
3

Collisions silently overwrite

This is the single biggest _.mapKeys pitfall. If two source keys transform to the same string, the later iteration overwrites the earlier value—no warning, no error.

javascript
import mapKeys from "lodash/mapKeys";

const fruits = { apple: 1, avocado: 2, banana: 3 };

// First letter only -> "a" collides for apple and avocado.
mapKeys(fruits, (value, key) => key[0]);
// -> { a: 2, b: 3 }
//    apple's value is silently lost.

// Safer alternative: include the original key in the new key.
mapKeys(fruits, (value, key) => key[0] + "_" + key);
// -> { a_apple: 1, a_avocado: 2, b_banana: 3 }

// If you actually want to keep every colliding source key,
// fold manually so you can decide the merge strategy:
const grouped = Object.entries(fruits).reduce((acc, [key, value]) => {
  const bucket = key[0];
  (acc[bucket] ||= []).push({ key, value });
  return acc;
}, {});
// -> {
//      a: [{ key: "apple", value: 1 }, { key: "avocado", value: 2 }],
//      b: [{ key: "banana", value: 3 }]
//    }
Try it Yourself

📋 _.mapKeys vs related helpers

Topic_.mapKeys_.mapValuesNative Object.fromEntries
TransformsKeys (values copied)Values (keys copied)Both at once
Iteratee args(value, key, object)(value, key, object)([key, value])
Mutates inputNoNoNo
Shorthand supportYesYesNo (write the map function)
CollisionsLast winsN/A (keys preserved)Last wins

Use _.mapKeys when only keys change. Use _.mapValues when only values change. Reach for Object.fromEntries(Object.entries(obj).map(...)) when you want to rewrite keys and values in the same pass.

Pitfalls to avoid

Collisions

Silent overwrites on duplicate keys

The old reference’s key.slice(0, 1) example only worked because the source keys were already single characters. With real data that would lose values.

Default

Don’t rely on the default iteratee

Without an iteratee, each value becomes the new key. Only meaningful if your values are already unique strings.

Types

Iteratee return is stringified

Numbers, booleans, and objects are all converted to strings when used as keys. Returning an object collapses to "[object Object]".

Iteration

Inherited and symbol keys are skipped

Only own enumerable string-keyed properties are processed. Bring symbols or prototype properties forward manually if you need them.

❓ FAQ

It is called with (value, key, object) for each own enumerable string-keyed property. The return value is coerced to a string and used as the new key.
No. It always returns a new object. The original source is untouched, which makes it safe for selectors and memoized helpers.
Last write wins. The most recently iterated key overwrites earlier ones silently, with no warning. Validate your iteratee or include the original key in the new name to avoid collisions.
Like other Lodash collection methods, the iteratee can be a function, a property name string, a [path, value] array, or an object matcher. Functions are the most common choice for key transformation.
Rarely. Without an iteratee, _.identity is used, which means each value becomes the new key. That only makes sense when values are unique strings. Always pass an explicit iteratee for key transformation.
_.mapKeys rewrites keys and keeps values; _.mapValues keeps keys and rewrites values. Both return a new object and iterate over own enumerable string-keyed properties.

Summary

Did you know?

_.mapKeys keeps the values intact and only rewrites the keys. If two transformed keys collide, the later iteration wins—silently. Sanitize your iteratee or use a unique-prefix strategy when collisions are possible.

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