RepoPilot

How does this find an available port? Show me the actual implementation.

About sindresorhus/get-port · 2 messages · last activity 8/1/2026

Question

How does this find an available port? Show me the actual implementation.

RepoPilot

The core logic lives in index.js and works in a few layers:

1. Low-level check: does a specific port/host bind successfully?

checkAvailablePort creates a temporary net.Server, tries to listen on the given options, and if it succeeds, immediately closes it and resolves with the bound port number. If listening fails (e.g. EADDRINUSE), the error event rejects the promise.

const checkAvailablePort = options =>
	new Promise((resolve, reject) => {
		const server = net.createServer();
		server.unref();
		server.on('error', reject);

		server.listen(options, () => {
			const {port} = server.address();
			server.close(() => {
				resolve(port);
			});
		});
	});

[index.js:L47-L60]

2. Checking across all local hosts

getAvailablePort decides whether to check just one host (if options.host was explicitly given, or if requesting a random port with port: 0) or to loop through every local host/interface, calling checkAvailablePort for each. It tolerates EADDRNOTAVAIL/EINVAL errors (meaning that host doesn't support that address family) and rethrows anything else.

const getAvailablePort = async (options, hosts) => {
	if (options.host || options.port === 0) {
		return checkAvailablePort(options);
	}

	for (const host of hosts) {
		try {
			await checkAvailablePort({port: options.port, host});
		} catch (error) {
			if (!['EADDRNOTAVAIL', 'EINVAL'].includes(error.code)) {
				throw error;
			}
		}
	}

	return options.port;
};

[index.js:L61-L78]

3. Top-level orchestration: getPorts (the default export, getPort)

This is where preferred ports, exclusions, locking, and reservation all come together:

  • It normalizes options.port into an array (or uses the iterable as-is), and validates/collects the exclude set [index.js:L89-L116].
  • It sets up a periodic timer that rotates "young"/"old" locked-port sets so temporary locks expire after 15–30 seconds (unless reserve is used) [index.js:L120-L131].
  • It resolves the list of local hosts via getLocalHosts() [index.js:L133].
  • It iterates over a generated port-check sequence (portCheckSequence(ports) — preferred ports first, then presumably random/range fallback), skipping excluded ports, calling getAvailablePort for each candidate, and re-trying with a new port (port: 0, i.e. random) if the returned port turns out to already be locked by this process:
for (const port of portCheckSequence(ports)) {
	try {
		if (exclude.has(port)) {
			continue;
		}

		let availablePort = await getAvailablePort({...netOptions, port}, hosts);
		while (isLockedPort(availablePort)) {
			if (port !== 0) {
				throw new Locked(port);
			}

			availablePort = await getAvailablePort({...netOptions, port}, hosts);
		}

		if (reserve) {
			reservedPorts.add(availablePort);
		} else {
			lockedPorts.young.add(availablePort);
		}

		return availablePort;
	} catch (error) {
		if (!['EADDRINUSE', 'EACCES'].includes(error.code) && !(error instanceof Locked)) {
			throw error;
		}
	}
}

throw new Error('No available ports found');

[index.js:L134-L162]

So the flow is: try each candidate port (starting with any preferred ones) → check it's actually bindable on the relevant host(s) via a real net.createServer().listen() call → make sure it isn't already locked/reserved by this same process → lock or reserve it → return it. If nothing works, it throws 'No available ports found' [index.js:L162].

Would you like me to look at portCheckSequence, getLocalHosts, or the locking/isLockedPort/Locked class definitions, since those weren't in the retrieved chunks?

FOLLOW_UPS:

  • What does portCheckSequence do internally?
  • How is getLocalHosts() implemented?
  • How does port locking/reservation actually work?

Want to ask your own question?

Open chat for sindresorhus/get-port

Public Q&A. Generated by RepoPilot from the actual source of sindresorhus/get-port. AI answers can be incomplete or stale — verify before relying on them.