RepoPilot

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

About sindresorhus/get-port · 2 messages · last activity 7/27/2026

Question

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

RepoPilot

The core algorithm works in a few layers, all in index.js:

1. Low-level port check: checkAvailablePort

This is the fundamental primitive — it creates a net.Server, tries to bind (listen) with the given options, and resolves with whatever port the OS assigned (or confirmed available), then immediately closes the server:

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]

If the port is taken, listen emits an error event (e.g. EADDRINUSE), which rejects the promise instead.

2. getAvailablePort — checking across network interfaces

If a specific host was given, or the caller asked for a random port (port === 0), it just calls checkAvailablePort directly. Otherwise, it loops through all local host addresses (from OS network interfaces) and verifies the preferred port is free on each of them, tolerating EADDRNOTAVAIL/EINVAL (host not applicable to that interface) but rethrowing 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}); // eslint-disable-line no-await-in-loop
		} catch (error) {
			if (!['EADDRNOTAVAIL', 'EINVAL'].includes(error.code)) {
				throw error;
			}
		}
	}

	return options.port;
};

[index.js:L61-L78]

3. getPorts (the default export, getPort) — orchestration

This is the main entry point. It:

  1. Normalizes options.port into an iterable list of candidate ports, and validates/builds the exclude set [index.js:L89-L114].
  2. Sets up a periodic cleanup timer that ages out "locked" ports (ports returned recently that shouldn't be immediately re-handed-out) — moving lockedPorts.young into lockedPorts.old and resetting young [index.js:L118-L129].
  3. Gets the list of local hosts to check against [index.js:L131].
  4. Iterates over the port candidates (via portCheckSequence, which yields preferred ports first, then falls back to 0 for a random OS-assigned port), skipping excluded ports, calling getAvailablePort, and re-trying with port: 0 if the returned port is currently locked:
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-L163]

So in short: it tries each preferred port (checked as actually bindable via a real net.createServer().listen() call across relevant interfaces), skips any that are excluded or already locked/reserved by this process, falls back to asking the OS for a random free port (port: 0) if nothing preferred works, and throws if nothing at all could be found.

FOLLOW_UPS:

  • What is portCheckSequence and how does it work?
  • How does the port-locking/reservation mechanism work internally?
  • What is getLocalHosts and why is it needed?

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.