Sharing state between pilets

Pilets are isolated by design. Communication happens through explicit, observable mechanisms — four channels, never direct imports or window globals.

Pilet A Pilet B events — emit / on shared data store — setData / getData shared library — importmap side-bundle extension slot — shared UI
Four explicit channels connect pilets — events, the shared data store, shared libraries, and extension slots.

1. Events: fire-and-forget

api.emit('cart:item-added', { productId: 'p1', qty: 2 });

api.on('cart:item-added', ({ productId, qty }) => {
  updateCartBadge(qty);
});

Good for: real-time notifications, analytics hooks, loose coupling. Not for: state a late-loading pilet needs at startup.

2. Shared data store: named key-value

// Write early in setup — other pilets find it when they load
api.setData('currentUser', { id: 'u1', name: 'Alice', roles: ['admin'] });

// Read from any pilet
const user = api.getData('currentUser');

// Subscribe to changes
api.on('store-data', ({ name, value }) => {
  if (name === 'currentUser') setLocalUser(value);
});

First pilet to write a key owns it. Others can read but not overwrite.

3. Shared libraries via importmap

Any pilet can share a package as a side-bundle:

{
  "importmap": {
    "imports": { "my-cart-service": "" }
  }
}

Other pilets that declare the same name get the same instance:

import { cartStore } from 'my-cart-service';

For how this resolves (externals vs side-bundles, and where each dependency belongs), see Dependency sharing.

4. Extension slots: sharing UI

<ExtensionSlot name="order-extras" params={{ orderId }} />

api.registerExtension('order-extras', ({ params }) => (
  <ShippingTracker orderId={params.orderId} />
));

Decision guide

ScenarioMechanism
Notify others of an eventapi.emit / api.on
Small value all pilets needapi.setData / api.getData
Shared service instanceimportmap side-bundle
Shared rendered componentExtension slots
Complex reactive global stateCustom plugin
State surviving page reloadURL params or localStorage
Warning

Never use window globals to share state. Untestable, untyped, and a debugging nightmare.