Skip to content
Hara

Substrate: the application connection layer

React has become much more than a rendering library. Components, hooks, and state models give web developers an excellent way to divide an interface, co-locate behaviour, and turn state changes into new views.

That strength has a gravitational pull: application structure can begin to follow the component tree. Hara's std.lib.substrate starts one layer earlier. It gives the application a structured, live connection layer; React remains the excellent renderer and interaction surface above it.

When the component tree becomes the application map

It is natural to start locally:

const [order, setOrder] = useState(initialOrder)

Then another component needs the order, then a branch needs it, then a page, then a server cache. The question changes from “what does the application mean?” to “where should this state live?”

Those are valid UI engineering decisions. They are not always the right first place to model the system. React does not need to own every application decision in order to render the result of it.

Begin with the application layer

A Substrate node is an eventing application node. It coordinates bounded application spaces, their state, named request handlers, event triggers, services, pending requests, subscriptions, and local or remote transports. The portable core is deliberately an in-memory, atom-backed node; browser ports, network transports, wire formats, and Studio integration are adapters above that core.

The interface does not have to decide where all application information ultimately lives. It connects to an application layer that already knows how state and events move.

Separate the model from the page

A node contains multiple named spaces. A space is a bounded application context with its own state and metadata. A page and a model can therefore be related without being the same thing.

A second page, a test, a background process, or an agent can interact with the same model without pretending to be a React component.

Requests express intentions

A request names a target space, action, arguments, metadata, and—when needed—a transport. The UI says what happened from the user's perspective; the application layer decides whether the transition is valid, local or remote, and which state, service, and event are involved.

Instead of encoding the whole transition in a component:

setOrder({ ...order, status: "submitted" })

the UI can ask the application layer to perform an operation:

space:  model/orders
action: order/submit
args:   ["order-42"]

This is delegation. The component does not need to own the order, know where it is stored, or know whether the submission happens locally, in a worker, or through a remote service.

Streams describe what happened

Requests describe an intention and expect a response. Streams describe events that occurred. A node can publish a signal inside a space, run local triggers, and forward the resulting frame to subscribed transports.

A React adapter can subscribe to the events it needs. A logger can record them, a transport can forward them, an agent can inspect them, and a second model can react. The event does not belong to one component.

React becomes an adapter—not a smaller React

Substrate state and events can be translated into the UI mechanism that makes sense for a renderer. React is free to use local state, context, a reducer, or an external store; another adapter could use Solid signals, a Svelte store, a canvas renderer, or a command-line display.

This does not weaken React. It lets React concentrate on composition, receiving input, rendering projections, and genuinely local interaction state.

Keep view state local; give application state a home

Not every value belongs in a Substrate space. A dropdown being open, an input's temporary contents, a hovered row, or an animation phase can stay local to a component. The distinction is ownership, not visibility.

Ask one question: would this information still matter if this component were removed? If yes, it probably belongs to a model or application space. That keeps Substrate from becoming another indiscriminate global store.

Shared does not mean one giant store

The challenge with global state is not only that it is global. One undifferentiated store often ends up responsible for unrelated domains, pages, services, caches, and transient UI details. Substrate keeps shared connectivity while dividing a node into bounded, addressable spaces.

The application exists before the UI

The shift is an ordering of responsibilities—not “Hara state versus React state.” React-centred work can begin with components and let application behaviour emerge from state and effects. Substrate starts with application spaces, state, actions, and events, then connects a UI adapter.

React remains an excellent way to display and interact with the system. The point is that the interface should not have to invent the entire application layer as it renders it.

Use the browser playground for a contained live environment, or On the Web to choose a host for a project.