npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tidyports/guard

v0.2.0

Published

When a dev server can't bind, say who is holding the port instead of just EADDRINUSE.

Readme

@tidyports/guard

EADDRINUSE tells you a port is taken. It never tells you by what.

Put this in front of your dev command and the error answers the actual question:

$ tidyports-guard npm run dev

Error: listen EADDRINUSE: address already in use :::3000

:3000 is held by Claude Code, in Ghostty [PID 12345] in acme-web (feature/auth)

  [1] use 3001 instead
  [2] stop it (asks again first)
  [enter] leave it

Pick 1 and the port lands on your clipboard. Enter leaves everything alone, so a stray keystroke never stops anyone's server.

Naming the owner matters most when an agent is reading it. An agent that hits a port conflict and can't tell it from a bug will often "fix" working code to get around the port — usually by editing your app's configuration. Naming the owner is what makes the conflict legible as a conflict.

When you get the choice, and when you don't

Not everything dies when it can't bind. Vite prints Port 5173 is in use and carries on at 5174, and a prompt underneath a live dev server would be competing with its output for the same terminal. So the choice appears only once the command has actually exited and the terminal is free.

If it's still running — or you're piped, in CI, or an agent is reading — you get the same answer as plain text instead, and nothing ever waits for input:

[tidyports] :3000 is held by Claude Code, in Ghostty [PID 12345] in acme-web (feature/auth)
To take a different port:  PORT=$(tidy-ports alloc web)
To stop it:                tidy-ports kill --match 3000

Use it

npx @tidyports/guard npm run dev

Or wire it into the script you already run:

{
  "scripts": {
    "dev": "tidyports-guard vite"
  }
}

It needs the TidyPorts CLI on your PATH to name the owner. Without it you get a one-line note instead, and nothing else changes.

What it does to your dev loop

Nothing, by design. It is a wrapper around a command you already run, so it is worth being precise about what it does not touch:

  • stdout stays a TTY. Only stderr is intercepted, and every chunk is written through before it's even inspected — so your dev server keeps its colour and its interactive keys.
  • Exit codes and signals are reproduced exactly, including the terminating signal, so a shell, a CI step or an agent reading the status sees what it would have seen anyway.
  • Ctrl-C still works. SIGINT, SIGTERM and SIGHUP are forwarded to the child.
  • Nothing is added on success. The message appears only when a bind actually failed, once, and never again for the same run.

What it understands

The message is different in every ecosystem, so it matches the wording rather than the language:

| | | |---|---| | Node | listen EADDRINUSE: address already in use :::3000 | | Vite | Port 5173 is in use | | Flask / Python | Address already in use + Port 5000 is in use | | Rails / Puma | bind(2) for "127.0.0.1" port 3000 | | Go | listen tcp :8080: bind: address already in use | | Docker | Bind for 0.0.0.0:5432 failed: port is already allocated |

Lines that merely mention a port are deliberately ignored. A false positive would send you after the wrong process, which is worse than staying quiet.

Tests

npm test

Covers the patterns above — including the ones that must not match — and the wrapper's behaviour: exit codes, stderr passthrough, and a real bind failure.

Licence

MIT