惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
L
LangChain Blog
WordPress大学
WordPress大学
MyScale Blog
MyScale Blog
The Cloudflare Blog
J
Java Code Geeks
Google DeepMind News
Google DeepMind News
Recent Announcements
Recent Announcements
Microsoft Azure Blog
Microsoft Azure Blog
Y
Y Combinator Blog
有赞技术团队
有赞技术团队
Last Week in AI
Last Week in AI
酷 壳 – CoolShell
酷 壳 – CoolShell
Martin Fowler
Martin Fowler
小众软件
小众软件
量子位
月光博客
月光博客
P
Proofpoint News Feed
IT之家
IT之家
腾讯CDC
博客园 - 三生石上(FineUI控件)
博客园 - 司徒正美
雷峰网
雷峰网
V
Visual Studio Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
How to Fix EADDRINUSE: Port Already in Use
Nilesh Raut · 2026-05-31 · via DEV Community

If you've worked with Node.js long enough, you've probably seen this error:

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

Enter fullscreen mode Exit fullscreen mode

Or:

Error: listen EADDRINUSE: address already in use 0.0.0.0:5000

Enter fullscreen mode Exit fullscreen mode

Your application refuses to start because the port you're trying to bind is already occupied.

This is one of the most common issues developers encounter during local development and deployments.

Let's fix it properly.


Problem

You start your Node.js server:

node server.js

Enter fullscreen mode Exit fullscreen mode

Instead of launching successfully, Node crashes:

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

Enter fullscreen mode Exit fullscreen mode

At this point, only one process can listen on a specific port.

If another process already owns that port, Node throws the EADDRINUSE error and exits.


Why It Happens

In production and development environments, this usually happens for one of these reasons:

1. Another Node.js process is already running

You accidentally started the application twice.

Example:

node server.js

Enter fullscreen mode Exit fullscreen mode

Then in another terminal:

npm run dev

Enter fullscreen mode Exit fullscreen mode

Both attempt to bind to port 3000.


2. A crashed process didn't release the port

This happens surprisingly often during development.

You close the terminal but the process remains alive in the background.

The port stays occupied.


3. Another application is using the port

Common examples:

  • Docker containers
  • PostgreSQL
  • Redis
  • Nginx
  • Another microservice
  • Local development tools

4. Multiple containers mapped to the same host port

Docker example:

ports:
  - "3000:3000"

Enter fullscreen mode Exit fullscreen mode

Two containers trying to expose port 3000 on the host will conflict.


Example

Consider a simple Express application:

const express = require("express");

const app = express();

app.listen(3000, () => {
  console.log("Server running");
});

Enter fullscreen mode Exit fullscreen mode

Start it:

node app.js

Enter fullscreen mode Exit fullscreen mode

Now start it again in another terminal:

node app.js

Enter fullscreen mode Exit fullscreen mode

Result:

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

Enter fullscreen mode Exit fullscreen mode

The first process already owns the port.


Production Ready Solution

Step 1: Identify Which Process Owns the Port

Linux / macOS

Find the process:

lsof -i :3000

Enter fullscreen mode Exit fullscreen mode

Example output:

COMMAND   PID USER
node     8234 dev

Enter fullscreen mode Exit fullscreen mode


Alternative

sudo netstat -tulpn | grep 3000

Enter fullscreen mode Exit fullscreen mode


Windows

netstat -ano | findstr :3000

Enter fullscreen mode Exit fullscreen mode

Output:

TCP    0.0.0.0:3000    LISTENING    12345

Enter fullscreen mode Exit fullscreen mode

Locate the process:

tasklist | findstr 12345

Enter fullscreen mode Exit fullscreen mode


Step 2: Kill the Process

Linux / macOS

kill -9 8234

Enter fullscreen mode Exit fullscreen mode


Windows

taskkill /PID 12345 /F

Enter fullscreen mode Exit fullscreen mode

The port becomes available immediately.


Step 3: Handle the Error Gracefully

Production applications should not crash without useful logs.

Example:

const PORT = process.env.PORT || 3000;

const server = app.listen(PORT, () => {
  console.log(`Running on ${PORT}`);
});

server.on("error", (err) => {
  if (err.code === "EADDRINUSE") {
    console.error(`Port ${PORT} already in use`);
    process.exit(1);
  }

  throw err;
});

Enter fullscreen mode Exit fullscreen mode

This makes troubleshooting much easier.


Step 4: Use Environment Variables

Hardcoding ports causes unnecessary conflicts.

Bad:

app.listen(3000);

Enter fullscreen mode Exit fullscreen mode

Better:

const PORT = process.env.PORT || 3000;

app.listen(PORT);

Enter fullscreen mode Exit fullscreen mode

Run:

PORT=5000 node app.js

Enter fullscreen mode Exit fullscreen mode

This becomes especially useful when running multiple services locally.


Step 5: Auto-Detect an Available Port

For internal tools and development environments:

const getPort = require("get-port");

(async () => {
  const port = await getPort({
    port: 3000
  });

  app.listen(port);
})();

Enter fullscreen mode Exit fullscreen mode

The application automatically chooses an available port.


Common Mistakes

Killing the Wrong Process

Many developers immediately run:

kill -9 <pid>

Enter fullscreen mode Exit fullscreen mode

Without verifying what owns the port.

Always inspect first.

I've seen developers accidentally terminate databases, Redis instances, and even production services on shared servers.


Assuming the Port Is Free

Just because a terminal was closed doesn't mean the process stopped.

Always verify:

lsof -i :3000

Enter fullscreen mode Exit fullscreen mode

before making assumptions.


Hardcoding Ports Everywhere

Large projects often contain:

3000
5000
8000
8080

Enter fullscreen mode Exit fullscreen mode

scattered throughout the codebase.

Use environment variables instead.


Ignoring Docker Port Mapping

A common issue:

service-a:
  ports:
    - "3000:3000"

service-b:
  ports:
    - "3000:3000"

Enter fullscreen mode Exit fullscreen mode

Docker won't allow both containers to bind the same host port.

Assign unique host ports.


Debugging Tips

When EADDRINUSE appears repeatedly, I usually follow this checklist.

Verify the owning process

lsof -i :3000

Enter fullscreen mode Exit fullscreen mode


Check background Node processes

ps aux | grep node

Enter fullscreen mode Exit fullscreen mode

You'll often find forgotten development servers.


Check Docker containers

docker ps

Enter fullscreen mode Exit fullscreen mode

Look for containers exposing the conflicting port.


Check PM2

If you're using PM2:

pm2 list

Enter fullscreen mode Exit fullscreen mode

A previously deployed process may still be running.


Check startup scripts

Sometimes systemd, PM2, Docker Compose, or Kubernetes automatically restart processes after they're killed.

The port immediately becomes occupied again.

Verify what's managing the service.


Performance Considerations

Repeatedly spawning and killing processes during development can leave orphaned processes consuming memory and CPU.

A few recommendations:

  • Use process managers responsibly
  • Avoid multiple watchers running simultaneously
  • Shut down servers gracefully
  • Monitor active processes regularly

For Express applications, graceful shutdown looks like this:

process.on("SIGTERM", () => {
  server.close(() => {
    console.log("Server closed");
    process.exit(0);
  });
});

Enter fullscreen mode Exit fullscreen mode

This helps release ports cleanly.


Final Thoughts

EADDRINUSE isn't really a Node.js problem.

It's an operating system telling you that another process already owns the network port.

The fastest way to solve it is:

  1. Identify the process
  2. Verify it's safe to stop
  3. Kill it if necessary
  4. Use configurable ports
  5. Add proper error handling

Those five steps eliminate most port-related startup issues in both local development and production environments.

If you're building backend systems regularly, keeping a small troubleshooting reference for common Node.js errors can save hours over time. I maintain similar engineering notes across projects and occasionally publish deeper backend debugging guides on NileshBlog.Tech and TechNilesh when a production issue is worth documenting.