Skip to content
v0.3

Apps & extension

The kernel changes globally or not at all. That sounds restrictive until you see what it buys: your instance takes upgrades forever, because there is nothing of yours in the part that upgrades.

Everything specific to you lives in one of four places outside the kernel. Which one is not a matter of taste — each answers a different question.

You need…It goes in
New behaviourAn app
New data on an existing thingCustom fields
The kernel to ask you something before it decidesA decision
A different look, layout or flowYour storefront

An app is code that runs beside the kernel and drives it through the same port you do. It declares what it needs in a manifest: the scopes it wants consent for, where it appears (slots, blocks, a whole admin screen of its own), when it acts (events, scheduled jobs, operator actions, decisions) and what it keeps or brings (its own data, its configuration, custom fields, notification types and channels, outbound connections, its own message catalogs). See build an app for what each group buys you.

Two properties make apps safe to install:

  • Consent is explicit and scoped. An app asks for scopes by name; installing it is granting them. It reaches exactly what it was granted and gets a named forbidden for anything else — the kernel’s check, not the app’s honesty.
  • Its data is its own. When an app has data that belongs to it, it gets its own isolated storage. It does not add columns to the kernel’s tables, so uninstalling it does not leave a wound.

An app is also how tooling gets written here. A seed script, a demo-data generator, an importer — anything that drives the port — is born as an app rather than a loose script, because the app model already gives it install, consent, scope and isolated storage.

For data that belongs to an existing thing — an extra attribute on a product, a field the checkout must collect — you define a custom field rather than adding a column.

The value rides in a JSONB metadata bag on the item, the definition is declared through the port, and the admin and storefront render it. No migration, no kernel change, and the field travels with the order snapshot like everything else.

Sometimes the kernel needs an answer only you have: which warehouse should serve this order, is this customer allowed this price, should this cart get free shipping.

A decision is the kernel asking — a declared question, with a declared shape, that your code answers during the transaction. It is not a webhook fired into the void; it is a synchronous seam the kernel is designed around. See decisions.

Design, layout, flow and copy are not kernel concerns. The storefront that ships with Forge is a reference implementation — you can restyle it with theme tokens, replace pieces of it, or replace the whole thing.

⚠️ “Theme” is only the visual-identity layer: colours, typography, logo, spacing tokens. Rebuilding the checkout flow is not theming — and it is not the storefront either: checkout, account, sign-in and orders are a separate deployable, hosted by us on the same origin and extended through theme, chrome, slots and apps. Owning either is supported, and means you own it. See own your storefront.

An app’s block on your storefront is the app’s, and you still restyle its inside without forking the app: the block’s root carries data-forge-block="<app>.<block>" and each named piece a data-part="<name>", and your stylesheet targets those — [data-forge-block="reviews.reviews"] [data-part="card"]. The app’s own class names are hashed per build and were never a contract. The names an app declares are frozen like the port: one is removed only after a deprecation that lasts at least one whole release series. When restyling is not enough, an app with a public API lets you draw the block yourself over the same faces its own block reads.

Ask: should every instance of Forge get this?

  • Specific to one business, one vertical, one integration → app, custom field, decision, or storefront.
  • A neutral primitive, generic and atomic, that several unrelated integrations would use → arguably kernel.

If it is the second, ask for it. Kernel requests are reviewed and, when accepted, ship to everyone — the kernel never learns one customer’s vocabulary.

You can fork. The kernel is source-available, and nothing stops you.

What you give up is every upgrade after that day. The four seams above exist so that you never have to: they are wide enough for real work, and they sit outside the part that moves.