Open-source project
libp2p/js-libp2p avatar
libp2p/js-libp2p

js-libp2p: the JavaScript libp2p stack for browser and Node peers

A JavaScript Implementation of libp2p networking stack.

2,580 stars549 forksTypeScriptApache-2.0

At a glance

What is it?
A monorepo of TypeScript packages that gives a JavaScript application dialable peers, encrypted connections and a DHT. It is a toolkit for people building their own peer-to-peer protocol, not a service you install and point at a network.
Who is it for?
Adopt js-libp2p if you are writing a peer-to-peer protocol in JavaScript or TypeScript and want transports, encryption, stream multiplexing and peer discovery to come from one stack rather than from your own socket code. Do not adopt it if you want a hosted relay, a stable API frozen for years, or a network that already exists; js-libp2p gives you the plumbing, and the peers are yours to find.
Can I use it commercially?
Yes. Apache-2.0 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 4 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

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

Editorial analysis

What js-libp2p actually solves for a JavaScript application

Writing peer-to-peer code by hand means solving the same five problems every time: how two machines find each other, how the connection is encrypted, how several logical streams share one socket, how you agree on a protocol name, and how the peer set stays fresh as nodes come and go. js-libp2p packages those as separate interfaces. The repository is a monorepo, and the README lists the parts: packages/connection-encrypter-noise for the Noise handshake, packages/multistream-select for protocol negotiation, packages/kad-dht for the Kademlia distributed hash table, packages/keychain for key management, packages/peer-discovery-bootstrap for bootstrapping, and packages/metrics-prometheus for scraping metrics. The audience is narrow on purpose. If you are building an application whose peers talk to each other directly, and you do not want to invent a wire protocol, this is the layer you would otherwise write yourself. If your application is a normal client against your own HTTP API, js-libp2p is more machinery than the problem needs.

Flat categories instead of a fixed stack

The README describes the design goal directly: libp2p takes the mechanisms that have accumulated around IP across the OSI layers, distils them into flat categories, and defines interfaces so that protocols and applications can use and swap them. In practice that means a node is assembled from parts you choose. A transport carries bytes, a connection encrypter secures the connection, a stream muxer shares it, and a peer discovery mechanism keeps the peer store populated. The interface packages make the contract explicit: packages/interface holds the interface implemented by a libp2p node, packages/interface-internal holds the interfaces implemented by internal components, and packages/interface-compliance-tests holds the tests that check an implementation against those interfaces. That last package is the interesting one. It means a transport or discovery module is not trusted because it is in the tree; it is checked against the same suite as everything else. The cost is that assembling a node is configuration work. The README points at doc/CONFIGURATION.md for that, and at doc/LIMITS.md for configuring a node to resist malicious network peers, which is a hint about how much of the hardening is left to you.

Installing js-libp2p and starting a node

The README gives one install command. It pulls the libp2p package, which lives at packages/libp2p in the monorepo.

bash
npm install libp2p

The README does not print a full node example inline. It directs readers to doc/GETTING_STARTED.md for the guide and to the separate js-libp2p-examples repository for worked scenarios. So the honest first step is to read GETTING_STARTED.md rather than to copy a snippet from the README, because the README has none. What the README does state is that the documentation on the main branch may contain changes from a pre-release, and that if you want the documentation for the latest release you should look at the npm page or select the matching tag in GitHub. Do that. Reading main and installing a released version is the most common way to end up with a config key that does not exist in the version you have.

The second thing to check is the migration guides, which the README links from a note at the top: doc/migrations in the repository. The note says plainly that if you are upgrading libp2p to the latest version you should check the migration guides for the changes you need to make. Treat that as part of the install, not as an afterthought.

The API moves, and semver is the promise, not stability

The project status section is unusually direct. It says the project has been used in production for years in Ethereum, IPFS and more, that it is maintained by multiple organizations, and then: the API might change, but we strictly follow semver. Those two halves belong together. Semver means a breaking change arrives with a major version bump and a migration guide, not that the shape of the API is settled. For a library that sits under your application's networking, that is a real ongoing cost. You will read migration guides. You will pin versions. The release history shows how granular the surface is: the recent releases listed are tagged per package, with webtransport at v6.0.40, webrtc at v6.0.33, and transport-interop-libp2p-main at v1.0.41. Independent version numbers per package mean a transport can move without the core moving, which limits the blast radius of an upgrade but also means there is no single version number that describes the whole stack you are running. Your lockfile is the real record of what you deployed.

Transports and the browser boundary

The repository carries separate packages for WebRTC and WebTransport, which is where js-libp2p stops looking like a Node library. A browser peer cannot open a raw TCP socket, so the transports available in a browser are a different set from those available in Node, and the connectivity matrix the README links to exists precisely because which combination of two implementations can talk to each other is not obvious from the package list. This is the limitation to internalise before you design anything. If your peers must run in browsers, you are choosing from browser-capable transports, and you should confirm the pairing you need against the connectivity matrix rather than assuming it. The interop directory in the repository, described as a multidimensional interop test, and the transport-interop-libp2p-main package are the project's own answer to that question, and they are worth reading before you commit to a transport combination. The README also links a universal connectivity demo, which is a more useful starting point than the package list for understanding what actually connects to what.

Gossipsub and the DHT are packages here, not the whole product

People arrive at js-libp2p looking for pub/sub or for a DHT, and both exist as packages rather than as features of the core node. The DHT is packages/kad-dht, described in the README as a JavaScript implementation of the Kad-DHT for libp2p. Gossipsub is not listed among the packages in the README excerpt, so if you need pub/sub, confirm the current package and its version rather than assuming it ships with the node. The distinction matters for how you plan. A node with a DHT enabled is doing background work: routing table maintenance, queries on behalf of other peers, and traffic you did not initiate. That is the point of a DHT, and it is also why doc/LIMITS.md exists. The README frames limits as help configuring your node to resist malicious network peers, which tells you the maintainers expect an exposed node to be probed. Budget time for that configuration before you expose anything to an untrusted network.

How js-libp2p differs from a single-transport peer library

A simpler alternative in this space is a WebSocket signalling library plus a direct WebRTC data channel: one transport, one discovery mechanism, and no protocol negotiation layer. That approach is smaller and easier to reason about, and for a fixed set of known peers it is often the right call. The difference is what happens when the peer set is not fixed. js-libp2p separates discovery from transport from negotiation, so you can add a transport or a discovery mechanism without rewriting the application, and the compliance test package keeps each implementation honest against the same interface. The other axis is cross-implementation reach. The README links a specification repository, a connectivity matrix and a universal connectivity demo, and the presence of a Rust implementation and a Python implementation in the related searches reflects the same idea: the interfaces are meant to be shared across languages, so a JavaScript peer can talk to a peer written elsewhere. If you only ever need two known browsers to exchange data, the signalling library is less to maintain. If you need a peer set that changes and a protocol other implementations can speak, the layering is the reason to accept the extra configuration.

Editorial conclusion

Adopt js-libp2p if you are writing a peer-to-peer protocol in JavaScript or TypeScript and want transports, encryption, stream multiplexing and peer discovery to come from one stack rather than from your own socket code. Do not adopt it if you want a hosted relay, a stable API frozen for years, or a network that already exists; js-libp2p gives you the plumbing, and the peers are yours to find. Before committing, read doc/GETTING_STARTED.md, doc/CONFIGURATION.md and doc/LIMITS.md, and check doc/migrations for the changes your target version requires.

Frequently asked questions

How do I install js-libp2p?

The README gives the command npm install libp2p. The package lives at packages/libp2p in the monorepo, and the README points to doc/GETTING_STARTED.md for the setup guide rather than printing a full example inline.

Is the js-libp2p API stable?

The project status section states that the API might change but that the project strictly follows semver, so breaking changes arrive with a major version and a migration guide. The README links migration guides under doc/migrations and tells upgraders to check them for required changes.

Can js-libp2p run in a browser?

The repository contains separate WebRTC and WebTransport packages, and the README links a connectivity matrix and a universal connectivity demo. Because a browser cannot open a raw TCP socket, the usable transports differ from Node, so the specific pairing you need should be checked against the matrix.

Where are the js-libp2p examples and tutorials?

The README points to doc/GETTING_STARTED.md inside this repository and to a separate js-libp2p-examples repository that walks through several scenarios. It also links ProtoSchool's introduction to libp2p and the docs.libp2p.io site.

Official sources

  1. libp2p/js-libp2p on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
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/libp2p-js-libp2p.svg)](https://hysenlabs.com/projects/libp2p-js-libp2p)