Node Plugins
Node plugins run in a subprocess with full access to the Node.js runtime, npm packages, and native addons. Use them when your plugin needs capabilities beyond pure computation – filesystem access, network requests, or npm dependencies.
Marking a Plugin as Node
Any .js file in plugins/ runs on embedded QuickJS by default. To use the Node subprocess, export runtime: "node":
Without this marker, your plugin runs sandboxed on QuickJS with no system access.
Prerequisites
Node plugins require:
- Node.js installed and available in
PATH - ESM project:
"type": "module"in yourpackage.json - Dependencies installed: run
npm installin your project root
Alloy does not ship Node.js, manage package.json, or run npm install. If Node plugins exist but node is not found, the build fails:
IPC Protocol
Node plugins communicate with Alloy via length-prefixed JSON-RPC over stdin/stdout (LSP-style framing).
You never interact with this protocol directly — the alloy API object handles serialization.
stdout isolation
Stdout is reserved for the plugin protocol. The bridge script intercepts JS-level writes before any plugin code loads:
console.log,console.warn,console.info,console.debug→ stderrprocess.stdout.write→ stderr
Plugin output and library logging appear in the terminal alongside Alloy’s own output, not in a log file. Plugins cannot corrupt the protocol by logging.
Known limitation: A child process spawned with stdio: 'inherit' writes to the real stdout file descriptor, bypassing the JS-level patch. This can corrupt the protocol. Spawn children with explicit stdio instead:
Troubleshooting
If you see this error:
A plugin or one of its dependencies is writing to stdout at the file descriptor level, bypassing the bridge’s process.stdout.write patch. Common causes:
- A child process spawned with
stdio: 'inherit' - A native addon writing directly to fd 1
require('fs').writeSync(1, ...)or similar fd-level writes
Fix by redirecting the child’s stdio as shown above.
Registering Filters
Filter arguments are passed as additional parameters:
Registering Shortcodes
Registering Hooks
Node plugins can register any lifecycle hook:
Hook Priority
Control execution order with the priority option:
Hook Scoping
Declare what data your hook needs to minimize serialization overhead:
See Hook Scoping for the full scoping API.
Data Source Plugins
The built-in rest and graphql source types handle simple, unauthenticated, single-request fetches. For anything beyond that — authentication, pagination, retries, multi-endpoint aggregation, database access — use type: "plugin". The plugin owns the entire data acquisition lifecycle and returns the final dataset. Alloy caches the result and injects it into the data cascade. For a comparison table, see Built-in types vs plugin sources.
Register a source handler:
Configure the source in alloy.config.yaml:
The fetched data is available as site.data.blog in templates and can drive virtual page generation via pagination.
Worker Pool
For per-page hooks (onPageRendered, onContentTransformed), Alloy distributes pages across multiple Node subprocess workers to parallelize the work:
Auto-scaling uses min(CPU_count / 2, 8) with a floor of 2. Each worker loads the same plugins via ESM import() so Node’s module cache prevents side-effect collisions.
Only Tier 3 (Node subprocess) plugins use the worker pool – Tier 2 plugins run in-process.
Module Resolution
The Alloy bridge script is written to .alloy/bridge.js in your project root. This ensures ESM import() resolves packages from your project’s node_modules/. Both import and dynamic import() work:
Plugin Timeout
Each plugin call respects the configured timeout (default 5 seconds):
A timed-out call produces a warning and continues with unmodified data. Plugin process crashes return an error.
Security
Node plugins run with the same permissions as the user. They have full access to:
- Filesystem (
fs,path) - Network (
fetch,http,net) - Environment variables (
process.env) - Child processes (
child_process)
Only install plugins you have reviewed or that come from trusted sources.
Related
- Plugin System – overview and tier comparison
- QuickJS Plugins – sandboxed JS plugins
- WASM Plugins – compiled plugins for maximum performance
- Lifecycle Events – all hook events and payloads