Plugins
A build-time extension system for adding reusable functionality to your EdgeBase project. Plugins are npm packages that inject tables, functions, hooks, and manifest metadata into your project โ with zero runtime overhead. The server doesn't even know plugins exist; it just sees more tables and functions.
How It Worksโ
Plugins use an Explicit Import pattern. You install a plugin package, import its factory function in edgebase.config.ts, and call it with your configuration. At build time, the CLI merges plugin tables, functions, and hooks into the project โ the server sees a regular EdgeBase app with more stuff.
npm install @edgebase/plugin-stripe
import { defineConfig } from '@edgebase/shared';
import { stripePlugin } from '@edgebase/plugin-stripe';
export default defineConfig({
plugins: [
stripePlugin({
secretKey: process.env.STRIPE_SECRET_KEY!,
webhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,
}),
],
});
That's it. Deploy and the plugin's tables, functions, hooks, and manifest metadata are live.
definePlugin() also stamps the current public pluginApiVersion onto the resolved plugin instance. Deploy rejects plugins built against a different contract instead of attempting to run them.
What Plugins Can Injectโ
Tables
Custom database tables with schema, access, handlers, and indexes. Automatically namespaced to prevent collisions.
Functions
HTTP endpoints, DB triggers, cron jobs โ all registered into the existing function system.
Auth Hooks
Hook into 11 auth lifecycle events: signup, signin, sign-out, token refresh, password reset, account deletion, and email verification.
Storage Hooks
Intercept file uploads, downloads, and deletions with blocking (before*) and non-blocking (after*) hooks.
Migrations
Version-keyed migration system with onInstall callback and semver-ordered upgrade scripts.
Manifest
Code-level plugin metadata such as description, docs URL, and configTemplate for CLI tooling.
Client SDK Extensions
Optional typed client wrappers for calling plugin functions from the frontend.
Namespace Isolationโ
All plugin resources are automatically prefixed with the plugin name to prevent collisions:
Plugin: plugin-stripe
Table: customers โ plugin-stripe/customers
Function: create-checkout โ plugin-stripe/create-checkout
Hook: onTokenRefresh โ __hook__/plugin-stripe/onTokenRefresh
Multiple plugins can coexist without any naming conflicts.
Manifest Metadataโ
Plugins can also declare a serializable manifest block inside definePlugin():
manifest: {
description: 'Stripe billing for EdgeBase',
docsUrl: 'https://edgebase.dev/docs/plugins/stripe',
configTemplate: {
stripeSecretKey: 'sk_test_CHANGE_ME',
stripeWebhookSecret: 'whsec_CHANGE_ME',
},
}
The CLI uses this for edgebase plugins list, setup guidance, and future plugin tooling. Metadata lives with the plugin code rather than in package.json, so it stays versioned with the actual runtime definition.
Build Pipelineโ
Plugins are resolved entirely at build time. No runtime scanning, no dynamic imports.
edgebase.config.ts (plugins: [stripePlugin({...})])
โ esbuild bundle (import graph pulls in plugin handler code)
โ mergePluginTables() (namespace-prefixed merge into DB blocks)
โ materializeConfig() (plugin tables become first-class config)
โ generateFunctionRegistry() (plugin functions + hooks registered)
โ runPluginMigrations() (version-based migrations on deploy)
โ wrangler deploy
Zero overhead: Plugin code is part of the Worker bundle. The server runtime has no concept of "plugins" โ it just executes registered functions and queries registered tables.
Architectureโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ edgebase.config.ts โ
โ plugins: [ โ
โ stripePlugin({ secretKey: '...' }), โ
โ analyticsPlugin({ trackPageViews: true }), โ
โ ] โ
โโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ build time
โโโโโโโโโโโโโโผโโโโโโโโโโโโโ
โผ โผ โผ
mergePluginTables initFunctionRegistry runPluginMigrations
(tables โ DB) (functions + auth/ (onInstall +
storage hooks) version migrations)
โ โ โ
โโโโโโโโโโโโโโผโโโโโโโโโโโโโ
โผ
Worker Bundle (single JS)
โ server sees: tables + functions
โ no "plugin" concept at runtime
Key Design Decisionsโ
| Decision | Rationale |
|---|---|
| Explicit Import (not auto-scan) | No magic. You see exactly what's loaded in config. Tree-shakeable. |
Factory Pattern (definePlugin<T>()) | Type-safe config. Closure captures userConfig for all handlers. |
| Build-time merge (not runtime) | Zero cold-start overhead. Plugin code is part of the Worker bundle. |
| npm as distribution | Standard ecosystem. npm install + import. Same workflow for official and community plugins. |
| Server-agnostic | Server code never references plugins. Plugin functions are just... functions. |
Trust Modelโ
Plugins are trusted server-side code. Installing a plugin means its code is bundled into the same Worker and gets the same admin-side capabilities as first-party server code. EdgeBase does not currently sandbox plugins or require per-plugin capability declarations.
That trust model is intentional: the extension point is build-time composition, not an untrusted runtime marketplace.
Cleanupโ
Removing a plugin from edgebase.config.ts stops its functions and hooks immediately, but data cleanup is a separate explicit step:
npx edgebase plugins cleanup my-plugin
The cleanup command removes namespaced plugin tables and plugin migration metadata from the internal control-plane D1 (CONTROL_DB). On Cloudflare Edge, pass --account-id and --api-token when the plugin may have touched dynamic Durable Object instances so the CLI can discover and clean those instances too.
Quick Linksโ
- Using Plugins โ Install, configure, and manage plugins
- Creating Plugins โ Build your own plugin from scratch
- API Reference โ
PluginFunctionContext,PluginHookContext, and all types
CLI Commandsโ
# Scaffold a new plugin project
npx edgebase create-plugin my-plugin
# List installed plugins (tables, functions, hooks)
npx edgebase plugins list
# Remove namespaced data for a removed plugin
npx edgebase plugins cleanup my-plugin