mrkeyoor.com_
Sat 08 Aug 20:59 UTC
npmCLI & Toolingupdated 08 Aug 2026

easy-table

easy-table is a small CommonJS formatter for aligned plain-text tables in Node.js command-line programs. You add named cells to a current row, close the row, then render headers, delimiter lines, body rows, and optional totals. It can also print arrays or objects directly, sort rows, transpose a record into key/value lines, right-align fixed-decimal numbers, and use custom two-pass cell printers. Width calculation strips ANSI escape sequences and optionally uses wcwidth for wide Unicode characters.

Verdict

easy-table still does clean, borderless reports with very little code, but its long release gap makes it a maintenance-risk choice for new projects. Pick it only when this exact small API fits; choose `table` or `cli-table3` for richer output and more active stewardship.

API stability5/5The API has barely moved: the current 1.2.0 package keeps the constructor, cell and newRow workflow, static print helper, sorting, totals, and printer contracts documented for years. That makes existing scripts predictable. The score reflects low change risk, not active design investment, and CommonJS-only packaging limits how naturally it fits modern module systems.
Docs3/5The README explains the main row workflow, two-pass printer contract, static printing, sorting, totals, installation, and output for each example. The complete implementation is small enough to inspect. There is no separate reference site, several details such as missing cells and multiline behavior require source reading, and a sample options object even omits a comma between properties.
Maintenance2/5The repository is not archived and was pushed in February 2025, but npm 1.2.0 dates to October 2021 and no release has followed. GitHub reports five open issues and pull requests, a small queue, while dependencies remain on older major lines. A tiny stable formatter may need little churn, but new adopters should assume slow fixes and own an exit plan.
Ecosystem3/5The package recorded 5,420,336 npm downloads for the week ending 2026-08-06, likely helped by transitive CLI use, and ships TypeScript declarations. It understands ANSI width and optionally Unicode terminal width. Its 315-star repository, CommonJS-only export, and narrow plain-text feature set make the surrounding ecosystem much smaller than `table` or `cli-table3`.

Use it if

  • You need a dependency-light table string for a Node CLI and borders, colors, wrapping, and streaming are unnecessary
  • Your rows are ordinary objects but you want column renaming and numeric alignment without building a formatter
  • You need built-in sorting and sum or average footer rows for a small report
  • You maintain CommonJS code and value an API small enough to understand from one README and one source file
Skip it if

Setup reality

`npm install easy-table` provides one CommonJS module, a declaration file, `ansi-regex`, and optional `wcwidth`. There is no initialization or config file. In CommonJS use `const Table = require('easy-table')`; TypeScript's bundled `export = EasyTable` shape works naturally with `import Table = require('easy-table')`, while default ESM imports depend on `esModuleInterop` or your runtime's CommonJS bridge. Rows are stateful. Calling `cell()` only fills the current row, and you must call `newRow()` or nothing is committed for output. Missing columns render blank, while column order is inferred from the order keys first appear across committed rows. Every custom printer runs twice: once without a width to measure, then again with the chosen column width to render. It must be deterministic and side-effect-free, and it should return a string both times. `Table.number(digits)` rejects non-number values but renders null and undefined as blank; convert numeric strings before adding them. ANSI escape sequences are removed for width measurement, but display-width accuracy for CJK and other wide characters relies on optional `wcwidth`. The formatter does not wrap or sanitize newlines, so multiline values break the one-row-per-line layout. `toString()` adds headings and dashed separators, `print()` emits body rows only, and `printTransposed()` turns columns into rows. The static `Table.print()` overload behaves differently for arrays and single objects: arrays become a normal headed table, while one object becomes a transposed key/value view. Sorting mutates the stored row order. Descending keys use the library's documented `|des` suffix, not the more obvious `|desc`. Totals are computed at render time from raw stored values, so mixing missing values or strings with the default sum reducer can produce unwanted coercion.

Patterns

Build a table row by rowrender-basic-table

const Table = require('easy-table')

const table = new Table()
for (const user of users) {
  table.cell('ID', user.id)
  table.cell('Name', user.name)
  table.cell('Active', user.active ? 'yes' : 'no')
  table.newRow()
}

process.stdout.write(table.toString())

cell only updates the current row. Call newRow after every record or that record will not appear in the rendered table.

Right-align fixed-decimal valuesformat-decimal-numbers

const table = new Table()
for (const invoice of invoices) {
  table.cell('Invoice', invoice.id)
  table.cell('Amount', invoice.amount, Table.number(2))
  table.newRow()
}
console.log(table.toString())

Table.number accepts actual numbers. Numeric strings throw; null and undefined are rendered as blank cells.

Render an array without manual rowsprint-object-array

const output = Table.print(products, {
  sku: { name: 'SKU' },
  description: { name: 'Description' },
  price: { name: 'Price', printer: Table.number(2) },
})

console.log(output)

Static print enumerates each object's own enumerable keys. Normalize nested values before passing domain objects directly.

Render one object as key/value rowsprint-key-value-object

console.log(Table.print({
  version: '1.4.0',
  environment: 'production',
  healthy: true,
}))

A single object is printed transposed with ` : ` separators, unlike an array, which gets a normal header row.

Omit headers and delimiter rowsrender-body-only

const table = new Table()
for (const row of rows) {
  table.cell('left', row.label)
  table.cell('right', row.value)
  table.newRow()
}
process.stdout.write(table.print())

Instance print emits committed body rows only. Use toString when you want column headings and dashed separators.

Customize spacing between columnschange-column-separator

const table = new Table()
table.separator = ' | '
table.cell('Name', 'api').cell('State', 'ready').newRow()
table.cell('Name', 'worker').cell('State', 'busy').newRow()
console.log(table.toString())

separator is the only built-in border control. easy-table does not draw vertical or outer borders for you.

Sort by multiple stored columnssort-table-rows

table
  .sort(['Status|asc', 'Duration ms|des'])
  .log()

Sorting mutates the table's rows. The descending suffix is `|des`, exactly as documented, not `|desc`.

Apply a custom row comparatorsort-with-comparator

table.sort((a, b) => {
  const severity = { error: 0, warning: 1, info: 2 }
  return severity[a.Level] - severity[b.Level]
})

console.log(table.toString())

Comparator arguments are the internal row objects keyed by the exact column labels passed to cell.

Add a sum footeradd-column-total

const table = new Table()
for (const item of items) {
  table.cell('Item', item.name)
  table.cell('Cost', item.cost, Table.number(2))
  table.newRow()
}

table.total('Cost', { printer: Table.number(2) })
console.log(table.toString())

The default reducer uses addition on raw cell values. Missing or string costs can coerce the accumulator unexpectedly.

Render an average with a labeladd-average-footer

table.total('Latency', {
  reduce: Table.aggr.avg,
  init: 0,
  printer: Table.aggr.printer('Avg: ', Table.number(1)),
})

console.log(table.toString())

Totals appear only in toString output and only when at least one committed row exists.

Create a deterministic cell printerwrite-custom-printer

function percent(value, width) {
  const text = `${(value * 100).toFixed(1)}%`
  return width ? Table.padLeft(text, width) : text
}

table.cell('Success', 0.973, percent).newRow()

A printer is called twice: first without width for measurement, then with width for rendering. Avoid side effects and return the same content shape.

Import the CommonJS package in TypeScriptuse-from-typescript

import Table = require('easy-table')

const table = new Table()
table.cell<number>('Count', 42, Table.number(0)).newRow()
console.log(table.toString())

The bundled declarations use `export = EasyTable`. A default import needs esModuleInterop or an equivalent bundler setting.

Alternatives

PackageRegistryPick it when
cli-table3npmYou want borders, colored cells, spanning, wrapping, and a maintained fork of the classic cli-table API
tablenpmYou need configurable borders, alignment, column widths, truncation, and word wrapping
ascii-tablenpmYou want a simple bordered ASCII table and can accept another old, minimal package
cli-tablenpmYou inherit code already using the original cli-table API and cannot migrate immediately