Open URLs, files, and executables. Cross-platform, ESM + CJS, dependency-free, CLI included.
Open URLs, files, and executables in their default (or a chosen) app, from Node.js or the command line — macOS, Windows, Linux, and WSL, as a single package with both a library and a bundled CLI.
npm install betteropenFor just the CLI:
npm install --global betteropenimport open, { openApp, apps } from 'betteropen'
// Opens the URL in the default browser.
await open('https://example.com')
// Opens a file in its default app, waiting for that app to exit.
await open('./document.pdf', { wait: true })
// Opens the URL in a specific app.
await open('https://example.com', { app: { name: 'firefox' } })
// Opens the default browser in private/incognito mode.
await open('https://example.com', { app: { name: apps.browserPrivate } })
// Launches an app directly, without a target.
await openApp(apps.chrome, { arguments: ['--incognito'] })open(target, options?) and openApp(name, options?) both resolve to the spawned ChildProcess. options accepts wait, background (macOS), newInstance (macOS), app/arguments, and allowNonzeroExitCode — see the type definitions shipped with the package for the full reference.
apps gives you the platform-correct binary name for a handful of well-known browsers (lazily resolved, so nothing is spawned until you actually read a property):
apps.chrome
apps.brave
apps.firefox
apps.edge
apps.safari
apps.opera
apps.vivaldi
apps.chromium
apps.browser // the OS default browser
apps.browserPrivate // the OS default browser, in private/incognito modeInstalled as betteropen, open-cli, and opencli (not just plain open, since that would shadow macOS's built-in open command):
betteropen https://example.com
betteropen https://example.com -- firefox
betteropen document.pdf --wait
cat image.png | betteropen
echo '<h1>hi</h1>' | betteropen --extension=htmlRun betteropen --help for the full flag list.
Note
open-cli/opencli may still conflict with another package's bin of the same name if you have one installed globally.
A feature comparison against packages commonly reached for in this space — two that together cover roughly what betteropen does alone (a library plus a separate CLI wrapping it), and one minimal library covering just the basics. All four open URLs/files/executables cross-platform, so the table below focuses on where they actually differ:
| betteropen | open | open-cli | tiny-open | |
|---|---|---|---|---|
| Link | npm · GitHub | npm · GitHub | npm · GitHub | npm · GitHub |
| Library and CLI, one package | ✅ | library only | CLI only, depends on open |
library only |
| Node.js requirement | >= 20 (declared) | >= 20 | >= 22 | not declared |
| Default browser detection | ✅ | ✅ | via open |
— |
| Built-in browser shortcuts | 8 — Chrome, Brave, Firefox, Edge, Safari, Opera, Vivaldi, Chromium | 5 | via open |
— |
| Recognizes beta/dev/nightly/ESR browser channels as their base browser | ✅ | — | — | — |
wait / background / newInstance options |
✅ | ✅ | --wait/--background only |
— |
Returns the spawned ChildProcess |
✅ | ✅ | n/a | boolean only |
| Module format | ESM + CJS | ESM only | ESM only | ESM only |
| CLI stdin piping with type detection | ✅ | — | ✅ | — |
| Library runtime dependencies | 0 | 6 | — | 0 |
| CLI runtime dependencies | 2 | — | 4, including open itself |
— |
- Node.js >= 20
- On Linux, a graphical desktop environment — the bundled
xdg-openscript needs one of the usual desktop tools (gio,gvfs-open,kde-open,exo-open, ...) to actually hand off to an app.
- Opens URLs, files, and executables in the platform default app, or a specific one you choose.
- Works on macOS, Windows, Linux, and WSL (including launching Windows apps from WSL via PowerShell).
- Resolves the default browser, with built-in support for opening it in private/incognito mode, and recognizes it even on less common release channels (beta, dev, nightly, ESR, developer edition, ...).
- Includes shortcuts for Chrome, Brave, Firefox, Edge, Safari, Opera, Vivaldi, and Chromium out of the box.
- Ships a CLI in the same package, installed as both
betteropenandopen— no separate install needed. - Bundles a known-good
xdg-openfor Linux, falling back to the system's own copy when present. - Minimal footprint: OS integration has no dependencies of its own — the library itself pulls in nothing, and only the CLI adds two small dependencies (flag parsing and stdin type detection).
Contributions are welcome! See CONTRIBUTING.md for details.
Distributed under the MIT License.