HomeRunner plugin development
A HomeRunner plugin is a React component, an optional server-render module, and a
manifest.json that tells the platform what you ship. You submit it as a source zip: you
host nothing, and you never build the artifact a customer loads. A HomeRunner reviewer reads
your source, runs your build, and publishes the result to the plugin CDN under an immutable
version prefix. Customers then install it per feed and configure it in a dashboard form
generated from your zod schema. From there your widget renders alongside first-party ones —
server-rendered into Declarative Shadow DOM where the request supports it, hydrated by the
platform’s shared runtime, or client-mounted on a CSR embed.
A plugin can carry a single widget or a whole suite of them under one version, one review and one publish — including layout widgets that host other widgets in named slots.
Start here
Building one widget? Read Install and versions,
then Your first widget. npx create-hr-plugin my-plugin
produces exactly this shape, and its dev sandbox and SSR preview both work out of the box.
Building a suite — several widgets, or a layout, or a one-click preset? Scaffold it
directly with npx create-hr-plugin my-suite --template suite (create-hr-plugin 0.8.0+),
which writes a working three-widget suite including a layout. Do the first-widget page anyway
(the component, schema and build steps are identical), then
Build a suite and
Add a layout widget.
Choose deliberately: the manifest shape is frozen at your first publish, and changing it afterwards needs a brand-new plugin slug. Converting is free until then — but only until then. The two manifest shapes explains the decision and its cost.
How this book is organised
- Get started — a working toolchain and a widget on screen: Install and versions → Your first widget.
- Concepts — the mental model, in prose: what the files are (Anatomy of a plugin), which shape you picked, how a render actually happens (How a widget renders), where settings come from (Settings and options), and who does what between your laptop and a customer page (Lifecycle).
- Contracts — normative reference: every field, rule and error string, one owner per fact. Start at Manifest: root fields; every hard number and every message the platform can show you is indexed in Limits and error index.
- Recipes — task-shaped guides: Styling and theming, Fetching data, Portals and dialogs, Composing a page.
- Local development — drive every state offline with the dev sandbox, and verify server rendering with SSR preview.
- Ship — Preflight and submit, then Publishing, versions and rollback and Install, customers and kill switches.
- When something breaks — Troubleshooting is organised by symptom; unfamiliar words live in the Glossary.
At a glance
# derived from packages/create-hr-plugin/bin/create-hr-plugin.js and both templates' package.json
# non-interactive, argv only: [--template <single|suite>] [--author <name>] [--no-install]
npx create-hr-plugin my-plugin # one widget (the default)
npx create-hr-plugin my-suite --template suite # several widgets + a layout
cd my-plugin
npm run dev # Vite dev sandbox on http://localhost:3001, MSW-mocked by default
npm run build # = npm run build:manifest && hr-widget-build
npm run dev:ssr # SSR preview on http://localhost:3003 — run a build first.
# A suite has no default widget, so name one:
# npm run dev:ssr -- --widget intro-card
npm run preview # = npm run build && node serve.js → http://localhost:3002
npm run build is two steps, not the three older versions of this guide described: your
project’s scripts/inject-schema.mjs writes the config and UI schema into the manifest (or into
per-widget sub-manifests), then the SDK’s hr-widget-build bin drives every Vite pass, hashes
dist/, writes dist/manifest.json and stamps runtime.widgetCore. It rewrites tracked files,
so expect manifest.json to be dirty in git afterwards — commit it.
npm run preview (create-hr-plugin 0.8.0+) serves dist/, /manifest.json, the /w/ hashed
redirect and the /p/ asset-proxy path, and the page boots the built bundles against the
real runtime IIFE. It runs with no mocks, so point its host ids at a real widget and feed first
— Your first widget has the details.
SDK versions
You import from one package, @homerunner-next/widget-core. The build stamps the version it
used into runtime.widgetCore, and that stamp is what the publish gate reads — never write it
by hand.
| widget-core | What it added |
|---|---|
| 0.10.0 | Evergreen runtime (/runtime externalized from your bundle). The publish floor. |
| 0.11.0 | Suites, registerPluginWidget, the hr-widget-build bin, layout widgets, presets. |
| 0.12.0 | assets.fonts, bundled assets, layout pages, marketplace icon and cover. |
| 0.12.1 | Slot prefill. |
| 0.12.2 | createSSRDevServer previews one named widget of a suite (--widget {slug}). |
| 0.12.3 | The SSR preview links a stylesheet for a widget that exports no getStaticAssets. |
This book documents widget-core 0.12.3 and create-hr-plugin 0.8.1, whose templates pin
^0.12.1 (--template single) and ^0.12.3 (--template suite).
Both are on npm as of 2026-09-08 — npx create-hr-plugin <slug> --template suite works straight
from the registry. Install and versions owns the version
matrix and what each release added.