localhost:3001: what runs on port 3001 and how to fix it

localhost:3001 is port 3001 on your own computer, and it's usually the "second" dev server: the place Next.js lands when 3000 is already taken, or the API that runs beside a frontend on 3000. BrowserSync's control panel and Uptime Kuma also default to 3001. If you see ERR_CONNECTION_REFUSED, nothing is listening there right now.

What runs on port 3001

WhatWhy it's on 3001
Next.js, Nuxt, Remix dev serverMoved automatically because 3000 was busy
Create React AppAsks "Would you like to run the app on another port instead?" and picks 3001
Express / NestJS / Fastify APIConvention when the frontend owns 3000
BrowserSync UIControl panel next to the proxied site on 3000
Uptime KumaDefault port of the self-hosted monitor

Fix "localhost:3001 refused to connect"

  1. Check where the app actually is. If your app only went to 3001 because 3000 was busy last time, it may be back on 3000 now. Read the Local: URL your dev server prints.
  2. API not started. In a monorepo, npm run dev in the frontend package won't start the API. Use your workspace runner (turbo dev, npm run dev --workspaces, docker compose up) or start the API in its own terminal.
  3. Docker Compose. Each service needs its own mapping, for example "3001:3001" for the API. From another container, call the API by service name (http://api:3001), not localhost. Inside a container, localhost is that container.

Find and free a busy port 3001

# macOS / Linux
lsof -i :3000 -i :3001
kill -9 $(lsof -ti :3001)
# Windows
netstat -ano | findstr :3001
taskkill /PID <pid> /F

If you keep ending up on 3001 by accident, the real fix is to find what holds 3000, often a dev server from another project or a crashed next dev. To fix the port on purpose: PORT=3001 npm start, next dev -p 3001, or app.listen(process.env.PORT || 3001) in Express.

Frontend on 3000, API on 3001

Browsers treat localhost:3000 and localhost:3001 as different origins, so fetch('http://localhost:3001/api') from the frontend triggers CORS. Two clean options:

  • Proxy through the frontend dev server. Vite's server.proxy, Next.js rewrites, or CRA's "proxy": "http://localhost:3001" in package.json. The browser sees one origin and cookies just work.
  • Enable CORS on the API for http://localhost:3000 only, not *, especially if you send cookies.

Open localhost:3001 from another device

Bind the server to all interfaces (HOST=0.0.0.0, next dev -H 0.0.0.0, or app.listen(3001, '0.0.0.0')), then open http://YOUR-LAN-IP:3001 from a device on the same network. If the frontend calls the API as http://localhost:3001, it breaks on the phone, because the phone's localhost is the phone. Use the proxy approach above or a relative URL.

Share 3001 or receive webhooks on it

When the frontend is on 3000 and the API on 3001, webhooks from Stripe, GitHub or Shopify should go straight to the API:

relay forward --bucket my-api http://localhost:3001/webhooks

The bucket has a permanent public URL that you paste into the provider once. Each webhook is delivered to port 3001 and logged, so you can replay it while you iterate. See receive webhooks on localhost.

To share a running app, tunnel it:

relay connect --name my-app http://localhost:3001

For a split frontend and API, tunnel the frontend and let its dev-server proxy reach the API locally. That way you need only one public URL.

Frequently asked questions

What is localhost:3001?

localhost:3001 is port 3001 on your own machine. It is usually a second dev server: Next.js and similar tools move to 3001 when 3000 is taken, and many projects run an Express or Nest API on 3001 next to a frontend on 3000. BrowserSync's control panel and Uptime Kuma also use 3001.

Why is my app on localhost:3001 instead of 3000?

Something else was already listening on port 3000, so the dev server picked the next free port. Next.js and Nuxt do this automatically and Create React App asks first. Stop the old process on 3000 if you want the app back on 3000.

Why does localhost:3001 refuse to connect?

Nothing is listening on 3001. If your app normally lands there only because 3000 is busy, it may be on 3000 now. Check the terminal for the actual URL.

How do I call an API on port 3001 from a frontend on port 3000?

The two ports are different origins, so the browser applies CORS. Either enable CORS on the API for http://localhost:3000 or configure the frontend dev server to proxy API paths to port 3001 so the browser only talks to one origin.