esbuild-dev-router
raw JSON → 0.8.0 verified Fri May 01 auth: no javascript
Express middleware for development with esbuild. Bundles TypeScript/JavaScript source files in memory, serves them directly, and automatically reloads the browser on file changes via Server-Sent Events. Current stable version is 0.8.0. Peer dependency on esbuild >0.17. Key differentiators: zero-config live reload injection, no disk writes, mounts as Express Router, merges loader and plugin configs so you can extend defaults. Best for teams that already use Express and esbuild and want a lightweight dev server without Webpack or Vite.
Common errors
error Error: The reloader endpoint is not found at /assets/reloader ↓
cause Middleware mounted at a subpath (e.g., app.use('/assets', devRouter(...))) but reloader path is hardcoded to '/reloader'.
fix
Mount the router at the root: app.use(devRouter({...}))
error TypeError: Cannot read properties of undefined (reading 'build') ↓
cause esbuild peer dependency not installed or version <0.17.
fix
Install esbuild >=0.17: npm install -D esbuild
error Error: esbuild-dev-router is ESM-only, require() is not supported ↓
cause Using CommonJS require() to load the package.
fix
Use ESM imports (import devRouter from 'esbuild-dev-router') or enable ESM in your project.
error Build failed: No entry point provided ↓
cause Missing or empty 'entryPoints' option in the config.
fix
Provide an entryPoints array: devRouter({ entryPoints: ['src/index.ts'] })
Warnings
breaking Must be mounted at root path — the SSE reloader endpoint is hardcoded to '/reloader'. ↓
fix Mount at app root: app.use(devRouter({...})). Do NOT mount under a subpath like '/assets'.
deprecated The 'write' option is always forced to false and cannot be overridden. ↓
fix Remove any 'write' option from the config; it does nothing.
gotcha Defaults merge for 'loader', 'plugins', and 'inject' but other options replace defaults. ↓
fix If you provide 'loader', your entries are added alongside .png and .jpg defaults. For other options, your value completely overrides the default.
gotcha Node.js 18+ required. Older Node versions may fail due to modern APIs used internally. ↓
fix Upgrade Node.js to version 18 or later.
gotcha Entry point output filename determines the URL path. E.g., 'src/index.ts' produces '/index.js' and '/index.css'. ↓
fix Reference the bundled file in HTML as '/index.js' (strip the directory and ts extension).
Install
npm install esbuild-dev-router yarn add esbuild-dev-router pnpm add esbuild-dev-router Imports
- default (devRouter) wrong
const devRouter = require('esbuild-dev-router')correctimport devRouter from 'esbuild-dev-router' - devRouter (named) wrong
import devRouter from 'esbuild-dev-router'correctimport { devRouter } from 'esbuild-dev-router' - BuildOptions
import { BuildOptions } from 'esbuild-dev-router'
Quickstart
import express from 'express';
import devRouter from 'esbuild-dev-router';
import { resolve } from 'path';
const app = express();
const port = process.env.PORT ?? 5000;
app.use(devRouter({
entryPoints: [resolve(process.cwd(), 'src/index.ts')],
outdir: resolve(process.cwd(), 'dist'), // used for path resolution only
}));
app.use(express.static(resolve(process.cwd(), 'public')));
app.listen(port, () => {
console.log(`Dev server running on http://localhost:${port}`);
});