Object.fromEntries()
ES2019+Transforms a list of [key, value] pairs — from an array, a Map, URLSearchParams, or any iterable — into a new plain object. It is the inverse of Object.entries() and the final step of the filter-map-rebuild pattern for immutable object transformations.
Syntax
Object.fromEntries(iterable)Parameters
iterable Iterable An iterable such as Array or Map containing key-value pairs
Return Value
A new object whose properties are given by the entries
Examples
const entries = [['a', 1], ['b', 2]];
console.log(Object.fromEntries(entries)); 📌 When to Use
Use Object.fromEntries() whenever data arrives as key-value pairs but the rest of your code wants a plain object. The three canonical sources are: the output of Object.entries() after array transformations (completing the entries-transform-fromEntries round trip), Map instances that must become JSON-serializable objects, and URLSearchParams when parsing a query string into an options object in one line. It also converts arrays of tuples produced by zip-style logic — for example pairing a list of column names with a row of values from a CSV — into records. Because it builds a brand-new object, it fits immutable update patterns: derive a filtered or renamed variant of a config without touching the original, then store the result in state safely. Prefer it over a manual reduce((acc, [k, v]) => { acc[k] = v; return acc; }, {}) loop, which does the same thing with more ceremony and more room for mistakes. Skip the round trip entirely when a single known property changes — a spread with an override like { ...obj, name: value } is simpler and faster than decomposing and rebuilding the whole object from entries.
⚠️ Common Mistakes
Expecting deep conversion of nested Maps - Object.fromEntries(map) only converts the top level. If the values are themselves Maps, or contain Maps, they stay Maps inside the result; write a recursive converter when you need a fully plain-object tree for JSON serialization.
Losing data when converting URLSearchParams with repeated keys - a query like "?tag=a&tag=b" collapses to { tag: "b" } because later pairs overwrite earlier ones. Use params.getAll("tag") for multi-value parameters instead of relying on the fromEntries result alone.
Passing an array without proper [key, value] structure - each element must be a two-element array or the conversion will fail.
Forgetting that duplicate keys will be overwritten - the last occurrence wins, just like object literal behavior.
Not handling non-string keys - Object.fromEntries() converts all keys to strings, which may cause unexpected behavior with Symbol or number keys.
✅ Best Practices
Build objects from parallel arrays by zipping first: Object.fromEntries(headers.map((h, i) => [h, row[i]])) turns CSV headers and a data row into a record object without an index-juggling loop, and reads as a single declarative statement.
Keep the entries round trip pure - inside the map() step, return new [key, value] tuples rather than mutating shared values, so the rebuilt object is a true independent snapshot at the top level and safe to store in application state.
After building objects from external pair data, freeze or validate before sharing: Object.freeze(Object.fromEntries(pairs)) hands consumers a locked snapshot, and running the result through a schema validator catches surprises like duplicate keys collapsing or numeric keys being reordered - cheap insurance at module boundaries where pair-shaped data enters from CSV parsers, query strings, or spreadsheets.
Use the entries-transform-fromEntries pattern for immutable object updates: Object.fromEntries(Object.entries(obj).map(...))
Parse URL parameters elegantly: Object.fromEntries(new URLSearchParams(queryString))
Convert Map to object when you need JSON serialization or object-specific operations.
⚡ Performance Notes
Object.fromEntries() runs in O(n) and creates one new object plus a property store sized to the entries. The cost that dominates in practice is the pipeline around it: Object.entries() allocates pair arrays, map() and filter() allocate intermediate arrays, and fromEntries() walks the final list. At config-object scale (tens of keys) this is negligible; when transforming thousands of records per frame, collapse the pipeline into a single reduce() or a plain for loop that assigns onto an accumulator object to cut allocations several-fold. Building many objects with identical keys in identical order also helps the engine share hidden classes between them, keeping downstream property access monomorphic and fast — another reason to keep transformation pipelines deterministic about key order rather than conditionally adding keys.
🌍 Real World Example
URL Query String Parser
This snippet turns a raw URL query string into a typed, safe options object in three explicit stages. URLSearchParams handles the percent-decoding and Object.fromEntries() converts it into a plain object; a filter pass then removes sensitive parameters like tokens before the object is logged or stored; finally a map pass converts numeric strings into real numbers. Each stage is a standalone entries round trip, so you can lift any of them into reusable helpers and apply the same pipeline to other endpoints.
const url = 'https://example.com?page=1&sort=date&token=abc123&limit=10';
const queryString = url.split('?')[1];
// Parse query string to object
const params = Object.fromEntries(new URLSearchParams(queryString));
console.log(params);
// { page: '1', sort: 'date', token: 'abc123', limit: '10' }
// Filter out sensitive parameters
const sensitiveKeys = ['token', 'password', 'secret'];
const safeParams = Object.fromEntries(
Object.entries(params).filter(([key]) => !sensitiveKeys.includes(key))
);
console.log(safeParams);
// { page: '1', sort: 'date', limit: '10' }
// Convert string numbers to actual numbers
const typedParams = Object.fromEntries(
Object.entries(safeParams).map(([key, value]) => [
key,
!isNaN(value) ? Number(value) : value
])
);
console.log(typedParams);
// { page: 1, sort: 'date', limit: 10 }