PATTERN Cited by 1 source
Per-request isolate per plugin¶
Pattern¶
When a plugin hook fires, spawn a fresh V8-style isolate (e.g. a Dynamic Worker) dedicated to that plugin, execute the plugin's hook handler, return the result, tear the isolate down. No plugin state persists between invocations except through explicitly-bound storage capabilities. Every plugin invocation is architecturally the plugin's first moment of life.
When to use¶
- You're running many small, third-party plugins on the same host, each with its own trust posture.
- You can afford millisecond-scale isolate start-up (V8 isolate, not container or VM).
- You want strong isolation (one plugin's memory corruption, leak, or infinite loop cannot affect another plugin).
- You want scale-to-zero plugin execution: idle plugins cost nothing.
- You want agent-driven / LLM-written plugins that may be updated frequently and should never carry implicit state.
Preconditions¶
- A V8-isolate-class runtime. Container-per-plugin is too expensive per-invocation; VM-per-plugin is way too expensive. Dynamic Workers / workerd are the explicit example Cloudflare positions.
- A capability-based sandbox in that runtime. Fresh isolates with ambient authority would be no better than in-process plugin execution.
- Explicit-binding storage for state that must persist across invocations (KV, Durable Objects, D1, R2). The isolate is ephemeral; its storage bindings are not.
How it differs from long-lived-isolate-per-plugin¶
Long-lived-per-plugin: each plugin gets its own long-running Worker (warm isolate retained across requests). Efficient; retains in-memory caches; typical Workers deployment pattern. But: state from one invocation persists to the next unless explicitly cleared; a plugin can accumulate latent bugs, memory leaks, or partial state over time.
Per-request-isolate-per-plugin: each hook invocation gets a fresh isolate. No cross-invocation state; no memory accumulation; no "plugin stuck in a bad state" failure mode. Cost: millisecond startup overhead per invocation. For plugin hooks that fire occasionally (content:afterSave, user:created, scheduled task), the overhead is small relative to the workload; for per-request plugins the trade is harder.
Relationship to Dynamic Workers¶
Dynamic Workers are Cloudflare's canonical per-request-isolate substrate — built for LLM-generated code in Project Think. The same property — "~100× faster and up to 100× more memory-efficient than a container. You can start a new one for every single request, run a snippet of code, and throw it away" — is what makes per-plugin-isolate-per-invocation viable as a plugin runtime.
EmDash is the first widely-visible deployment of Dynamic Workers as a plugin-hosting substrate (after Project Think's agent-tool use case). The pattern generalises: any host that needs to run many small, untrusted extensions on-demand can use the same substrate.
Consequence: lifetime-bounded security¶
A plugin cannot:
- Leave a lingering socket open across invocations.
- Cache sensitive data in process memory between calls.
- Use a compromise in one invocation to affect the next.
- Run a slow leak that eventually crashes the plugin runtime.
Everything a plugin might have done with persistent state has to go through an explicit storage binding — which is itself a declared capability in the manifest, visible at install time.
Consequence: scale-to-zero at the plugin tier¶
A plugin with no incoming hook invocations runs no isolate, holds no memory, costs nothing. A site with 100 installed plugins, 5 of which are actively firing, is only paying for those 5. The host's idle-cost model is set by active traffic, not installed plugin count — a meaningful economic improvement over plugin architectures that load everything into the host process at startup.
Worked example — EmDash¶
incoming request → EmDash core handles routing
→ content:afterSave hook fires
→ for each installed plugin with this hook:
spawn Dynamic Worker isolate with capabilities
from plugin's manifest
invoke the plugin's hook function
collect result (or error)
tear isolate down
→ EmDash core assembles response
No plugin holds any state between hook invocations except through its declared storage capabilities. The host never has to worry about a plugin's in-memory garbage state.
Seen in¶
- sources/2026-04-01-cloudflare-emdash-wordpress-spiritual-successor — canonical wiki instance in the plugin-hosting setting. EmDash plugins as Dynamic Workers; the "instantly spins up an isolate to execute code and serve a response, scales back down to zero" property is what EmDash inherits from workerd.
Related¶
- systems/dynamic-workers — the runtime substrate.
- systems/emdash — CMS-level deployment.
- systems/cloudflare-workers — the Workers-level framing of the same isolate architecture (long-lived isolate mode).
- systems/workerd — the open-source runtime implementing the isolate model.
- concepts/capability-based-sandbox — the security posture each isolate starts with.
- concepts/scale-to-zero — the economic model this pattern delivers at the plugin tier.
- patterns/capability-manifest-plugin-isolation — the install-interface companion pattern.
- companies/cloudflare — operator of the canonical substrate.