window-size review
window-size 1.1.1 is a 2018 CommonJS helper that reports terminal width and height. Importing it immediately checks stdout, stderr, `COLUMNS` and `ROWS`, then an old TTY fallback. Version 1.1.1 fixes `.tput()` so it reads the active terminal instead of repeatedly returning 80 by 24. A successful export is a snapshot with `width`, `height`, an undocumented source `type`, and helper methods. If every probe fails, the export is `undefined` and those methods disappear. Current Node exposes ordinary TTY dimensions directly on its streams.
window-size 1.1.1 took 1 second but pulled 10 packages into our 1 MB sandbox install, and its browser bundle failed; npm has not released it since 2018. Do not add it to a current Node CLI when stream columns and rows are enough. Retain it only where legacy fallback behavior is an explicit compatibility requirement.
We installed it
| Install | ✓ · 1s | 10 packages on disk · 1 MB |
| Import | ✓ | ESM import works · require() works · CommonJS package |
| Browser | n/a | could not be bundled for the browser (Node-only code, most likely) |
| Types | — | no TypeScript types found |
| Known vulns | 0 | 0 critical · 0 high · 0 moderate · 0 low (npm audit) |
Answers from our run
Does window-size install cleanly?
Yes. In a fresh container with an empty cache, npm install window-size finished in 1 seconds, leaving 10 packages and 1 MB on disk. npm audit reported no known vulnerabilities.
Can window-size run in a browser?
Not directly: esbuild could not bundle it for the browser in our run, which normally means it depends on Node built-ins. Use it on the server, or find a browser-targeted alternative.
Does window-size work with both ESM and CommonJS?
Yes. Both import 'window-size' and require('window-size') worked in Node 22 in our run. The package is published as CommonJS.
Does window-size include TypeScript types?
No type declarations were found in our install, so TypeScript users need their own declarations.
window-size or term-size: which should you use?
term-size: Use it when a current package with explicit terminal fallbacks is preferable to local stream checks. window-size 1.1.1 took 1 second but pulled 10 packages into our 1 MB sandbox install, and its browser bundle failed; npm has not released it since 2018.
When should you not use window-size?
The CLI targets current Node. process.stdout.columns, rows, getWindowSize(), and the stream resize event cover the ordinary TTY case without 10 installed packages.
Use it if
- A legacy CommonJS CLI must retain this package's exact fallback order and `{ width, height, type }` shape.
- Very old supported Node versions make direct stream dimension handling inconsistent.
- A controlled non-TTY environment always provides numeric `COLUMNS` and `ROWS` values.
- Replacing a transitive dependency would change tested output wrapping in an older tool.
- The CLI targets current Node. `process.stdout.columns`, `rows`, `getWindowSize()`, and the stream `resize` event cover the ordinary TTY case without 10 installed packages.
- The program runs under CI, pipes, or redirected output without fixed size variables. The default export may be `undefined`, and even `.get()` is then absent.
- You need a reliable Windows terminal fallback. The `.win()` source invokes WMIC for `Win32_VideoController`, which describes display resolution rather than console character cells.
- Synchronous external commands are unacceptable. `.tput()` blocks with `execSync`, depends on terminal database state, and suppresses failures by returning `undefined`.
- Maintained types and module metadata matter. Version 1.1.1 has no declarations or exports map, and npm has not published an update since July 2018.
Setup reality
We installed window-size 1.1.1 in 1 second in a fresh Node 22 Bookworm sandbox. It left 10 packages and 1 MB on disk. The package has 2 direct dependencies, no peers, a 32 KB unpacked size, an MIT license, and a declared Node floor of 0.10. npm audit found 0 known vulnerabilities. Our CommonJS require() and ESM import checks worked, and no TypeScript declarations were present.
There are no credentials, native builds, or config files. The package is CommonJS without an exports map. Our browser bundle failed because it reads Node TTY, process, OS, and child-process APIs. Import timing is the bigger surprise: measurement happens while the module loads, and the export is either a size object or undefined. Methods such as .get() and .tput() are attached only after that first probe succeeds. Import window-size/utils directly if you truly need helpers when no initial size exists.
The default order checks process stdout, process stderr, environment variables, then the legacy TTY API. COLUMNS and ROWS count only when both pass the package's number check. Resizing is not observed automatically; attach a resize listener to stdout and call .get() again. The README warns that some platforms expose only the initial value, so layout code still needs a bounded fallback and must tolerate stale dimensions.
Two explicit helpers are poor recovery mechanisms. .tput() synchronously runs Unix commands, blocks the event loop, and returns undefined on failure. .win() synchronously invokes WMIC only on a narrow Windows release check and reads video-controller resolution, not terminal rows and columns. The bundled window-size executable accesses fields without guarding an undefined result. For modern Node, a small function around stream.isTTY, columns, and rows is easier to test and avoids these paths.
Patterns
Guard the import-time size read-import-snapshot
const size = require('window-size');
if (size) {
console.log(size.width, size.height, size.type);
} else {
console.log('terminal size unavailable');
}The main export can be `undefined`. When present, `type` identifies the winning probe even though the primary README shape omits it.
Recheck dimensions safely refresh-size
const size = require('window-size');
const current = size?.get();
if (current) render(current.width, current.height);`.get()` exists only when import found an initial size. Optional access is required under pipes and other non-TTY environments.
Redraw on stdout resize handle-resize
const size = require('window-size');
if (size && process.stdout.isTTY) {
process.stdout.on('resize', () => {
const current = size.get();
if (current) redraw(current.width, current.height);
});
}Version 1.1.1 does not register the listener. Some platforms still report only the dimensions captured when the terminal started.
Query COLUMNS and ROWS directly read-size-environment
const utils = require('window-size/utils');
const dimensions = utils.env();
if (dimensions) console.log(dimensions.width, dimensions.height);Both environment values must be numeric. Set both explicitly in CI if deterministic wrapping depends on them.
Access helpers when the main export failed load-utils-without-size
const size = require('window-size');
const utils = require('window-size/utils');
const current = size || utils.env();Direct `utils` import bypasses the conditional method attachment. Avoid automatically falling through to synchronous platform commands.
Call the Unix fallback explicitly query-tput
const { tput } = require('window-size/utils');
const size = tput();
if (size) console.log(`${size.width}x${size.height}`);`.tput()` blocks with `execSync`, needs the `tput` command and terminal database, and returns `undefined` when its command fails.
Supply predictable CI dimensions provide-ci-size
// Run with: COLUMNS=120 ROWS=40 node report.js
const size = require('window-size');
const width = size?.width ?? 80;
renderReport(width);stdout and stderr probes run before environment fallback. Keep the 80-column application default because environment input can still be absent.
Clamp a detected width bound-layout-width
const size = require('window-size');
const detected = size?.width ?? 80;
const contentWidth = Math.max(20, Math.min(detected - 4, 120));
printWrapped(message, contentWidth);Terminal dimensions can be missing, stale, or unreasonable. A 20-to-120 range prevents negative and extremely wide layouts.
Replace the package on current Node use-node-stream-size
function terminalSize(stream = process.stdout) {
if (!stream.isTTY) return undefined;
if (!Number.isInteger(stream.columns) || !Number.isInteger(stream.rows)) return undefined;
return { width: stream.columns, height: stream.rows };
}This avoids the 10-package install, import snapshot, old TTY fallback, and Windows display-resolution query measured in version 1.1.1.
Track size with built-in stream properties observe-node-resize
function redrawFrom(stream) {
const width = stream.isTTY && stream.columns ? stream.columns : 80;
redraw(width);
}
redrawFrom(process.stdout);
process.stdout.on('resize', () => redrawFrom(process.stdout));Use a fallback under redirected output. The built-in resize event and current `columns` value remove the need for window-size's cached object.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| term-size | npm | Use it when a current package with explicit terminal fallbacks is preferable to local stream checks. |
| terminal-size | npm | Use it for a Promise-based cross-platform query that can call platform tools when needed. |
| cli-width | npm | Use it when only column count matters for text wrapping and horizontal layout. |
| get-stdin | npm | Use it when the actual requirement is reading piped input rather than measuring a terminal. |
More cli & tooling guides
chalk · commander · typescript · esbuild · yargs · click · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

