Plugin System Overview
bext ships a plugin system that lets you extend the server at three levels: request/response middleware, source-code transforms, and server lifecycle hooks. Every plugin runs inside a sandbox, and you choose from three isolation tiers depending on your performance, security, and flexibility requirements.
Three Isolation Tiers
| Tier | Runtime | Startup | Memory | Best For |
|---|---|---|---|---|
| QuickJS | Embedded JS interpreter | < 1 ms | < 1 MB | Business logic, pricing rules, webhook handlers |
| WASM (Pro) | wasmtime with fuel budgets | < 1 ms | 1-5 MB | High-performance Rust/Go/C plugins |
| nsjail (Pro) | Linux namespace isolation | ~10 ms | Near zero | Untrusted code, multi-tenant plugins, full Linux userspace |
QuickJS — Lightweight JS Sandbox
The default tier. Embeds the QuickJS engine via rquickjs to run JavaScript in a memory-limited, time-limited sandbox. Plugins get a controlled API surface (bext.storage, bext.fetch, bext.config, bext.metric) with no direct filesystem or network access. Ideal for tenant-supplied scripts where you want zero cold-start overhead.
WASM — wasmtime Sandbox
Compile your plugin in Rust, Go, or C to a .wasm module. bext loads it via wasmtime with configurable fuel budgets per lifecycle call (e.g., 100M fuel for on_request_complete, 500M for on_server_start). Host functions are exposed under the "bext" import module for storage, HTTP fetch, metrics, and queue access. This tier gives you near-native speed with strong isolation guarantees.
nsjail — Process-Level Isolation
Run any executable (Python, Ruby, compiled binaries) as a child process with JSON-over-stdio IPC. On Linux with root, bext applies PID/NET/MOUNT namespace isolation, cgroup limits, and seccomp filters. Without root, plugins still run as separate processes with piped stdio and wall-clock timeouts. Best when WASM and QuickJS are too restrictive.
Plugin Capabilities
Plugins declare which capabilities they provide in their manifest:
# plugin.toml
[manifest]
name = "rate-limiter"
version = "1.0.0"
capabilities = ["middleware"]
The four capability types are:
- Middleware — intercept requests (on_request) and modify responses (on_response). Can short-circuit with a custom response.
- Transform — rewrite source code at build time. Runs in priority order alongside bext's 14 built-in transforms.
- Lifecycle — receive notifications at server start, stop, cache writes, cache invalidations, ISR reloads, and request completion.
- CacheBackend — provide a custom cache storage backend.
Plugin Lifecycle
Every plugin follows the same lifecycle regardless of sandbox tier:
1. Init — bext reads plugin.toml, validates the manifest, and loads the plugin into its sandbox. The plugin receives its config section from bext.config.toml.
2. on_server_start — called once after all subsystems initialize. Use this to set up connections, warm caches, or register metrics.
3. on_request / on_response — called on each HTTP request for middleware plugins. on_request runs before routing; on_response runs after the handler produces a response.
4. on_request_complete — fires asynchronously after the response is sent. Receives path, method, status, cache status, render time, and tenant info.
5. on_cache_write / on_cache_invalidate — ISR cache events for analytics or cache synchronization.
6. on_reload — fires after a successful V8 pool reload (new bundle deployed).
7. cleanup — called during graceful shutdown. Release resources here.
Middleware Priority Stack
Built-in middleware runs at fixed priorities. Plugin middleware defaults to priority 600 (after all built-ins):
| Priority | Middleware |
|---|---|
| 100 | CORS |
| 200 | Rate Limiter |
| 300 | JWT / Session Auth |
| 400 | Tenant Resolver |
| 500 | Request Tracing |
| 600+ | Plugin Middleware |
Set a custom priority in your plugin config to run earlier or later in the stack.
Plugin Registry
Discover and install community plugins from plugins.bext.dev:
bext plugin install security-headers
bext plugin install geo-redirect
Installed plugins are configured in bext.config.toml:
[plugins.security-headers]
sandbox = "quickjs"
[plugins.security-headers.config]
hsts_max_age = 31536000
x_frame_options = "DENY"
When to Use Which Tier
- QuickJS: you need simple request interception, data transforms, or webhook handlers, and your plugin is written in JavaScript.
- WASM: you need maximum performance with strong isolation, and you can compile your code to WebAssembly.
- nsjail: you need to run existing tools, scripts in any language, or handle untrusted third-party code with full OS-level isolation.
See the dedicated pages for each tier: QuickJS, WASM, nsjail.