console.table() - Debug Arrays Like a Human
Format arrays and objects as readable tables in your browser console.
No third-party tools. No endless console.log() scrolling. Just data you can actually read.
Live demo
Click the button to log the sample data to your browser console (open DevTools to see it).
const users = [
{ id: 1, name: "Alice", role: "Developer", active: true },
{ id: 2, name: "Bob", role: "Designer", active: true },
{ id: 3, name: "Charlie", role: "Manager", active: false }
];
console.table(users);💡 Open your browser DevTools (F12 or Cmd+Option+I) to see the formatted table
Before vs After
> console.log(users)
(3) [{…}, {…}, {…}]
0: {id: 1, name: 'Alice', ...}
1: {id: 2, name: 'Bob', ...}
2: {id: 3, name: 'Charlie', ...}
length: 3
[[Prototype]]: Array(0)Collapsed by default. Have to expand each object manually. Hard to scan.
| (index) | id | name | role | active |
|---|---|---|---|---|
| 0 | 1 | "Alice" | "Developer" | true |
| 1 | 2 | "Bob" | "Designer" | true |
| 2 | 3 | "Charlie" | "Manager" | false |
Formatted as a table. All data visible at once. Easy to compare values.
Practical use cases
API responses
fetch('/api/users')
.then(r => r.json())
.then(users => console.table(users));Performance timings
const timings = performance.getEntriesByType('measure');
console.table(timings, ['name', 'duration']);Form validation errors
const errors = formik.errors;
console.table(errors);💡 Browser support: All modern browsers. Works in Chrome, Firefox, Safari, Edge DevTools.
What is console.table()?
console.table() is a built-in method that prints arrays and objects as tables in DevTools.
Instead of:
console.log(users); // [{…}, {…}, {…}] – collapsed by default
You get:
console.table(users); // ┌─────────┬────┬───────────┬─────────────┬────────┐ // │ (index) │ id │ name │ role │ active │ // ├─────────┼────┼───────────┼─────────────┼────────┤ // │ 0 │ 1 │ 'Alice' │ 'Developer' │ true │ // │ 1 │ 2 │ 'Bob' │ 'Designer' │ true │ // │ 2 │ 3 │ 'Charlie' │ 'Manager' │ false │ // └─────────┴────┴───────────┴─────────────┴────────┘
All rows visible. Columns aligned. Your eyes do less work.
Why this matters
Most debugging sessions start with console.log() and never really evolve.
For single values, that is fine:
console.log(user.name); // "Alice"
For arrays of objects, you get this:
console.log(users); // (3) [{…}, {…}, {…}] // ▸ 0: {id: 1, name: "Alice", role: "Developer", active: true} // ▸ 1: {id: 2, name: "Bob", role: "Designer", active: true} // ▸ 2: {id: 3, name: "Charlie", role: "Manager", active: false}
Collapsed by default. Click to expand. Scroll. Forget which object you were looking at.
console.table() is the "what if we did not suffer" version:
console.table(users);
Same data, but you can actually compare values across rows at a glance.
Basic usage
Array of objects
const users = [ { id: 1, name: "Alice", email: "alice@example.com" }, { id: 2, name: "Bob", email: "bob@example.com" }, { id: 3, name: "Charlie", email: "charlie@example.com" }, ]; console.table(users);
DevTools renders a table with columns for id, name, and email.
Single object
const user = { id: 1, name: "Alice", email: "alice@example.com", role: "Developer", }; console.table(user);
Keys become the first column. Values become the second.
Show only specific columns
If each object has many properties, you can limit the output:
console.table(users, ["name", "email"]);
Only the selected keys appear as columns. Useful when you know what you are hunting for.
Real-world use cases
API responses
You fetch data from an API and want to confirm the shape and a few key fields.
Before:
fetch("/api/users") .then((r) => r.json()) .then((users) => console.log(users));
You get a long list of collapsed objects.
After:
fetch("/api/users") .then((r) => r.json()) .then((users) => console.table(users));
Now you see every row, can scroll through the table, and spot missing or odd values immediately.
Performance timings
Using the Performance API:
const timings = performance.getEntriesByType("measure"); // Harder to scan console.log(timings); // Easier to scan console.table(timings, ["name", "duration"]);
You get a clean table showing each measurement and its duration.
Form validation errors
Large forms can generate many errors:
console.table(formik.errors);
Field names in one column, error messages in another. Easier than digging through nested objects.
State diffs
To see what actually changed:
const changes = [ { field: "name", before: "Alice", after: "Alice Johnson" }, { field: "role", before: "Developer", after: "Senior Developer" }, ]; console.table(changes);
Side-by-side comparison, no mental join required.
When NOT to use console.table()
console.table() is great for structured data, but it is not the answer to every logging problem.
Skip it for:
- Single values -
console.log(42)is enough - Deeply nested objects - tables are flat; use
console.log()orconsole.dir()instead - Huge datasets - DevTools will truncate after a certain number of rows; for large arrays, filter first
- Non-tabular data - strings, functions, and DOM nodes are usually clearer with
console.log()
Use it for:
- Arrays of objects
- Lists of errors or warnings
- Performance metrics
- Anything where you mostly care about comparing columns across rows
If it looks like a spreadsheet in your head, console.table() is probably a good fit.
Browser and Node support
console.table() works in all modern browsers:
- Chrome
- Firefox
- Safari
- Edge
It has been in DevTools for more than a decade. If someone can open the console, they can use console.table().
Node.js also supports it (v10+):
const data = [ { id: 1, label: "one" }, { id: 2, label: "two" }, ]; console.table(data);
Same tabular output, just in the terminal.
Performance
Formatting a table is slightly more work than printing raw objects, so console.table() is a bit slower than console.log().
For normal debugging, the difference is irrelevant. You are inspecting dozens of rows, not running a trading bot.
If you are logging from inside a hot loop, collect your data first and print once:
const snapshots = []; for (let i = 0; i < 1000; i++) { snapshots.push({ i, value: expensiveComputation(i) }); } console.table(snapshots);
Readable and still cheap.
Tips and tricks
Combine with filtering
const activeUsers = users.filter((u) => u.active); console.table(activeUsers, ["id", "name", "role"]);
Show only the rows and columns you care about.
Add computed columns
const usersWithFlags = users.map((u) => ({ ...u, isAdmin: u.role === "Admin", })); console.table(usersWithFlags, ["name", "role", "isAdmin"]);
Pre-compute whatever you want to compare, then log once.
Keep it out of production (or not)
Most build setups strip console.* calls in production. If you want to keep console.table() around for admin/debug pages, gate it:
if (process.env.NODE_ENV !== "production") { console.table(users); }
Or route it through your own logger with levels.
Try it yourself
Open DevTools (F12 or Cmd+Option+I) and paste:
const users = [ { id: 1, name: "Alice", role: "Developer", active: true }, { id: 2, name: "Bob", role: "Designer", active: true }, { id: 3, name: "Charlie", role: "Manager", active: false }, ]; console.log(users); console.table(users);
Look at the two outputs next to each other. One is noise. One is information.
Resources
- MDN: console.table() - official documentation
- Chrome DevTools: Console API - full console API reference
Copy. Paste. Debug. Your logs just became boringly readable.