LogoPear Docs
About PearBuilding & shipping apps

Pear desktop application architecture

How a typical Pear + Electron desktop app splits OTA updates, on-disk storage, and Bare workers — main process, renderer, and data plane.

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.

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 owns the pear-runtime instance together with Hyperswarm, Hypercore, and the OTA updater; Electron's main process is a thin shell that spawns the worker and forwards IPC; the renderer stays a normal web view. Updates flow when the application Hyperdrive changes; the runtime signals the UI, then swaps paths on disk so the next process start runs the new code.

The official hello-pear-electron template uses this worker-hosted shape. The getting started production-shape part runs the same runtime in the main process instead — a teaching simplification that keeps the moving parts in one file.

Process model

Electron PearRuntime.run duplex preload / IPC Bare worker Renderer Main process

The renderer does not load hyperswarm, hypercore, or other Bare-oriented modules directly. The main process starts the worker with PearRuntime.run (or the instance method pear.run) and forwards bytes between the worker’s Bare.IPC stream and whatever bridge you expose to the renderer.

Updates

An update is triggered when a seeded application drive gains new writes: the replicated 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. Handlers attach with pear.on('updating') / pear.on('updated') (some sample apps use a nested updater object — same events, different accessor).

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 during local development so a seeded link does not replace your working tree mid-session.

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 is the string you pass into 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

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 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

The getting started chat walkthrough uses PearRuntime.run() 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. In the official hello-pear-electron template, that constructor runs inside the Bare worker, keeping the main process a thin proxy; the getting started production-shape part runs it in the main process instead as a teaching simplification.

Where to go next

On this page