Skip to main content

Documentation Index

Fetch the complete documentation index at: https://zenbulabs.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

Every Zenbu.js application is itself a plugin. Your app is defined with definePlugin() the same way any third-party extension would be, and it has the same capabilities. The only thing that makes the main application special is the uiEntrypoint in defineConfig(), which tells the framework which plugin’s code to load in the renderer process first.

Defining a plugin

Plugins are declared with definePlugin() from @zenbujs/core/config:
zenbu.config.ts
import { defineConfig, definePlugin } from "@zenbujs/core/config"

export default defineConfig({
  db: "./.zenbu/db",
  uiEntrypoint: "./src/renderer",
  plugins: [
    definePlugin({
      name: "app",
      services: ["./src/main/services/*.ts"],
      schema: "./src/main/schema.ts",
      events: "./src/main/events.ts",
      migrations: "./migrations",
    }),
  ],
})
FieldRequiredDescription
nameyesUnique plugin identifier. Used as the top-level namespace for the plugin’s database section, RPC services, and events (e.g. db.<name>, rpc.<name>.<service>, events.<name>.<event>). Reserved value: core belongs to the framework.
servicesyesGlob patterns for main process service files.
schemanoPath to the database schema definition.
eventsnoPath to event type definitions.
migrationsnoDirectory of generated migration files.
dependsOnnoDeclares which other plugins this plugin needs type definitions from. See Type dependencies.

Scaffolding a plugin

create-zenbu-app can scaffold a plugin folder from anywhere on disk:
pnpm create zenbu-app --plugin my-plugin
FlagDescription
--pluginUse the plugin template instead of the app template. Skips app-only prompts (Tailwind, build config).
--no-add-to-hostSkip the interactive prompt that offers to add the new plugin to each upstream host’s plugins: array.
--no-gitSkip the git init prompt. Git init is auto-skipped when an ancestor already has a .git/.
--yes / -yAuto-confirm every prompt with the default.
The command scaffolds the plugin folder and installs its dependencies.

Adding a plugin

Plugins can be inlined with definePlugin() or referenced by path to a zenbu.plugin.ts file:
plugins: [
  definePlugin({ name: "app", services: ["./src/main/services/*.ts"] }),
  "./plugins/devtools/zenbu.plugin.ts",
]
Adding or removing a plugin in zenbu.config.ts is a hot-reloadable change that takes effect without restarting the app.

Plugin capabilities

A plugin has the same capabilities as the host application:
  • Services run in the main process and expose methods via RPC.
  • Database schemas define sections of the shared database.
  • Events can be emitted and listened to across plugins.
  • Views are iframe-mounted renderer entry points other plugins can embed.
  • Content scripts inject JavaScript into any view.
  • Advice lets a plugin wrap or replace any React component in the renderer.

Type dependencies

If a plugin needs to call another plugin’s RPC methods, read its database, or subscribe to its events, it needs that plugin’s type definitions. You declare this with dependsOn:
zenbu.plugin.ts
import { definePlugin } from "@zenbujs/core/config"

export default definePlugin({
  name: "devtools",
  services: ["./src/main/services/*.ts"],
  dependsOn: [
    { name: "app", from: "../../zenbu.config.ts" },
  ],
})
name is the plugin you depend on, and from is the path to the file that defines it. With this in place, you get typed access to that plugin’s API:
// Read app's database
const count = useDb(root => root.app.count)

// Call app's RPC methods
const rpc = useRpc()
await rpc.app.counter.increment()

// Subscribe to app's events
events.app.notification.subscribe(data => { ... })
This is a type-only dependency. dependsOn tells zen link where to find the other plugin’s service, schema, and event definitions so it can generate TypeScript types under <plugin>/.zenbu/types/. The generated files are import type pointers to the actual source on disk, and the entire .zenbu/types/ directory is gitignored. zen link runs automatically inside zen dev. Outside dev, run it manually before typechecking:
zen link