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.