Object.entries()

ES2017+

Returns an array of a given object's own enumerable string-keyed [key, value] pairs, in the same order as Object.keys(). It is the bridge between objects and array iteration, enabling destructuring loops, Map construction, and filter-then-rebuild transformations with Object.fromEntries().

Syntax

Object.entries(obj)

Parameters

obj Object

The object whose enumerable own property [key, value] pairs are to be returned

Return Value

Array

An array of [key, value] pairs

Examples

JavaScript
const obj = { a: 1, b: 2 };
console.log(Object.entries(obj));
Output:
// [['a', 1], ['b', 2]]

📌 When to Use

Use Object.entries() when a transformation needs to see both the key and the value at once. It is the backbone of the filter-map-rebuild pattern: spread an object into pairs, reshape them with array methods, then reassemble with Object.fromEntries(). Reach for it when renaming or normalizing keys (snake_case to camelCase), stripping entries whose values are undefined before serializing, whitelisting or blacklisting fields, inverting a lookup table, or converting a plain object into a Map to gain non-string keys and size tracking. In UI code, for (const [label, value] of Object.entries(stats)) renders definition lists and tables without hardcoding field names. It also makes objects usable with array destructuring in for...of loops, which reads far more clearly than indexing entry[0] and entry[1] manually. If a task touches only one side of the pair, prefer Object.keys() or Object.values() — they allocate less and state your intent more precisely. And when data is naturally key-value from the start and heavily mutated at runtime, consider using a Map directly instead of repeatedly converting back and forth through entries().

⚠️ Common Mistakes

Calling Object.entries() inside nested loops over the same object - every call rebuilds all the pair arrays from scratch. Cache the result in a variable before a double loop, or restructure the algorithm; otherwise an O(n) allocation silently becomes O(n * m) and shows up in profiles as mysterious garbage-collection time.

Round-tripping through Map and expecting non-string keys to survive - new Map(Object.entries(obj)) always produces string keys because object keys are strings, but a Map built elsewhere may hold number or object keys, and Object.fromEntries() will coerce them to strings on the way back. The object-to-Map direction is lossless; the reverse is not.

Assuming numeric-looking keys come back in insertion order - integer-like keys are enumerated first in ascending numeric order, so Object.entries({ b: 1, 10: 2, 2: 3 }) starts with ["2", 3] and ["10", 2] before ["b", 1]. Code that zips entries against another insertion-ordered list will silently misalign.

Forgetting to destructure the [key, value] pair in callbacks: use ([key, value]) => ... not (entry) => entry[0], entry[1].

Not realizing that modifying the returned arrays does not affect the original object - entries are snapshots, not live references.

Using Object.entries() when only keys or values are needed - it creates unnecessary [key, value] arrays that waste memory.

✅ Best Practices

Invert small lookup tables in one line: Object.fromEntries(Object.entries(codes).map(([k, v]) => [v, k])) - handy for bidirectional enums like status-code maps, without maintaining two hand-written objects that can drift apart over time.

Strip noise before serializing: Object.fromEntries(Object.entries(payload).filter(([, v]) => v !== undefined && v !== null)) produces clean API bodies and avoids sending keys that the backend would treat as explicit nulls rather than omissions.

Use with for...of and destructuring for clean iteration: for (const [key, value] of Object.entries(obj)) { ... }

Combine with Object.fromEntries() for object transformations: Object.fromEntries(Object.entries(obj).filter(...))

Convert objects to Maps easily: new Map(Object.entries(obj)) preserves key-value relationships with Map benefits.

⚡ Performance Notes

Object.entries() is the most expensive of the three enumeration helpers because it allocates one outer array plus a fresh two-element array per property — O(n) time with roughly double the allocation of Object.keys(). For a handful of keys this is irrelevant, but in tight loops or per-frame rendering the extra garbage adds up; hoist the call outside loops and reuse the result while the object is stable. The filter-map-fromEntries pipeline also creates intermediate arrays at each stage — fine at config scale, worth flattening into a single reduce() when processing thousands of objects. If you find yourself calling entries() on the same object repeatedly just to look values up, that object probably wants to be a Map, whose entries() iterator yields pairs lazily without materializing the whole list up front.

🌍 Real World Example

Environment Variable Parser

This configuration parser shows the full entries pipeline on realistic environment-variable data. One pass filters entries down to DB_-prefixed keys and simultaneously renames them into a clean lowercase config shape; a second pass converts "true" and "false" strings into real booleans across the whole object. Both transformations need keys and values together, which is exactly the case Object.entries() exists for, and both rebuild plain objects with Object.fromEntries() so the rest of the app consumes ordinary config objects.

const config = {
  DB_HOST: 'localhost',
  DB_PORT: '5432',
  DB_NAME: 'myapp',
  API_KEY: 'secret123',
  DEBUG: 'true'
};

// Filter only DB-related config
const dbConfig = Object.fromEntries(
  Object.entries(config)
    .filter(([key]) => key.startsWith('DB_'))
    .map(([key, value]) => [key.replace('DB_', '').toLowerCase(), value])
);

console.log(dbConfig);
// { host: 'localhost', port: '5432', name: 'myapp' }

// Convert string booleans to actual booleans
const typedConfig = Object.fromEntries(
  Object.entries(config).map(([key, value]) => [
    key,
    value === 'true' ? true : value === 'false' ? false : value
  ])
);

console.log(typedConfig.DEBUG);
// true (boolean)

Related Methods