How to Fix EADDRINUSE Address Already in Use Errors on Port 3000 5173 or 8080 Without Rebooting Your Machine
A practical guide to fixing EADDRINUSE and address already in use errors by finding the exact owning process, understanding why it stayed alive, and freeing the right port without killing unrelated work.
Why this problem keeps returning: the port conflict is rarely the whole bug. The real issue is usually an orphaned process, a second dev server, or a watcher that survived after you thought it died.
Typical output:
Error: listen EADDRINUSE: address already in use :::3000The worst fix is to restart your machine every time this appears. The better fix is to identify the owner and decide whether it should live.
Step 1: find the real process
On macOS or Linux:
lsof -iTCP:3000 -sTCP:LISTENFor other ports:
lsof -iTCP:5173 -sTCP:LISTEN
lsof -iTCP:8080 -sTCP:LISTENIf you want just the PID:
lsof -tiTCP:3000 -sTCP:LISTENStep 2: inspect before killing
ps -fp "$(lsof -tiTCP:3000 -sTCP:LISTEN)"This matters because the owner might be:
- your actual app in another terminal
- a previous watcher process
- Docker publishing that port
- a different project entirely
Step 3: kill the exact process if appropriate
kill -15 "$(lsof -tiTCP:3000 -sTCP:LISTEN)"If it ignores SIGTERM:
kill -9 "$(lsof -tiTCP:3000 -sTCP:LISTEN)"Use -9 only when the process refuses to exit normally.
If Docker owns the port
Check published containers:
docker ps
docker stop <container_id>Do not keep killing random Node processes if the real owner is a container port mapping.
If the framework can switch ports, use that deliberately
Examples:
PORT=3001 npm run dev
npx next dev -p 3001
vite --port 5174Changing the port is fine when you know why you are doing it. It is a workaround, not a diagnosis.
Why this happens so often
The most common reasons are boring:
- terminal closed but child process survived
- auto-reloader forked another process
- a second copy of the app is still running
- Docker or another local service already claimed the port
Once you get used to checking ownership first, the bug becomes much less dramatic.
Quick verification
lsof -iTCP:3000 -sTCP:LISTEN
npm run devIf the first command returns nothing and the second starts cleanly, the port is free again.
Bottom line
EADDRINUSE is a process ownership question before it is a framework question. Find the listener, inspect it, then kill or reconfigure it on purpose.