{"id":10793,"library":"env-runner","title":"env-runner","description":"env-runner is a generic environment runner for JavaScript applications, abstracting away the complexities of various runtime environments. It enables developers to run server applications across Node.js worker threads, child processes, Bun, Deno, Cloudflare Workers (via Miniflare), Vercel, Netlify, or even in-process. The package provides essential features like hot-reloading for development, WebSocket proxying, and a bidirectional messaging system between the main process and the runner environment. Currently at version 0.1.7, it is actively developed with rapid minor releases focusing on enhancements and new runner integrations, offering a unified API for deploying serverless functions or local servers across diverse JavaScript ecosystems. Its key differentiator is providing a consistent interface regardless of the underlying runtime.","status":"active","version":"0.1.7","language":"javascript","source_language":"en","source_url":"https://github.com/unjs/env-runner","tags":["javascript"],"install":[{"cmd":"npm install env-runner","lang":"bash","label":"npm"},{"cmd":"yarn add env-runner","lang":"bash","label":"yarn"},{"cmd":"pnpm add env-runner","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Required for the NetlifyEnvRunner to function correctly.","package":"@netlify/runtime","optional":true},{"reason":"Required for the MiniflareEnvRunner to emulate Cloudflare Workers locally.","package":"miniflare","optional":true}],"imports":[{"note":"EnvServer provides a high-level API for running applications with watching and auto-reload.","symbol":"EnvServer","correct":"import { EnvServer } from 'env-runner'"},{"note":"RunnerManager is a proxy for hot-reloading, message queueing, and listener forwarding.","symbol":"RunnerManager","correct":"import { RunnerManager } from 'env-runner'"},{"note":"Specific environment runners are imported from subpaths within the `env-runner/runners/` directory.","wrong":"import { NodeProcessEnvRunner } from 'env-runner'","symbol":"NodeProcessEnvRunner","correct":"import { NodeProcessEnvRunner } from 'env-runner/runners/node-process'"}],"quickstart":{"code":"import { serve } from \"srvx\";\nimport { EnvServer } from \"env-runner\";\nimport { fileURLToPath } from 'node:url';\nimport path from 'node:path';\n\n// app.ts (your application entry point - create this file)\n// export default {\n//   fetch(request: Request) {\n//     return new Response(`Hello from env-runner at ${new Date().toISOString()}!`);\n//   },\n// };\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\nconst appEntryPath = path.join(__dirname, 'app.ts'); // Path to your app.ts entry\n\nconst envServer = new EnvServer({\n  runner: \"node-process\", // Choose your desired runner: 'miniflare', 'bun-process', etc.\n  entry: appEntryPath,\n  watch: true,\n  watchPaths: [path.join(__dirname, 'src')], // Example additional watch path\n});\n\nenvServer.onReady((_runner, address) => {\n  if (address) {\n    console.log(`Worker ready on ${address.host}:${address.port}`);\n  } else {\n    console.log(\"Worker ready, but no address reported.\");\n  }\n});\n\nenvServer.onReload(() => {\n  console.log(\"Application reloaded!\");\n});\n\nenvServer.onError((error) => {\n  console.error(\"EnvServer error:\", error);\n});\n\nawait envServer.start();\n\n// Use with any HTTP server (srvx is used here as an example from the README)\nconst server = serve({\n  fetch: (request) => envServer.fetch(request),\n});\n\nconst port = process.env.PORT ? parseInt(process.env.PORT) : 3000;\nserver.listen({ port, host: 'localhost' });\nconsole.log(`HTTP server listening on http://localhost:${port}`);\n\n// Graceful shutdown\nprocess.on('SIGINT', async () => {\n  console.log('Shutting down env-runner and HTTP server...');\n  await envServer.close();\n  server.close();\n  process.exit(0);\n});\n","lang":"typescript","description":"This quickstart demonstrates setting up `EnvServer` to run an application entry point with hot-reloading and proxy requests through a standard HTTP server. Remember to create an `app.ts` file with a default `fetch` handler."},"warnings":[{"fix":"Update `RunnerManager` and `EnvServer` usage to use `.on('event', listener)` or `.onEvent(listener)` methods instead of direct assignment to callback properties.","message":"The `RunnerManager` and `EnvServer` APIs changed their event handling from direct callback properties (e.g., `onReady = () => {}`) to a multi-listener event pattern (e.g., `.onReady((runner, address) => {})`).","severity":"breaking","affected_versions":">=0.1.6"},{"fix":"Applications must now manually handle process signals (e.g., `SIGINT`) and explicitly call `.close()` on `EnvServer` or `RunnerManager` instances to ensure proper termination.","message":"Core graceful shutdown mechanisms were removed from the package, requiring applications to implement their own shutdown logic.","severity":"breaking","affected_versions":">=0.1.6"},{"fix":"Ensure you install the necessary peer dependencies explicitly (e.g., `npm install miniflare @netlify/runtime`) when using their respective runners.","message":"Specific runners, such as `MiniflareEnvRunner` or `NetlifyEnvRunner`, rely on peer dependencies (`miniflare`, `@netlify/runtime`) that must be installed separately by the consumer.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Always consult the package's changelog before upgrading minor versions and consider pinning exact versions in production environments to prevent unexpected issues.","message":"As a pre-1.0 package, `env-runner` may introduce frequent breaking changes between minor versions, especially in its early stages of development.","severity":"gotcha","affected_versions":">=0.1.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Use the new event listener methods: `manager.onReady((runner, address) => { ... });` or `envServer.onReady((runner, address) => { ... });`","cause":"Attempting to use the old callback assignment style on `RunnerManager` or `EnvServer` (e.g., `manager.onReady = ...`).","error":"TypeError: Cannot read properties of undefined (reading 'onReady')"},{"fix":"Install the missing peer dependency: `npm install miniflare` (or `npm install @netlify/runtime`) in your project.","cause":"Using `MiniflareEnvRunner` (or `NetlifyEnvRunner`) without having its corresponding peer dependency installed.","error":"Error: Cannot find module 'miniflare'"},{"fix":"Ensure your application entry file has `export default { fetch(request: Request) { /* ... */ } };` at its root.","cause":"The entry module specified for the runner (e.g., `app.ts`) does not export a default object containing a `fetch` method.","error":"Error: Module './app.ts' does not export a default 'fetch' handler."},{"fix":"Always instantiate runner classes using the `new` keyword: `const runner = new NodeProcessEnvRunner({...});`.","cause":"Attempting to invoke a runner class constructor directly (e.g., `NodeProcessEnvRunner({...})`) instead of instantiating it with `new`.","error":"TypeError: Class constructor NodeProcessEnvRunner cannot be invoked without 'new'"}],"ecosystem":"npm"}