Library / SDK
sindresorhus/get-port avatar
sindresorhus/get-port

get-port finds a free TCP port, and holds it long enough to use

Get an available TCP port

929 stars65 forksJavaScriptMIT

At a glance

What is it?
get-port is a small ES module that resolves an available TCP port in Node.js, with preferred ports, port ranges, a per-process lock that closes the race window between asking for a port and binding it, and a reserve option for long-running test suites. The remaining race, between processes, is documented rather than solved.
Who is it for?
get-port suits anyone starting a server or a test server in Node.js who has hit the EADDRINUSE flake that comes from picking a port by guessing, since it checks availability rather than assuming, and it removes the in-process race with a lock you can extend to the life of the process with reserve. It is the wrong tool when you need a port that is guaranteed to survive your process exiting, and it does nothing for the multi-process case beyond surfacing EADDRINUSE.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 50 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 7, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • sindresorhus/get-port929 ★ · +0
Star history
Repository2026-10-212026-11-07
sindresorhus/get-port929929

0 Stars in the last 17 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

One question, asked correctly: is this TCP port free right now

The whole package exists to answer a question that sounds trivial until you have been on the receiving end of it. You want to start a server on a port, and you do not want to hardcode 3000 because something else on the machine already holds it. The tempting shortcut is to listen on port 0 and let the operating system choose, but that only works when you own the socket, and it does not work when the port number has to be known before the socket is opened, for example because it goes into a URL for another process.

get-port resolves an available TCP port for you. The API is a single function returning a promise for a port number.

js
import getPort from 'get-port';

console.log(await getPort());
//=> 51402

The package is ESM only. The package.json sets type to module, exposes a default export from index.js alongside types from index.d.ts, marks itself sideEffects free, and declares engines node >=16. The distributed files are just index.js and index.d.ts, so the install footprint is a single implementation file and a type declaration.

The audience is Node.js developers who need a port number to hand to something else. That covers dev servers, test harnesses, tools that launch a child process and then connect to it, and anything that wants to run several instances of itself on one machine.

Preferred ports are honoured when free, and dropped when not

The useful behaviour is that get-port is not just a random port picker. You can state a preference, and the preference wins whenever it is actually available.

js
import getPort from 'get-port';

console.log(await getPort({port: 3000}));
// Will use 3000 if available, otherwise fall back to a random port

The port option accepts either a single number or an iterable of numbers, so a list of candidates works the same way.

js
import getPort from 'get-port';

console.log(await getPort({port: [3000, 3001, 3002]}));
// Will use any element in the preferred ports array if available, otherwise fall back to a random port

For ranges there is a helper, portNumbers, which generates port numbers in a given range and returns an iterable.

js
import getPort, {portNumbers} from 'get-port';

console.log(await getPort({port: portNumbers(3000, 3100)}));
// Will use any port from 3000 to 3100, otherwise fall back to a random port

The range helper has constraints worth knowing. The from value must be in the range 1024 to 65535, and the to value must be in the same range and must be greater than from. That lower bound is the giveaway that this is about unprivileged ports and not about binding anything below 1024, which needs elevated privileges on a Unix system.

The fallback to a random port is what keeps the function useful in a busy CI machine. A preference is a request, not a guarantee, and the code never throws just because the port you asked for is taken.

The 15 to 30 second lock is what closes the in-process race

Asking whether a port is free and then binding to it are two separate actions, and something else can take the port in between. get-port addresses the common version of that race with a lightweight locking mechanism: returned ports are held for 15 to 30 seconds before they become eligible for reuse, which the README says eliminates in-process race conditions such as parallel Jest tests.

The default window is not always long enough. If the delay between getting a port and binding to it may exceed that window, which the README names as the situation in long-running test suites, there is a reserve option that locks the port for the lifetime of the process instead.

js
import getPort, {clearLockedPorts} from 'get-port';

const port = [3000, 3001, 3002];

console.log(await getPort({port}));
//=> 3000

console.log(await getPort({port}));
//=> 3001

// If you want the results to be unaffected by previous calls, clear the cache.
clearLockedPorts();

console.log(await getPort({port}));
//=> 3000

Two details in that example are worth pausing on. The second call returns the next candidate, 3001, precisely because 3000 is still locked by this process. And clearLockedPorts empties the internal cache, which the README says is useful when you want results unaffected by previous calls, with the explicit warning that clearing the cache removes protection against in-process race conditions. In other words the lock is a cache, and clearing it is a deliberate decision to give that protection up.

One more subtlety: reserved ports are locked globally by port number for the current process, even if you looked them up with a specific host or ipv6Only option. The lock ignores the address you checked, so it is broader than you might expect.

Host decides which addresses are checked, and that changes the answer

By default get-port checks availability on all local addresses defined in the OS network interfaces. The host option narrows that to a single address, and the README says it can be either an IPv4 or an IPv6 address.

That default is the right one for most cases, because a port can be occupied on one interface and free on another, and the failure you are trying to avoid is a bind that succeeds on the loopback interface and then fails on the interface your users connect to. Checking everything is the conservative choice.

The host option exists for the opposite reason. If you know the exact address the service will bind to, checking only that address is faster and gives a more accurate answer about whether that specific endpoint is free. The cost is that the answer says nothing about the other interfaces, and the port might be taken on one of them.

The exclude option is the other half of the API surface. It takes an iterable of ports that should not be returned, and the README notes you could pass it the return value of portNumbers. That makes it easy to carve a range out of the candidate set, for example to keep a well-known port free for something else while still using the rest of the range.

The race that remains is the one between processes

The README has a section titled Beware, and it is honest about the limits.

There is a very tiny chance of a race condition if another process starts using the same port number between the time you get the number and the time you actually use it. Multi-process race conditions are described as extremely rare, and the consequence is an immediate EADDRINUSE error when attempting to bind, which allows your application to retry.

That is a deliberate design choice rather than an oversight. The lock is in-process, so it cannot protect against another Node process, and pretending otherwise would be a lie about what the library guarantees. What it does give you is that in-process parallelism, the kind that shows up as flaky parallel tests, is fully handled, and the cross-process case fails loudly and immediately rather than silently.

So the correct mental model is that get-port converts a silent, intermittent failure into a visible one in the case it cannot prevent. That is worth having, but it means your code still needs a retry path around the bind if it must survive a busy machine.

Writing the check yourself, and the CLI wrapper

The alternative is to do it without the dependency, which is entirely reasonable for a handful of lines. Node's net module can create a server, attempt to listen on a port, and report an error event when the port is taken. A short function that tries a candidate and resolves or rejects on the error event gives you the same answer.

The difference in approach is exactly the locking. A hand-rolled check answers the question at one instant, so two parallel test files in the same process can receive the same port and one of them fails. get-port's lock is the feature that makes parallel use safe, and it is the reason to take the dependency rather than write the twenty lines yourself. For a script that starts one server and never runs in parallel, the hand-rolled version is fine and adds nothing to your dependency tree.

For command line use there is a separate package, get-port-cli, listed in the README's Related section as a CLI for this module. It is a distinct repository rather than a binary shipped here, so it has to be installed on its own if you want a shell-level equivalent.

On maintenance, the package is at version 7.2.0 with the last push to the repository on 2026-09-18. The release history shows v7.2.0 on 2026-03-22, v7.1.0 on 2024-03-20 and v7.0.0 on 2023-06-04, and the major versions track Node engine changes rather than new features. The licence is MIT, and the package is marked sideEffects false, so a bundler can drop it from a tree-shaken bundle when it is unused.

Editorial conclusion

get-port suits anyone starting a server or a test server in Node.js who has hit the EADDRINUSE flake that comes from picking a port by guessing, since it checks availability rather than assuming, and it removes the in-process race with a lock you can extend to the life of the process with reserve. It is the wrong tool when you need a port that is guaranteed to survive your process exiting, and it does nothing for the multi-process case beyond surfacing EADDRINUSE. Verify first whether your framework already picks a free port for you, because duplicating that logic adds a dependency without adding anything, and check the engine requirement of Node 16 or newer before adding it to an older codebase.

Frequently asked questions

How do I get a free TCP port with get-port?

Import the default export and await the call, for example console.log(await getPort()). The function returns a promise for a port number, and it checks availability on all local addresses by default.

Can get-port use a specific port if it is available?

Yes. Pass a preferred port with getPort({port: 3000}), or an array of candidates with getPort({port: [3000, 3001, 3002]}). If the preferred port is taken, the call falls back to a random port instead of failing.

What does the reserve option do in get-port?

By default a returned port is held for 15 to 30 seconds before it can be reused. The reserve option locks the port for the lifetime of the process instead, which is useful when the delay between getting the port and binding to it may exceed that window, such as in long-running test suites.

How do I get a port in a specific range with get-port?

Use the portNumbers helper and pass its result as the port option, for example getPort({port: portNumbers(3000, 3100)}). Both the from and to values must be within 1024 to 65535, and to must be greater than from.

Does get-port prevent two processes from taking the same port?

No. The README says multi-process race conditions are extremely rare and result in an immediate EADDRINUSE error when binding, which lets the application retry. The locking mechanism only covers in-process races such as parallel Jest tests.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. sindresorhus/get-port on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/sindresorhus-get-port.svg)](https://hysenlabs.com/projects/sindresorhus-get-port)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/sindresorhus-get-port.svg)](https://hysenlabs.com/projects/sindresorhus-get-port)

Was this useful?