# Pear
import { Tabs, Tab } from 'fumadocs-ui/components/tabs'
import { Cards, Card } from 'fumadocs-ui/components/card'
Pear is an installable peer-to-peer runtime, development, and deployment platform. Build, share, and extend unstoppable, zero-infrastructure P2P apps for mobile, desktop, and terminal.
Welcome to the Internet of Peers.
*– Holepunch, the P2P Company*
Install Pear [#install-pear]
Get the [`pear`](/reference/pear/cli) CLI from **[install.pears.com](https://install.pears.com)**:
```sh
curl https://install.pears.com/pear.sh | sh
```
```powershell
irm https://install.pears.com/pear.ps1 | iex
```
```sh
npx pear
```
```sh
docker run -it --rm tetherto/pear
```
Follow the `PATH` instructions the installer prints, then run `pear` directly. Full details, upgrade instructions, and the npm-global alternative are on [Install & upgrade](/reference/pear/cli#install). The [`tetherto/pear`](https://hub.docker.com/r/tetherto/pear) image runs Pear inside Ubuntu with `pear` and `pear-install` ready to go—a low-risk way to try out Pear apps without installing anything locally.
Boilerplates & key docs [#boilerplates--key-docs]
Starter paths and the most relevant docs for building and shipping a Pear desktop app (macOS / Linux / Windows):
The upstream Electron template used by the team is `holepunchto/hello-pear-electron` on GitHub (clone there for a ready-made repo; use the links above for explanations and procedures).
How-to guides by task [#how-to-guides-by-task]
Goal-oriented recipes, grouped by task. **Releasing and distributing your app** lives here too—shipping and updating is a how-to, spanning [manual deployment](/how-to/operate-an-app/manual-deployment), [multisig](/how-to/operate-an-app/multisig), [build & package](/how-to/operate-an-app/build-and-package), and [CI](/how-to/operate-an-app/github-actions); the why is in [Release pipeline](/explanation/deployment-releasing-apps-p2p).
Module catalog [#module-catalog]
The full list of `pear-*` and `bare-*` modules—application libraries, UI libraries, common libraries, developer libraries, integration libraries—lives at **[Reference → Modules](/reference/modules/pear-modules)** and **[Reference → Bare modules](/reference/modules/bare-modules)**. Building-block libraries ([Hypercore](/reference/building-blocks/hypercore), [Hyperbee](/reference/building-blocks/hyperbee), [Hyperdrive](/reference/building-blocks/hyperdrive), …), helpers ([Corestore](/reference/helpers/corestore), [Localdrive](/reference/helpers/localdrive), …), and CLI tools have full reference pages under **[Reference](/reference)**. The runtime underneath has its own reference—the [Bare runtime API](/reference/bare/runtime), the [`bare` CLI](/reference/bare/cli), and [Bare Kit](/reference/bare/bare-kit) for native embedding.
# Availability and blind peering
Peer-to-peer availability is not automatic. A new user can only download data that at least one online peer already holds. Pear applications therefore need an explicit strategy for [data availability](#data-availability) and [application availability](#application-availability).
This page covers seeding, when it falls short, and **blind peering**—a service that replicates cores on your behalf without reading their contents. For the general distribution model, see [Storage and distribution](/explanation/storage-and-distribution).
Two availability problems [#two-availability-problems]
Data availability [#data-availability]
Data availability means the [Hypercores](/reference/building-blocks/hypercore), [Autobases](/reference/building-blocks/autobase), or drives your application reads and writes remain reachable on the swarm. Chat history, shared documents, and room state all depend on someone seeding the relevant cores.
Application availability [#application-availability]
Application availability means the Pear app itself—its metadata core and content [Hyperdrive](/reference/building-blocks/hyperdrive)—can be discovered and installed. A `pear://` link is stable, but the bytes behind it still have to exist on at least one peer.
Both problems share the same underlying constraint: replication requires a live source.
Seeding with pear seed [#seeding-with-pear-seed]
The simplest way to keep an application bundle online is [seeding](#seeding-with-pear-seed), analogous to seeding a torrent. Running `pear seed pear://` keeps the underlying cores announced and available for download.
```bash
pear seed pear://
```
The process must stay running while you want to act as a guaranteed source. Anyone can open the link, but a first-time user needs at least one seeder with a complete copy.
See [Storage and distribution](/explanation/storage-and-distribution#how-distribution-works) for how staging, seeding, and lazy replication fit together—this page does not repeat that model.
Seeding works well when you control an always-on machine and the cores you care about are ones you already possess. It has two practical limits:
1. **Operational overhead**—You need a running `pear` (or equivalent replicator) per application you seed.
2. **Scope**—You can only seed cores you have locally. A private room or direct-message thread you are not a member of cannot be seeded from your node.
When authors go offline and no participant keeps seeding, data can become temporarily unreachable even though the cryptographic keys still exist.
Blind peering [#blind-peering]
A **blind peer** is a dedicated replicator that stores and serves Hypercores **without decrypting or interpreting** their contents. Blind peering is one way of **putting the server in serverless**: always-on reachability like a hosted service, but the operator never holds the plaintext. It joins swarms on request and caches blocks so other peers can find a source. Blind peering separates "make this core findable" from "I personally hold the plaintext."
The stack has three parts:
1. **[blind-peer](https://github.com/holepunchto/blind-peer)**—server library that accepts peering requests and replicates cores.
2. **[blind-peering](https://github.com/holepunchto/blind-peering)**—client library used inside applications to register cores or Autobases with a blind peer.
3. **[blind-peer-cli](https://github.com/holepunchto/blind-peer-cli)**—CLI that runs a blind peer as a standalone server (provides the `blind-peer` command).
Running a blind peer server [#running-a-blind-peer-server]
Install the CLI and start the server:
```bash
npm i -g blind-peer-cli
blind-peer
```
On startup the process logs (as ndjson) a `Listening at ` line—that public key is the blind peer's identity, and clients use it as one of their configured `keys`. The default disk budget is 100 GB; cap it with `-m ` (megabytes).
For production, run `blind-peer` under a service manager. Example systemd unit:
```toml
[Unit]
Description=Blind Peer
After=network.target
[Service]
ExecStart=/usr/local/bin/blind-peer -m 10000 --trusted-peer
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
```
Pass `--trusted-peer ` to authorize a specific peer to announce on the blind peer (set `announce: true` on its requests). The public key here is the identity of the peer that will make those requests—the `Listening at ` value logged by that peer's own swarm node.
Registering cores from an application [#registering-cores-from-an-application]
Inside a Pear worker, wire the client to your existing [Hyperswarm](/reference/building-blocks/hyperswarm) and [Corestore](/reference/helpers/corestore):
```js
import BlindPeering from 'blind-peering'
import Hyperswarm from 'hyperswarm'
import Corestore from 'corestore'
const store = new Corestore(Pear.config.storage)
const swarm = new Hyperswarm()
swarm.on('connection', (conn) => store.replicate(conn))
const BLIND_PEER_KEYS = ['']
const blinds = new BlindPeering(swarm.dht, store.namespace('blind-peering'), {
keys: BLIND_PEER_KEYS
})
// Ask the blind peers to keep a single Hypercore available…
await blinds.addCore(core)
// …or a whole Autobase (all of its writer and view cores).
await blinds.addAutobase(base)
```
`addCore` / `addAutobase` connect to the closest configured blind peers and request that they replicate and seed the given cores—without the blind peer ever being able to read them.
Consider letting users configure which blind peers they trust—default infrastructure may not match privacy or jurisdiction requirements (for example location-sensitive data).
Finding the keys to keep available [#finding-the-keys-to-keep-available]
`pear info pear://` prints the keys behind an application bundle:
```bash
pear info pear://
```
The `project` and `content` rows identify the metadata core and content drive. To keep them available, open the corresponding cores in a replicator process and register them with the client library shown above—`blinds.addCore(core)` for a single [Hypercore](/reference/building-blocks/hypercore), `blinds.addAutobase(base)` for an [Autobase](/reference/building-blocks/autobase) and all of its writer and view cores.
Trusted peers and discovery keys [#trusted-peers-and-discovery-keys]
When a blind peer runs with `--trusted-peer`, it recognizes seed requests signed by that key and joins the swarm for the requested core. That is more targeted than broadcasting blindly: peers looking for a specific core use its **discovery key** as a [Hyperswarm](/reference/building-blocks/hyperswarm) topic, so participants in that topic are likely to hold or want the same data.
Blind peering does not replace end-to-end encryption or capability checks on the cores themselves; it only improves **reachability** by keeping an always-on replica on the network.
See also [#see-also]
* [Storage and distribution](/explanation/storage-and-distribution)—on-disk layout and the `pear seed` distribution model.
* [Deploy your application](/how-to/operate-an-app/manual-deployment/deployment)—staging and announcing releases.
* [Peer-to-peer, demystified](/explanation/peer-to-peer-demystified)—how peers find one another on the swarm.
* [Autobase reference](/reference/building-blocks/autobase)—multi-writer cores often registered with blind peering.
* [Hyperswarm reference](/reference/building-blocks/hyperswarm)—topic-based discovery blind peers participate in.
# One core, many platforms
A peer-to-peer app has two very different halves.
1. One is the **core**: swarm identity, storage, replication, and the protocol logic—code that should be identical on every device.
2. The other is the **UI**: windows, views, and gestures—code that is necessarily different on a desktop, a phone, and a terminal.
Bare's answer is to keep the core in one place and let only the UI change. This page explains that pattern and the machinery that connects the two halves. For the runtime itself, see [Inside Bare](/explanation/bare-runtime); for where this sits in the wider picture, see [How Pear and Bare fit together](/explanation/pear-and-bare).
The shape: shell, seam, core [#the-shape-shell-seam-core]
A cross-platform Bare app has three parts:
* The **native shell** is written in the platform's own language and owns nothing but presentation.
* The **core** runs as a Bare *worklet*—an isolated Bare thread—and owns everything peer-to-peer:
* it holds the swarm identity
* opens the [Corestore](/reference/helpers/corestore)
* runs [Hyperswarm](/reference/building-blocks/hyperswarm) and [HyperDHT](/reference/building-blocks/hyperdht)
* handles the Noise-encrypted connections to other peers.
* The shell never imports a networking library
* The core never imports a UI framework
* Between them is a [**typed RPC seam**](#the-typed-rpc-seam)
Worklets carry the core [#worklets-carry-the-core]
[`bare-kit`](/reference/bare/bare-kit) is the toolkit that runs a Bare core inside a native app. It exposes a web-worker-like API for starting and managing isolated Bare threads—called *worklets*—each with an IPC channel to the host.
* On iOS you drive a worklet from Objective-C (Swift interop is available through the standard language bridge);
* on Android, from Java (Kotlin interop is available through the standard language bridge);
* from React Native or Expo, [`react-native-bare-kit`](/reference/bare/bare-kit) gives you the same `Worklet` and `IPC` objects in JavaScript;
* The worklet honours the Bare [lifecycle](/explanation/bare-runtime#the-lifecycle), so the host can suspend and resume the core in step with the OS's app-lifecycle rules.
Because the worklet is just Bare, the core you ship to mobile is the *same JavaScript* you'd run in a desktop [worker](/explanation/workers) or a standalone terminal binary. Write it once; embed it everywhere.
The typed RPC seam [#the-typed-rpc-seam]
The shell and the core could exchange raw bytes over the IPC pipe, but that pushes framing and parsing into hand-written code on both sides. The Bare RPC ecosystem replaces those raw bytes with **typed methods generated from a shared schema**:
* [`hyperschema`](https://github.com/holepunchto/hyperschema) defines versioned, append-only data structures and generates [`compact-encoding`](/reference/helpers/compact-encoding) codecs for them.
* [`bare-rpc`](/reference/modules/bare-modules) frames requests and replies over a duplex stream, with a unique command number per method.
* Code generators turn the schema into typed bindings for each language. JavaScript bindings are generated today, and a Swift toolchain (`hyperschema-swift`, `bare-rpc-swift`, `compact-encoding-swift`, `hrpc-swift`) produces wire-compatible Swift structs and a typed RPC class, with C and Kotlin generators following.
The seam supports the RPC patterns a real app needs:
* **unary** request/response,
* **send-only** events,
* **response-stream** (the handler writes a sequence of chunks),
* **request-stream** (the caller streams input), and
* **duplex** (both at once).
Update the schema, regenerate, and both sides get the new types—no hand-maintained parsing, and a compiler error if the shell and core drift apart.
One core, many platforms [#one-core-many-platforms]
Put the pieces together and the payoff is structural.
* The JavaScript core is portable and unchanged across devices.
* Each platform adds two cheap, generated or layout-only pieces: a native shell and the bindings for the seam.
* Swapping from iOS to Android to desktop changes the shell and the generated bindings—never the protocol logic.
This is the architecture behind [Keet's](https://keet.io) identical behaviour on phones, laptops, and terminals: one core, several UIs. The desktop ([Electron](/explanation/pear-desktop-architecture)) and terminal ([standalone Bare binary](/getting-started/from-a-template/start-from-hello-pear-bare)) hosts ship today. On mobile, [`pear-runtime`](/reference/pear/runtime) itself targets desktop; its mobile counterpart is [`pear-mobile`](https://www.npmjs.com/package/pear-mobile), the embeddable Pear runtime for mobile applications—or wire the worklet and updates yourself with `bare-kit`.
Common questions [#common-questions]
Does Bare run on iOS and Android? [#does-bare-run-on-ios-and-android]
Yes. `bare-kit` embeds a Bare worklet in native iOS and Android apps today, and `react-native-bare-kit` does the same for React Native and Expo. The [`pear-runtime`](/reference/pear/runtime) equivalent for mobile is [`pear-mobile`](https://www.npmjs.com/package/pear-mobile) (noted earlier on this page).
How does native code talk to the JavaScript core? [#how-does-native-code-talk-to-the-javascript-core]
Through an IPC channel between the host and the worklet. You can write bytes directly, or—recommended—put a [typed RPC seam](#the-typed-rpc-seam) on top so both sides call generated, type-checked methods instead.
How is this different from React Native's own JavaScript engine? [#how-is-this-different-from-react-natives-own-javascript-engine]
React Native runs your UI's JavaScript on the main JS thread. A Bare worklet is a *separate*, isolated runtime for your peer-to-peer core, running off the UI thread with its own module system and native addons. The two communicate over IPC; the worklet keeps networking and storage out of the UI's way.
Do I have to write the protocol twice—once in JS, once in Swift? [#do-i-have-to-write-the-protocol-twiceonce-in-js-once-in-swift]
No. You define the schema once with `hyperschema` and generate bindings for each language. The Swift, JavaScript (and forthcoming C/Kotlin) sides are all generated from—and wire-compatible with—that single source.
See also [#see-also]
* [`bare-kit` reference](/reference/bare/bare-kit)—the Worklet and IPC API for iOS, Android, and React Native.
* [Embed Bare in a React Native app](/how-to/run-on-native/embed-bare-in-react-native)—start a worklet and exchange messages.
* [Type a native RPC bridge](/how-to/run-on-native/type-a-native-rpc-bridge)—generate a typed seam with `hyperschema` and `bare-rpc`.
* [Bundle a Bare app](/how-to/run-on-native/bundle-a-bare-app)—produce an embeddable bundle or a standalone binary.
* [Workers](/explanation/workers)—the same host-and-core split on the desktop.
* [Inside Bare](/explanation/bare-runtime)—the runtime the worklet is an instance of.
# Inside Bare
[Bare](https://github.com/holepunchto/bare) is the JavaScript runtime every Pear app runs on. Like Node.js, it gives you an asynchronous, event-driven environment for writing applications in JavaScript. Unlike Node.js, it treats **embedding** and **cross-device support** as core use cases—it aims to run just as well inside a phone app as on a laptop or a server. This page explains what that buys you and why the runtime is shaped the way it is.
* For the exact API, see the [`Bare` runtime reference](/reference/bare/runtime).
* For where Bare sits relative to Pear, see [How Pear and Bare fit together](/explanation/pear-and-bare).
What Bare adds, and what it leaves out [#what-bare-adds-and-what-it-leaves-out]
Bare is built on two C libraries: [`libjs`](https://github.com/holepunchto/libjs), which provides low-level bindings to V8 (or QuickJS, via [`libqjs`](https://github.com/holepunchto/libqjs)) in an engine-independent way, and [`libuv`](https://github.com/libuv/libuv), which provides the asynchronous I/O event loop. On top of those primitives Bare adds only a few missing pieces:
1. A **module system** supporting both CommonJS and ESM, with bidirectional interoperability between the two.
2. A **native-addon system** supporting both statically and dynamically linked addons.
3. **Lightweight threads** with synchronous joins and `SharedArrayBuffer` support.
Everything else is left to userland. There is no built-in `fs`, no built-in `http`, no bundled standard library—those live in installable [`bare-*` modules](/reference/modules/bare-modules) you add only when you need them. The runtime itself stays succinct and, well, *bare*.
That minimalism is a deliberate "less is more" stance, and it pays off in two ways. Bundles only carry the modules an app actually declares, so they stay small enough to embed on a phone. And because the standard library isn't baked into the runtime, you can upgrade Bare without being forced to refactor dependencies in lockstep.
Engine independence [#engine-independence]
By abstracting the JavaScript engine behind the `libjs` ABI and platform I/O behind `libuv`, Bare lets a native addon run on *any* engine that implements the `libjs` ABI and *any* system `libuv` supports. In practice that means Bare can be compiled against V8, through [`libqjs`](https://github.com/holepunchto/libqjs), QuickJS, or through [`libjsc`](https://github.com/holepunchto/libjsc), JavaScriptCore — useful on platforms like iOS where JSC is the sanctioned engine. The addon you wrote against Bare doesn't change.
The lifecycle [#the-lifecycle]
A server runtime can assume it owns the process and runs until it's killed. A runtime embedded in a mobile app can't: the operating system suspends apps that move to the background and may reclaim them entirely. Bare models this explicitly with a process lifecycle that an embedder — or your JavaScript — can drive.
Calling `Bare.suspend()` emits a `suspend` event, signalling that outstanding work (network activity, file access) should be deferred or paused. When the loop runs out of work it emits `idle` and blocks rather than exiting, keeping the process alive but quiet. `Bare.resume()` emits `resume` and lets the loop continue; `Bare.wakeup()` allows a bounded burst of work (**awake** state) during suspension before the process settles back to idle.
This is what lets a peer-to-peer core behave correctly when a phone locks the screen: it parks its sockets on `suspend`, sits quietly at `idle`, and picks back up on `resume`—instead of being killed mid-replication. The [full state machine and event list](/reference/bare/runtime#lifecycle) is in the reference.
Common questions [#common-questions]
Is Bare a fork of Node.js? [#is-bare-a-fork-of-nodejs]
No. Bare is a separate runtime built on `libjs` and `libuv`. The surface looks familiar—asynchronous, event-driven, module-based—but Bare drops Node's server-oriented assumptions and its bundled standard library. The [`bare-node`](https://github.com/holepunchto/bare-node) shim maps many Node.js builtins onto their `bare-*` equivalents to ease porting.
Can I use npm modules with Bare? [#can-i-use-npm-modules-with-bare]
Pure-JavaScript packages from npm generally work, and Bare uses the npm dependency model. Packages that depend on Node's built-in modules need the corresponding [`bare-*` module](/reference/modules/bare-modules) (or the `bare-node` shim), and packages with native addons need to be built against Bare's addon API rather than Node's N-API (the [`bare-compat-napi`](https://github.com/holepunchto/bare-compat-napi) headers ease that transition).
For the full builtin-to-`bare-*` mapping, see [Node.js compatibility](/reference/modules/bare-modules#nodejs-compatibility).
Do users need Node.js installed to run a Bare app? [#do-users-need-nodejs-installed-to-run-a-bare-app]
No. A Bare program can be compiled into a single standalone executable with `bare-build`—this is how the [`hello-pear-bare`](/getting-started/from-a-template/start-from-hello-pear-bare) template ships—so no Node.js, Bare, or [Pear CLI](/reference/pear/cli) is required on the user's machine.
Which JavaScript engine does Bare use? [#which-javascript-engine-does-bare-use]
It depends on the build. Bare talks to the engine through the `libjs` ABI, so it can be compiled against V8 (the default), QuickJS via `libqjs`, or JavaScriptCore via `libjsc`. Your application and addons don't change between engines.
See also [#see-also]
* [Using Bare on its own](/explanation/use-bare-standalone)—the runtime-only path, for adopting Bare without Pear.
* [`Bare` runtime reference](/reference/bare/runtime)—the `Bare` global API, lifecycle events, addons, and threads.
* [`bare` CLI reference](/reference/bare/cli)—running scripts and the REPL from the command line.
* [Bare modules](/reference/modules/bare-modules)—the `bare-*` standard library you opt into.
* [One core, many platforms](/explanation/bare-on-native)—embedding the runtime in native and mobile apps.
* [Handle app suspension](/how-to/run-on-native/handle-app-suspension)—stop all I/O on `suspend` or the OS will force-terminate the app.
* [Runtime and languages](/explanation/runtime-and-languages)—why Pear is JavaScript and how other languages plug in.
* [How Pear and Bare fit together](/explanation/pear-and-bare)—where the runtime sits relative to Pear.
# Dependencies and network
Two questions come up enough during onboarding:
* [Why Pear uses npm at all when applications run on Bare, not Node?](#why-npm-for-dependencies)
* [What peers can learn about you when you join a swarm?](#what-peers-learn-from-your-ip)
Both answers have the same shape—a deliberate trade-off between developer ergonomics and the platform's clean-room ideals.
Why npm for dependencies [#why-npm-for-dependencies]
npm is a great package manager for JavaScript, and most JavaScript developers already know how to use it. All of Holepunch's modules—[Hypercore](/reference/building-blocks/hypercore), [Hyperdrive](/reference/building-blocks/hyperdrive), [Hyperbee](/reference/building-blocks/hyperbee), the lot—are published there. Reinventing a peer-to-peer package manager would have meant reinventing every developer's habits at the same time, for very little upside.
The bootstrap relationship is what's interesting: npm and Node.js are required to **install** Pear initially (`npm install -g pear`), but once the platform is set up neither is needed at runtime. The `pear` command after install is using Bare, not Node, to run your application; npm was just the delivery mechanism.
What dependencies your application declares stays meaningful, though. When you `pear stage`, every dependency in your `package.json` is bundled into the application's hyperdrive and replicated to peers along with your code. A few practical implications follow:
* **Audit before you ship.** Run `pear stage --dry-run` to review the file list before announcing a release; this is where you'd catch a dependency that ballooned in size or pulled in something unexpected.
* **Updates ship fully replicated.** If you update a dependency, you're not merely changing a `package-lock.json`—you're shipping the actual new code to every running peer. Ordinary semver discipline applies, but the consequence is more direct than on a server-rendered web app.
Dependency layout for Pear apps [#dependency-layout-for-pear-apps]
Bare loads modules from `node_modules` the same way Node does during development, and Pear replicates those trees into the application hyperdrive at stage time. A few layout rules keep staging predictable:
1. **Use `node_modules` for dependencies**—Pear picks them up during development and includes them when you stage.
2. **Use `package.json`**—Pear reads it for application metadata and dependency lists.
3. **Do not bundle dependencies into a single file**—bundlers that inline `node_modules` fight Pear's model of replicating discrete packages. Ship source and dependencies as separate files instead.
TypeScript is supported. Not every Holepunch module ships its own typings yet; the community [holepunch-types](https://github.com/Drache93/holepunch-types) project aggregates coverage. An IDE with TypeScript language service helps even for plain JavaScript projects.
If you compile TypeScript locally, keep dependencies external. With Bun:
```bash
bun build index.ts --packages=external --outdir=.
```
The `--packages=external` flag compiles your application code without inlining `node_modules`. Avoid bundling dependencies into the output artifact you stage.
**Never load JavaScript over HTTP(S).** Loading code from an external source is dangerous—if that source is compromised or malicious, your app can be exploited, and the risk is worse for apps with native API access. Pear blocks HTTP and HTTPS code loading by default to prevent this supply-chain risk. Ship dependencies with the app (as above) instead of fetching them at runtime.
What peers learn from your IP [#what-peers-learn-from-your-ip]
When you connect to a swarm—directly via `hyperswarm`, or transitively because you're running a Pear application that swarms—your IP address is exposed to the peers you connect to. This is unavoidable for the same reason it's unavoidable for any peer-to-peer network: peers need a routable address to reach you, and IP is what TCP/UDP transport provides.
This means a peer you connect to can, in principle:
* Geolocate you to the level of granularity their IP database supports (typically city, sometimes ISP).
* Correlate your presence on multiple swarms if they participate on more than one.
* Log timing of your connections and disconnections.
What they can't do without further ado:
* Read your traffic (Pear connections are end-to-end encrypted via [Secretstream](/reference/helpers/secretstream))
* Impersonate you (your peer key is a public key you control)
* Identify you across IP changes (the IP changes; your peer key is what's stable)
If your IP is sensitive—you're a journalist, an activist, or just privacy-conscious—route Pear's traffic through a VPN or Tor. The peer-to-peer protocol doesn't care what's underneath the transport, and using a privacy network shifts the IP-disclosure surface from your real address to the exit node's.
See also [#see-also]
* [Connect to many peers by topic with Hyperswarm](/how-to/connect-to-peers/connect-to-many-peers-by-topic-with-hyperswarm)—joining a swarm in practice.
* [Peer-to-peer, demystified](/explanation/peer-to-peer-demystified)—conceptual overview of HyperDHT and Hyperswarm.
* [Secretstream](/reference/helpers/secretstream)—the encryption layer on every Pear peer connection.
* [Storage and distribution](/explanation/storage-and-distribution)—what actually crosses the wire when peers replicate.
* [Hyperswarm reference](/reference/building-blocks/hyperswarm)—topic-based peer discovery and connection management.
* [HyperDHT reference](/reference/building-blocks/hyperdht)—the lower-level DHT layer handling hole punching and IP routing.
# Deployment - Releasing Apps P2P
This page explains **why** many Pear **desktop** release flows use three operations: **stage**, **provision**, and **multisig**, and how **release lines** and the **deployment directory** fit around them.
Read it before you run commands so the mental model matches the CLI (concrete steps live under [Deploy your application](/how-to/operate-an-app/manual-deployment/deployment) and [Build desktop distributables](/how-to/operate-an-app/build-and-package/build-desktop-distributables)).
{/*
Shared snippet (content/_snippets/) included via Fumadocs by the full-control
release pages, pointing readers at the CI shortcut for the simple publish/update path.
See: https://www.fumadocs.dev/docs/markdown#include
*/}
For the simplest publish/update workflow, let CI stage for you. [Publish with GitHub Actions](/how-to/operate-an-app/github-actions/publish-with-github-actions) turns shipping a new version into a `git push`. This page is the full-control path when you need release lines, provision, and multisig.
**Operator detail:** [Deploy your application](/how-to/operate-an-app/manual-deployment/deployment), [Build desktop distributables](/how-to/operate-an-app/build-and-package/build-desktop-distributables), and [Troubleshoot desktop releases](/how-to/operate-an-app/manual-deployment/troubleshoot-desktop-releases) carry the same pipeline as these diagrams. The [Glossary](#glossary) below defines the terms.
The short version [#the-short-version]
Centralized deploy pipelines often separate *staging servers*, *preview*, and *production*. Pear can fold similar **trust boundaries** into **different Hyperdrives addressed by different `pear://` links**:
1. You **stage** a folder of builds into a drive used for iteration,
2. You **provision** from a versioned stage into a leaner prerelease drive, and
3. You **multisig-commit** into production so a **quorum of signers** must agree. **Each hop can shrink history or raise assurance.**
OTA update event lifecycle [#ota-update-event-lifecycle]
A running Pear desktop app polls the [Hyperdrive](/reference/building-blocks/hyperdrive) behind its `upgrade` link, downloads new application data when the [Hypercore](/reference/building-blocks/hypercore) length advances, and emits two events from [`pear.updater`](/reference/pear/runtime). The host process forwards them to renderers so the UI can react:
* [`updating`](/reference/pear/runtime#updates) fires when the updater begins streaming new blocks; treat it as "background work in progress."
* [`updated`](/reference/pear/runtime#updates) fires when the new build is fully on disk; it is safe to swap.
* [`bridge.applyUpdate()`](https://github.com/holepunchto/pear-docs/blob/preview/examples/getting-started/pear-chat/electron/preload.js#L9) (renderer side) calls [`pear.updater.applyUpdate()`](https://github.com/holepunchto/pear-runtime-updater#await-updaterapplyupdate) (updater worker side). [`applyUpdate()`](https://github.com/holepunchto/pear-runtime-updater#await-updaterapplyupdate) renames the application directory to the new build and deletes the old one—until the process restarts, the running code is still the old build.
* [`bridge.appAfterUpdate()`](https://github.com/holepunchto/pear-docs/blob/preview/examples/getting-started/pear-chat/electron/preload.js#L10) triggers [`app.relaunch()`](https://www.electronjs.org/docs/latest/api/app#apprelaunchoptions) and [`app.quit()`](https://www.electronjs.org/docs/latest/api/app#appquit). On Linux AppImage you usually relaunch with `process.env.APPIMAGE` instead of `process.execPath` so the host wrapper script gets re-executed—see [`app:afterUpdate` in pear-chat](https://github.com/holepunchto/pear-docs/blob/preview/examples/getting-started/pear-chat/electron/main.js#L234).
You can disable updates per run with `--no-updates` (handy in development) or globally by setting `"updates": false` in `package.json` and spreading the package config into the `PearRuntime` options.
The two-event split is what lets you build UI like the "Update ready" banner in [Reshape into a production app](/getting-started/build-a-peer-to-peer-chat/reshape-into-a-production-app): show a spinner on `updating`, swap to a restart button on `updated`, restart the app on click.
Stage, provision, multisig [#stage-provision-multisig]
* **Stage**—Local and team checks: feature branches, unsigned or lightly signed builds, ephemeral links. Appends to the application drive; good for iteration.
* **Provision**—Prerelease / QA / dogfood: synchronizes from a **versioned** stage source onto a target link while **compacting** additions and deletions so the drive is closer to what stakeholders mirror.
* **Multisig**—Production: writes require **co-signing** up to a configured quorum so one compromised machine cannot redefine the release line.
Each stage link can feed the next operation; a **provisioned** link becomes the source for **multisig** commits once signers agree.
Deployment directory and release lines [#deployment-directory-and-release-lines]
A **deployment directory** is the multi-architecture output you assemble after per-OS **make** steps (often with `pear build` merging `darwin`, `linux`, and `win32` artifacts). That directory is what **`pear stage`** reads from disk and writes into [Hypercore](/reference/building-blocks/hypercore)-backed storage for a given **release line** link.
**Release lines** are parallel stability tracks: common names are **development**, **staging**, **rc** (each a **staged** link), then **prerelease** (provisioned from `rc`), then **production** (multisig’d from prerelease). The **`upgrade`** field in `package.json` decides **which link** a shipped binary follows for OTA—so different builds can track different lines intentionally.
A common pattern is that **`rc`’s `upgrade` pins the production multisig key**, so `rc` builds **do not** receive casual OTA bumps—you ship new installers when that line moves.
Release cycle (steady state) [#release-cycle-steady-state]
Once bootstrapping finishes, the steady **release cycle** is repetitive: bump **`version`**, **make** per platform, **build** the deployment directory, **stage**, iterate; when stable, **provision**; when assessed, run **multisig** prepare → sign → verify → commit; production goes live; the next cycle starts again at **version**.
Numbered labels align with common documentation ordering (touch/seed and upgrade-link setup happen **before** this loop is warm).
Foundational steps (bootstrap + loop) [#foundational-steps-bootstrap--loop]
The **foundational** diagram adds multisig **key creation** and config **beside** the main loop: signing keys, the multisig config in `pear.json`, pointing `upgrade` at the multisig link, then joining the same release flow.
**Stage-only** is enough for proofs of concept; **production** benefits from quorum signing and machine-independent drives.
From per-OS builds to one directory [#from-per-os-builds-to-one-directory]
That directory must at least contain `package.json` and `by-arch/.../app` trees before `pear stage` is meaningful.
Multisig setup and signing [#multisig-setup-and-signing]
The diagrams below follow [`hello-pear-electron`'s Foundational Steps](https://github.com/holepunchto/hello-pear-electron#foundational-steps)—the same Electron + Bare worker template [Keet](https://keet.io) and [PearPass](https://pass.pears.com) ship. **One-time** multisig wiring is in [Set up multisig](/how-to/operate-an-app/multisig/set-up-multisig); every production shipment after that uses [Sign with multisig](/how-to/operate-an-app/multisig/sign-with-multisig). If a commit fails mid-flight, see [Troubleshoot multisig](/how-to/operate-an-app/multisig/troubleshoot-multisig).
How setup connects to the release cycle [#how-setup-connects-to-the-release-cycle]
The [multisig config](/how-to/operate-an-app/multisig/set-up-multisig#create-the-multisig-config) in `pear.json` derives the **multisig link** from its `namespace`, `publicKeys`, and `quorum` alone—it does **not** reference the provision drive. The provision link from the most recent [`hello-pear-electron`](https://github.com/holepunchto/hello-pear-electron) `pear stage` / [`pear provision`](/how-to/operate-an-app/manual-deployment/deployment#6-provision) is instead supplied as the **source** when you prepare and commit each signing request. Shipped binaries read the **multisig link** from [`package.json` `upgrade`](/how-to/operate-an-app/multisig/set-up-multisig#set-upgrade-to-the-multisig-link).
Quorum signing [#quorum-signing]
Each production commit runs the four steps in [Sign with multisig](/how-to/operate-an-app/multisig/sign-with-multisig): [`pear multisig request`](/how-to/operate-an-app/multisig/sign-with-multisig#prepare-the-request), [`pear multisig sign`](/how-to/operate-an-app/multisig/sign-with-multisig#sign) from each signer until [quorum](/how-to/operate-an-app/multisig/set-up-multisig#create-the-multisig-config) is met, [`pear multisig verify`](/how-to/operate-an-app/multisig/sign-with-multisig#verify), then [`pear multisig commit`](/how-to/operate-an-app/multisig/sign-with-multisig#commit).
Release lines [#release-lines]
For [`hello-pear-electron`](https://github.com/holepunchto/hello-pear-electron), one [`pear build`](https://github.com/holepunchto/hello-pear-electron#deploying) output can feed parallel **stage** links; **prerelease** and **production** are the provision and multisig gates on the trust ladder.
**Custom** lines are optional forks for spikes, hotfixes, or instrumented builds—same mechanics, different seeded link.
Relationship to Pear’s global storage story [#relationship-to-pears-global-storage-story]
Platform installs still use Pear’s OS-wide tree described in [Storage and distribution](/explanation/storage-and-distribution). The diagrams here are about **application release artifacts** moving between links—not replacing that global layout.
Glossary [#glossary]
Terms you will see across the **Pear desktop release** and **OTA update** docs:
| Term | Meaning |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **OTA** | Over-the-air: delivering a new app build without a traditional reinstall flow from a store. |
| **OTA updates** | Syncing the running app’s bundle from a peer-to-peer source when the [application drive](#deployment-directory-and-release-lines) changes. |
| **P2P** | Peer-to-peer: machines replicate directly; distribution does not require a single central server if seeders exist. |
| **Application drive** | The [Hyperdrive](/reference/building-blocks/hyperdrive) that holds the published app files and version history for a given `pear://` link. |
| **Deployment directory** | The multi-architecture folder produced after per-OS builds are assembled (for example with `pear build`) and before `pear stage`. See [Deployment directory and release lines](#deployment-directory-and-release-lines). |
| **Multisig** | Co-signing: a quorum of signers must approve before writes land on the production drive. |
| **Pear link** | Stable `pear://…` identifier the swarm routes on; see the **Links** row in [Command Line Interface](/reference/pear/cli) and [Storage and distribution](/explanation/storage-and-distribution). |
| **Quorum** | Minimum number of multisig signers required to commit a release. |
| **Release line** | A parallel deployment stream (for example development, staging, rc) at its own stability level, each with its own staged link. |
| **Seeding** | Keeping a drive announced and available so peers can discover and replicate it (`pear seed`). |
| **Vendor signing** | OS-level code signing (Apple notarization, Windows Authenticode, etc.) so distributables run on other machines without quarantine. |
| **Versioned link** | A `pear://` link that pins `fork`, `length`, and `key` of the [Hypercore](/reference/building-blocks/hypercore) behind the application Hyperdrive—used when provisioning between known versions. |
Where to go next [#where-to-go-next]
* [Pear desktop application architecture](/explanation/pear-desktop-architecture)—workers, storage, and update events in the running app.
* [Deploy your application](/how-to/operate-an-app/manual-deployment/deployment)—operator checklist for `pear stage` / `pear provision` / multisig tooling.
* [Build desktop distributables](/how-to/operate-an-app/build-and-package/build-desktop-distributables)—per-OS makes and signing pointers.
* [Desktop release npm scripts](/reference/ci-and-release/desktop-release-npm-scripts)—common `package.json` scripts.
* [Troubleshoot desktop releases](/how-to/operate-an-app/manual-deployment/troubleshoot-desktop-releases)—OTA, staging, and `pear build` pitfalls.
# From append-only logs to files
Pear storage is built from a small set of composable primitives stacked on top of one another:
At the bottom is **[Hypercore](#hypercore-append-only-blocks)**, an append-only log of verified blocks. Everything else in Pear storage ultimately replicates through one or more cores.
**[Hyperblobs](#hyperblobs-large-opaque-objects)** sits on a core when you need opaque objects larger than a single block—it handles chunking and returns stable ids you can store elsewhere.
**[Hyperdrive](#hyperdrive-paths-metadata-and-directories)** is the top layer: path-addressed files and directories, with metadata in a [Hyperbee](/reference/building-blocks/hyperbee) tree and file contents in **[Hyperblobs](#hyperblobs-large-opaque-objects)**.
Understanding that ladder helps you pick the right building block before you reach for a full filesystem API.
This page is conceptual. For API details, see [Hypercore](/reference/building-blocks/hypercore), [Hyperdrive](/reference/building-blocks/hyperdrive), and [Hyperbee](/reference/building-blocks/hyperbee).
Hypercore: append-only blocks [#hypercore-append-only-blocks]
[Hypercore](/reference/building-blocks/hypercore) is a secure, sparse-replicated append-only log. Each `append` adds one block; readers verify integrity and optionally decrypt per-block. Hypercore is the foundation for nearly every other Pear data structure.
You can store arbitrary bytes directly in a core:
```js
import Hypercore from 'hypercore'
const core = new Hypercore('./my-core')
await core.ready()
await core.append(Buffer.from('I am a block of data'))
```
That works for small payloads, but Hypercore blocks have a practical size limit. Storing a large file as one block is inefficient; splitting it manually means tracking chunk order, offsets, and retrieval yourself.
Hyperblobs: large opaque objects [#hyperblobs-large-opaque-objects]
[Hyperblobs](https://github.com/holepunchto/hyperblobs) chunks large data across [Hypercore](/reference/building-blocks/hypercore) blocks and exposes a simple put/get API. A `put` returns an **id** (block and byte offsets and lengths) that you store elsewhere—for example in a [Hyperbee](/reference/building-blocks/hyperbee) key.
```js
import Hypercore from 'hypercore'
import Hyperblobs from 'hyperblobs'
const core = new Hypercore('./blob-core')
const blobs = new Hyperblobs(core)
await blobs.ready()
const id = await blobs.put(Buffer.from('hello world', 'utf-8'))
const data = await blobs.get(id)
```
Hyperblobs is the right choice when you need **object storage**—attachments, media, serialized blobs—without file paths or directory semantics. Replication still flows through the underlying Hypercore; peers fetch missing blob blocks like any other core data.
[Hyperdrive](/reference/building-blocks/hyperdrive) uses Hyperblobs internally for file contents. You do not need Hyperdrive if all you want is keyed blob storage.
Hyperdrive: paths, metadata, and directories [#hyperdrive-paths-metadata-and-directories]
[Hyperdrive](/reference/building-blocks/hyperdrive) combines a [Hyperbee](/reference/building-blocks/hyperbee) metadata tree with a Hyperblobs content store. You get path-based operations—`get`, `put`, `del`, `list`, existence checks—similar to a filesystem, with the same replication properties as [Hypercore](/reference/building-blocks/hypercore).
```js
import Hyperdrive from 'hyperdrive'
import Corestore from 'corestore'
const store = new Corestore('./drive-storage')
const drive = new Hyperdrive(store)
await drive.ready()
await drive.put('/notes/readme.txt', Buffer.from('hello'))
const buffer = await drive.get('/notes/readme.txt')
```
Pear application bundles are Hyperdrives: code, assets, and dependencies staged with `pear stage` live in a drive that peers replicate. User-facing apps often keep **application state** in separate cores or drives under [Corestore](/reference/helpers/corestore).
Helpers extend the model without changing the stack:
* [Localdrive](/reference/helpers/localdrive)—mirror between a Hyperdrive and a local folder.
* [Mirrordrive](/reference/helpers/mirrordrive)—copy or sync between two drives.
Choosing a layer [#choosing-a-layer]
| Need | Use |
| --------------------------------- | --------------------------------------------------------------------------------------- |
| Ordered event log, small messages | [Hypercore](/reference/building-blocks/hypercore) directly |
| Large binary object, no path | Hyperblobs on a dedicated core |
| Files, directories, bundle layout | [Hyperdrive](/reference/building-blocks/hyperdrive) |
| Sorted key/value over one log | [Hyperbee](/reference/building-blocks/hyperbee) (often inside Hyperdrive or standalone) |
If you do not need path-addressed files shared between peers, prefer Hyperblobs over Hyperdrive. Hyperdrive pays for directory semantics and metadata indexing you may not use.
See also [#see-also]
* [Storage and distribution](/explanation/storage-and-distribution)—where cores and drives live on disk in a Pear installation.
* [Share append-only databases with Hyperbee](/how-to/store-and-replicate/share-append-only-databases-with-hyperbee)—key/value patterns on Hypercore.
* [Work with many Hypercores using Corestore](/how-to/store-and-replicate/work-with-many-hypercores-using-corestore)—managing multiple cores from one storage root.
* [Hypercore reference](/reference/building-blocks/hypercore)—append-only log API.
* [Hyperdrive reference](/reference/building-blocks/hyperdrive)—filesystem API.
* [Hyperbee reference](/reference/building-blocks/hyperbee)—sorted key/value tree.
# About Pear
The pages here are for understanding, not doing. They answer "why" rather than "how": why does Pear use append-only logs, what does "peer-to-peer" mean in practice, what's the difference between Bare and Node, and why is there no central server.
If you want to build something, head to **[How To](/how-to)**. If you need to look up a specific API, that's **[Reference](/reference)**.
In this section [#in-this-section]
Pages are grouped by topic and ordered roughly from foundational concepts to app-specific ones.
Platform foundations [#platform-foundations]
* [How Pear and Bare fit together](/explanation/pear-and-bare)—how Pear and Bare layer together, from the native C foundations up to the apps you run.
* [Peer-to-peer, demystified](/explanation/peer-to-peer-demystified)—hole punching, public-key identity, and the roles of [HyperDHT](/reference/building-blocks/hyperdht) and [Hyperswarm](/reference/building-blocks/hyperswarm).
* [Runtime and languages](/explanation/runtime-and-languages)—JavaScript on Bare, native addons for other languages, and the Pear-end pattern for cross-platform apps.
* [Using Bare on its own](/explanation/use-bare-standalone)—the entry point for adopting Bare as a standalone runtime, without Pear's peer-to-peer platform.
* [Inside Bare](/explanation/bare-runtime)—what the Bare runtime adds, its lifecycle, and why its standard library is opt-in.
* [One core, many platforms](/explanation/bare-on-native)—running the peer-to-peer core in a Bare worklet behind a typed RPC seam.
* [Dependencies and network](/explanation/dependencies-and-network)—why NPM is the install path, the runtime relationship to Node, and what your IP discloses on a swarm.
Storing & replicating data [#storing--replicating-data]
* [From append-only logs to files](/explanation/from-logs-to-files)—Hypercore, Hyperblobs, and [Hyperdrive](/reference/building-blocks/hyperdrive)—which storage layer to use and why.
* [Storage and distribution](/explanation/storage-and-distribution)—where Pear keeps your data, what the swarm replicates, and how new releases reach users.
* [Availability and blind peering](/explanation/availability-and-blind-peering)—seeding, its limits, and always-on replication without reading user data.
Building & shipping apps [#building--shipping-apps]
* [Pear desktop application architecture](/explanation/pear-desktop-architecture)—how a typical Pear Electron app splits updates, storage, and Bare workers (with a link to a full sample repo).
* [Workers](/explanation/workers)—why peer-to-peer logic lives in a Bare worker behind one IPC stream, and where the host/worker boundary should sit.
* [Release pipeline](/explanation/deployment-releasing-apps-p2p)—stage, provision, multisig, release lines, and deployment-directory diagrams (agnostic; sample implementation on GitHub).
{/* Planned explanation pages. Uncomment each bullet as the page lands.
More conceptual overviews are in flight; topics planned to land here include:
- **What is Pear?**—the runtime, the toolchain, and the philosophy in plain language.
- **Append-only logs are a database**—why [Hypercore](/reference/building-blocks/hypercore) looks weird if you're coming from SQL.
- **The runtime model**—how Pear apps start, update, and shut down.
*/}
Coming from the old FAQ? [#coming-from-the-old-faq]
The single FAQ page was retired. Each question now lives in the section it actually belongs to:
| Old FAQ question | New home |
| --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| *How do I get a list of installed applications?* | [Manage installed applications](/how-to/manage-installed-applications) |
| *How do I uninstall a Pear application?* | [Manage installed applications](/how-to/manage-installed-applications) |
| *Where is the Pear application stored?* | [Storage and distribution](/explanation/storage-and-distribution) |
| *Can Pear be used with X language?* | [Runtime and languages](/explanation/runtime-and-languages) |
| *How do I write an application once that runs on desktop, mobile, etc.?* | [Runtime and languages](/explanation/runtime-and-languages) · [One core, many platforms](/explanation/bare-on-native) |
| *Is Bare a fork of Node? Can I use npm modules?* | [Inside Bare](/explanation/bare-runtime) |
| *Can Bare run on iOS or Android?* | [One core, many platforms](/explanation/bare-on-native) |
| *How is my application distributed? Do I have to keep `pear seed` running?* | [Storage and distribution](/explanation/storage-and-distribution) |
| *Why is NPM used for dependencies?* | [Dependencies and network](/explanation/dependencies-and-network) |
| *How do I distribute a binary version of my application?* | [Distribute as a binary](/how-to/operate-an-app/build-and-package/distribute-as-binary) |
| *Can peers know my IP address when using `hyperswarm`?* | [Dependencies and network](/explanation/dependencies-and-network) |
{/* Writing a new explanation? See [Diátaxis on explanation](https://diataxis.fr/explanation/)—discursive, comparative, opinionated where it helps. Don't list APIs; that's reference. Don't tell readers to do anything; that's how-to. */}
# How Pear and Bare fit together
Pear is the platform people see: a runtime, a CLI, and over-the-air updates for peer-to-peer apps. [Bare](/explanation/bare-runtime) is the engine underneath it. They sit at different layers, and knowing which layer you're working at makes the rest of these docs easier to navigate.
This page lays out the layers, bottom to top, and shows where each library you'll meet elsewhere belongs.
The layers at a glance [#the-layers-at-a-glance]
Each layer runs on the one beneath it. Read from the bottom up, it's a story about how raw C bindings become a peer-to-peer app you can install.
The engine room: native foundations and the Bare runtime [#the-engine-room-native-foundations-and-the-bare-runtime]
At the very bottom are C libraries: [`libjs`](https://github.com/holepunchto/libjs) (and its JavaScriptCore-backed sibling [`libjsc`](https://github.com/holepunchto/libjsc)) give an engine-independent, ABI-stable way to talk to a JavaScript engine; [`libuv`](https://github.com/libuv/libuv) provides the asynchronous I/O event loop; [`libudx`](https://github.com/holepunchto/libudx) carries the reliable UDP streams the networking stack rides on.
[Bare](/explanation/bare-runtime) sits directly on top. It's a small, embeddable JavaScript runtime that adds only what those C primitives can't supply on their own: a module system (with CommonJS/ESM interop), a native-addon loader, and lightweight threads. Everything else is left to userland—which is the next layer up.
Bare userland: the bare-* modules [#bare-userland-the-bare--modules]
Bare ships almost no standard library. The familiar runtime surface—file system, sockets, crypto, HTTP—lives in installable [`bare-*` modules](/reference/modules/bare-modules) you opt into. The same layer holds two other families that matter for cross-platform apps:
* **Embedding & native** ([`bare-kit`](/reference/bare/bare-kit), [`react-native-bare-kit`](/reference/bare/bare-kit), and the typed RPC seam of [`bare-rpc`](/reference/modules/bare-modules) + [`hyperschema`](https://github.com/holepunchto/hyperschema)) let a native app run a Bare core on a background thread. See [One core, many platforms](/explanation/bare-on-native).
* **Build & bundle** (`bare-pack`, `bare-bundle`, `bare-make`, `bare-build`) turn a Bare program and its dependencies into an embeddable bundle or a standalone executable.
The peer-to-peer building blocks [#the-peer-to-peer-building-blocks]
The libraries Pear is famous for—[Hypercore](/reference/building-blocks/hypercore), [Hyperbee](/reference/building-blocks/hyperbee), [Hyperdrive](/reference/building-blocks/hyperdrive), [Autobase](/reference/building-blocks/autobase), [Hyperswarm](/reference/building-blocks/hyperswarm), [HyperDHT](/reference/building-blocks/hyperdht), and [Corestore](/reference/helpers/corestore)—are ordinary JavaScript modules. They have no special status in the runtime; they run *on* Bare like any other dependency. That's why the same storage and networking code works unchanged whether it's hosted by Electron on the desktop or a worklet on a phone.
The Pear platform [#the-pear-platform]
[Pear](/) is the layer that turns those building blocks into a product: [`pear-runtime`](/reference/pear/runtime) spawns and updates your app, the [`pear-*` modules](/reference/modules/pear-modules) supply application services, and the [Pear CLI](/reference/pear/cli) stages, seeds, and releases it. Pear is built *on* Bare and the building blocks—it doesn't replace them.
Apps: one core, many UI hosts [#apps-one-core-many-ui-hosts]
At the top are the apps—[Keet](https://keet.io), [PearPass](https://pass.pears.com), and whatever you build. The recommended shape splits an app into a portable JavaScript **core** (peer-to-peer logic and storage) and a thin **UI host** that changes per platform: Electron on desktop, a native shell on mobile, a standalone binary in the terminal. The core is the same code everywhere; only the host swaps. That split is the subject of [Runtime and languages](/explanation/runtime-and-languages) and [One core, many platforms](/explanation/bare-on-native).
See also [#see-also]
* [Inside Bare](/explanation/bare-runtime)—what the runtime layer actually adds.
* [One core, many platforms](/explanation/bare-on-native)—how the portable core reaches mobile and native apps.
* [Runtime and languages](/explanation/runtime-and-languages)—why the stack is JavaScript and how other languages join in.
* [Bare modules](/reference/modules/bare-modules)—the catalog of `bare-*` userland modules.
* [Pear modules](/reference/modules/pear-modules)—the `pear-*` libraries at the platform layer.
# Pear desktop application architecture
This page explains **why** a production-style Pear **Electron** app usually separates three concerns:
1. **over-the-air (OTA) updates**,
2. **persistent peer-to-peer storage**, and
3. **Bare workers** behind a single IPC stream.
Read it if you are sketching your own main/renderer/worker split or comparing a full runtime setup to the minimal [getting started chat](/getting-started/build-a-peer-to-peer-chat/build-a-peer-to-peer-chat).
The short version [#the-short-version]
The pattern optimizes to:
* **ship new builds without a central server**
* **keep replication-capable storage beside the app**
* **keep native P2P modules out of the renderer**
A [**Bare worker**](/explanation/workers) owns the [`pear-runtime`](/reference/pear/runtime) instance together with [Hyperswarm](/reference/building-blocks/hyperswarm), [Hypercore](/reference/building-blocks/hypercore), and the [OTA updater](/reference/pear/runtime#updates); Electron's [main process](#process-model) is a thin shell that spawns the worker and forwards [IPC](/explanation/workers#the-ipc-contract); the [renderer](#process-model) stays a normal web view. Updates flow when the [**application Hyperdrive**](/reference/building-blocks/hyperdrive) changes; the runtime signals the UI, then swaps paths on disk so the [**next process start**](#updates) runs the new code.
The official [`hello-pear-electron`](https://github.com/holepunchto/hello-pear-electron) template uses this worker-hosted shape, and the [getting started production-shape part](/getting-started/build-a-peer-to-peer-chat/reshape-into-a-production-app) follows it—running the `pear-runtime` updater in its own dedicated Bare worker so update traffic never blocks the chat worker.
Process model [#process-model]
The renderer does not load `hyperswarm`, `hypercore`, or other Bare-oriented modules directly. The main process starts the worker with [`PearRuntime.run`](/reference/pear/runtime#running-workers) (or the instance method [`pear.run`](/reference/pear/runtime#running-workers)) and forwards bytes between the worker’s [`Bare.IPC`](/reference/pear/runtime#running-workers) stream and whatever bridge you expose to the renderer.
Updates [#updates]
An **update** is triggered when a **seeded application drive** gains new writes: the replicated [Hyperdrive](/reference/building-blocks/hyperdrive) behind your `pear://` link reflects a new staged or provisioned build. The runtime emits **`updating`** while it syncs, then **`updated`** when the new bundle is ready. These events are emitted on the runtime's [`pear.updater`](/reference/pear/runtime#updates) sub-object—handlers attach with `pear.updater.on('updating')` / `pear.updater.on('updated')`, and the staged update is applied with `pear.updater.applyUpdate()`.
After `updated`, a common shell **repoints the active application path** to the freshly synced build and removes the old tree from disk so the **next start** runs the new code. That matches OTA expectations: sync in the background, switch on restart (or after your UI explicitly restarts).
Disable updates per run (`--no-updates`) or with [`package.json` `updates: false`](/reference/pear/runtime#disabling-updates) during local development so a seeded link does not replace your working tree mid-session.
Storage [#storage]
The runtime’s **`dir`** option is the root for **peer-to-peer and local application data**. In production that usually maps to per-OS application support directories; in development many teams use a **separate dev default** or a flag. [`pear.storage`](/reference/pear/runtime#storage) is the string you pass into [`Corestore`](/reference/helpers/corestore) so every core shares one coherent on-disk layout.
Passing **`--storage /path`** (or equivalent) spins up an **isolated Corestore**—the same idea as running two app instances on two machines: different storage roots, no key collisions.
Workers [#workers]
**Application P2P logic**—swarms, cores, drives—belongs in the worker entrypoint. Arguments you pass from `pear.run('./workers/main.js', [pear.storage, …])` show up as [`Bare.argv`](/reference/pear/api#bare-argv) inside the worker (`argv[0]`/`argv[1]` are reserved; **`argv[2]`** is the first user argument, which is why sample apps often pass storage at index `2`).
Rule of thumb: **main = shell + IPC**, **worker = data plane**, **renderer = view**.
Where this differs from the minimal tutorial [#where-this-differs-from-the-minimal-tutorial]
The [getting started chat](/getting-started/build-a-peer-to-peer-chat/build-a-peer-to-peer-chat) walkthrough uses [`PearRuntime.run()`](/reference/pear/runtime#running-workers) so you can paste a tiny worker without configuring `upgrade` or `dir`. A shipped desktop app switches on the **full `new PearRuntime({ ... })` constructor** so OTA, storage, and the updater share one runtime object—the shape in the [`pear-runtime` reference](/reference/pear/runtime). In the official [`hello-pear-electron`](https://github.com/holepunchto/hello-pear-electron) template, that constructor runs inside the Bare worker, keeping the main process a thin proxy; the [getting started production-shape part](/getting-started/build-a-peer-to-peer-chat/reshape-into-a-production-app) does the same, running the updater in its own dedicated Bare worker.
Where to go next [#where-to-go-next]
* [Start from the hello-pear-electron template](/getting-started/from-a-template/start-from-hello-pear-electron)—a hands-on tour of this architecture in the official boilerplate.
* [Release pipeline](/explanation/deployment-releasing-apps-p2p)—stage, provision, multisig, and diagrams for moving builds between links.
* [Release pipeline glossary](/explanation/deployment-releasing-apps-p2p#glossary)—terminology in one table.
* [Storage and distribution](/explanation/storage-and-distribution)—Pear-wide layout versus per-app `dir`.
* [Deploy your application](/how-to/operate-an-app/manual-deployment/deployment)—when you are ready to run commands.
**Related documentation**
**Getting Started:** [Part 1: Chat](/getting-started/build-a-peer-to-peer-chat/build-a-peer-to-peer-chat) · [Part 2: Production-shaped](/getting-started/build-a-peer-to-peer-chat/reshape-into-a-production-app) · [Part 3: Ship](/getting-started/build-a-peer-to-peer-chat/ship) · [Part 4: Update](/getting-started/build-a-peer-to-peer-chat/update)
**Operating an app**
* [Build desktop distributables](/how-to/operate-an-app/build-and-package/build-desktop-distributables)
* [Desktop release npm scripts](/reference/ci-and-release/desktop-release-npm-scripts)
* [Distribute as a binary](/how-to/operate-an-app/build-and-package/distribute-as-binary)
* [Manage installed applications](/how-to/manage-installed-applications)
* [Troubleshoot desktop releases](/how-to/operate-an-app/manual-deployment/troubleshoot-desktop-releases)
* [Troubleshoot common issues](/how-to/troubleshooting)
# Peer-to-peer, demystified
import { Cards, Card } from 'fumadocs-ui/components/card'
Pear applications replicate data and connect to one another without a central server. Peers exchange bytes directly over encrypted streams; there is no single host that routes every message or stores every copy. That model changes how discovery, connectivity, and privacy work compared with a traditional client–server application—but it does not remove the need for careful application design.
This page explains networking concepts. For step-by-step connection guides, see [Connect two peers by key with HyperDHT](/how-to/connect-to-peers/connect-two-peers-by-key-with-hyperdht) and [Connect to many peers by topic with Hyperswarm](/how-to/connect-to-peers/connect-to-many-peers-by-topic-with-hyperswarm).
What changes without a server [#what-changes-without-a-server]
In a client–server design, clients know where to connect: a hostname or IP address, often fronted by a load balancer. In Pear, **peers are identified by cryptographic public keys**, not by fixed network locations. A peer can move between Wi‑Fi networks, cellular connections, or countries and still be reachable at the same key.
Replication and chat still need **at least one peer online** with a copy of the data you want—Pear does not magically materialize files from nowhere. What changes is *who* can serve that copy: any participant in the swarm, not only the original author.
What does **not** change: you still need to think about availability, authorization, and what metadata leaks at the transport layer.
* [Storage and distribution](/explanation/storage-and-distribution)—how application bundles and user data reach peers over the same primitives.
* [Dependencies and network](/explanation/dependencies-and-network)—what peers can infer from your IP when you join a swarm.
Hole punching and NAT traversal [#hole-punching-and-nat-traversal]
Most devices sit behind home routers or carrier-grade network address translation (NAT). Two peers cannot open a Transmission Control Protocol (TCP) connection to each other simply by knowing each other's keys—neither side has a stable, publicly routable address that the other can dial first.
**User Datagram Protocol (UDP) hole punching** coordinates both peers through a rendezvous point so that each opens a path through its local firewall. Once the "hole" exists, Pear's transport can carry encrypted traffic over it. Hole punching works on most consumer networks; it is not guaranteed on every corporate or symmetric-NAT setup, which is why Pear also supports relay paths when direct connectivity fails.
[HyperDHT](#hyperdht-discovery-and-encrypted-connections) implements this discovery and connection machinery. You rarely call hole punching directly; you create a DHT node or join a [Hyperswarm](/reference/building-blocks/hyperswarm) topic and the stack handles traversal.
HyperDHT: discovery and encrypted connections [#hyperdht-discovery-and-encrypted-connections]
[HyperDHT](/reference/building-blocks/hyperdht) is a distributed hash table. It is the layer that finds peers and establishes **end-to-end encrypted** connections using Noise streams (via [Secretstream](/reference/helpers/secretstream)).
Core mechanisms:
1. **Peer identification**—Connections are addressed by public key, not IP address. Location and network changes do not invalidate identity.
2. **Hole punching**—UDP techniques to connect through NATs and firewalls on typical networks.
3. **Encrypted streams**—Every connection is encrypted; intermediaries see traffic volume and endpoints, not payload.
4. **Bootstrapping**—Default bootstrap nodes help a new node join the public DHT; isolated networks can use custom bootstrap lists.
5. **Announcement and discovery**—Peers announce themselves under 32-byte topics; others look up who is listening on a topic. Peers with a known public key can also connect directly without topic lookup.
See [Connect two peers by key with HyperDHT](/how-to/connect-to-peers/connect-two-peers-by-key-with-hyperdht) for a walkthrough of how to use HyperDHT.
HyperDHT also supports limited mutable and immutable storage in the DHT itself. Most Pear applications instead replicate structured data over [Hypercore](/reference/building-blocks/hypercore) once a connection exists; the DHT's primary job is **finding and connecting**, not long-term storage.
Hyperswarm: topic-based connection management [#hyperswarm-topic-based-connection-management]
[Hyperswarm](/reference/building-blocks/hyperswarm) wraps [HyperDHT](/reference/building-blocks/hyperdht) with a higher-level API oriented around **topics**—arbitrary 32-byte identifiers, often a [Hypercore](/reference/building-blocks/hypercore)'s `discoveryKey`. Where HyperDHT exposes servers, clients, announce streams, and lookup streams, Hyperswarm exposes `join`, `leave`, and a single `connection` event.
[Connect to many peers by topic with Hyperswarm](/how-to/connect-to-peers/connect-to-many-peers-by-topic-with-hyperswarm) for a walkthrough of how to use Hyperswarm.
Hyperswarm adds:
* **Automatic reconnection** when peers drop off the network.
* **Connection limits and firewall hooks** to cap fan-out or reject unwanted keys.
* **Client/server roles per topic**—a peer can announce only, discover only, or both.
* **Direct peer joins** via `joinPeer(publicKey)` when you already know whom to reach.
For replication workflows—chat rooms, file sync, application updates—Hyperswarm is usually the right default: you join the discovery key of the core or drive you care about and let the swarm maintain connections. HyperDHT remains the right choice when you need fine-grained control over server lifecycle, custom DHT storage, or minimal dependencies.
Choosing between HyperDHT and Hyperswarm [#choosing-between-hyperdht-and-hyperswarm]
| Concern | [HyperDHT](/reference/building-blocks/hyperdht) | [Hyperswarm](/reference/building-blocks/hyperswarm) |
| -------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------ |
| API surface | Low-level: nodes, servers, sockets | High-level: topics, connections |
| Reconnection | Your responsibility | Built in |
| Typical use | Custom protocols, direct key connections | [Hypercore](/reference/building-blocks/hypercore) replication, multi-peer apps |
| Underlying transport | UDX + hole punching | Same (uses HyperDHT internally) |
If you are replicating a Hypercore or [Hyperdrive](/reference/building-blocks/hyperdrive), start with Hyperswarm unless you have a specific reason to manage DHT nodes yourself.
See also [#see-also]
* [Connect two peers by key with HyperDHT](/how-to/connect-to-peers/connect-two-peers-by-key-with-hyperdht)—minimal two-peer connection walkthrough.
* [Connect to many peers by topic with Hyperswarm](/how-to/connect-to-peers/connect-to-many-peers-by-topic-with-hyperswarm)—topic-based discovery and chat.
* [Replicate and persist with Hypercore](/how-to/store-and-replicate/replicate-and-persist-with-hypercore)—persistence once peers are connected.
* [Dependencies and network](/explanation/dependencies-and-network)—IP disclosure and NPM's role at install time.
* [From append-only logs to files](/explanation/from-logs-to-files)—how replicated data is structured above the transport layer.
* [HyperDHT reference](/reference/building-blocks/hyperdht)—full API.
* [Hyperswarm reference](/reference/building-blocks/hyperswarm)—full API.
# Runtime and languages
Pear applications are JavaScript programs. The runtime under them is **[Bare](/explanation/bare-runtime)**, a small embeddable JavaScript runtime that strips the assumptions Node.js carries about being a server. This page explains why the language story looks the way it does, how non-JavaScript code joins in, and what the recommended app shape is when you want one codebase to run on desktop, mobile, and terminal.
For where Bare sits relative to Pear, see [How Pear and Bare fit together](/explanation/pear-and-bare).
Why JavaScript [#why-javascript]
Two pragmatic reasons:
1. **Web heritage.** The peer-to-peer libraries Pear is built on ([Hypercore](/reference/building-blocks/hypercore), [Hyperdrive](/reference/building-blocks/hyperdrive), [Hyperswarm](/reference/building-blocks/hyperswarm)) are mature JavaScript modules with millions of downloads. Reusing them on the desktop and on mobile through a single language eliminates a translation layer.
2. **Bare keeps it small.** Bare ships without Node's standard library opinions—no `fs.read` on a URL, no built-in `http` module, no Worker baggage. That makes it cheap to embed in mobile apps, desktop shells, and constrained terminal environments alike. The Pear runtime adds the bits applications actually need on top.
If you're coming from Node.js, the surface looks similar but isn't identical—see [Bare modules](/reference/modules/bare-modules) for the exact set of standard libraries available, and the [Node.js compatibility](/reference/modules/bare-modules#nodejs-compatibility) section for a builtin-by-builtin mapping to the corresponding `bare-*` modules. The [`bare-node`](https://github.com/holepunchto/bare-node) shim maps many Node.js builtins onto their Bare equivalents, easing the port.
Other languages: native addons [#other-languages-native-addons]
For code that JavaScript can't naturally express—tight cryptography loops, codec work, hardware access—Bare loads native addons. The [`bare-addon`](https://github.com/holepunchto/bare-addon) template is the starting point: write the addon in C, C++, Rust, or any language with a C-compatible ABI, expose it through Bare's addon API, and call it from JavaScript like any module.
For languages that compile to JavaScript (TypeScript being the obvious one) the path is unchanged: compile to JS, then point the application's [`main` field or HTML `