Skip to content

Auto Port Selection

Automatically find an available port when the default is occupied. Prevents the common "port already in use" error during development without manual intervention.

When to Use

  • Development servers where multiple instances may run simultaneously
  • CLI tools that start servers on default ports
  • Any server startup where a fixed port is preferred but not required
  • Avoiding EADDRINUSE errors without manual port management

The Pattern

Use the portfinder package to scan for an available port starting from a preferred default:

javascript
import portfinder from "portfinder";

async function findPort(start = 8000) {
  return portfinder.getPortPromise({
    port: start,
  });
}

With a stop limit

Constrain the search range to avoid scanning too far:

javascript
export async function getPort(start) {
  const { default: portfinder } =
    await import("portfinder");
  return portfinder.getPortPromise({
    port: start,
    stopPort: start + 100,
  });
}

Respect environment variable

Always prefer an explicit PORT environment variable. Auto-selection is a development convenience, not a production strategy:

javascript
const port = process.env.PORT
  ? Number(process.env.PORT)
  : await findPort(8000);

Integration with server startup

Pass the resolved port to app.listen() to start serving:

javascript
const PORT = process.env.PORT || await findPort(8000);

app.listen(PORT, () => {
  console.log(`Running at http://localhost:${PORT}`);
});

Minimal Express server

A complete example combining port finding with an Express app:

javascript
import express from "express";
import portfinder from "portfinder";

const app = express();

app.get("/", (req, res) => res.send("ok"));

const PORT =
  process.env.PORT || await findPort(8000);

app.listen(PORT, () => {
  console.log(
    `Running at http://localhost:${PORT}`,
  );
});

async function findPort(start = 8000) {
  return portfinder.getPortPromise({
    port: start,
  });
}

With promisified listen

The promisified listen() helper from the server-startup pattern returns a structured result with the URL already constructed:

javascript
const port = await getPort(3000);
const { url } = await listen(app, port);
console.log(`Server running at ${url}`);

Trade-offs

ApproachProsCons
portfinderSimple, reliableExtra dependency
net.createServer + retryNo dependencyMore code, slower
Fixed port onlyPredictableFails on conflict
Random port (0)No conflicts everUnpredictable URL

Use auto-selection in development, fixed ports in production. Production deployments should fail loudly if the expected port isn't available — silently switching ports would break load balancers and DNS.