serve vs live-server vs browser-sync vs http-server vs lite-server vs nodemon vs webpack-dev-server
Local Development Servers and Tooling for Frontend Workflows
servelive-serverbrowser-synchttp-serverlite-servernodemonwebpack-dev-serverSimilar Packages:

Local Development Servers and Tooling for Frontend Workflows

These packages provide essential infrastructure for local web development, ranging from simple static file serving to complex build tool integration. http-server, serve, and live-server focus on serving static assets with varying degrees of configuration. browser-sync and lite-server add live reloading and device syncing capabilities. webpack-dev-server integrates tightly with module bundlers for hot module replacement. nodemon differs by monitoring file changes to restart Node.js processes rather than serving static files directly. Together, they form the backbone of local testing environments.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
serve2,257,4799,90626 kB1548 months agoMIT
live-server58,3054,56153.7 kB212-MIT
browser-sync012,292582 kB5782 years agoApache-2.0
http-server014,243124 kB110-MIT
lite-server02,303-796 years agoMIT
nodemon026,653219 kB148 months agoMIT
webpack-dev-server07,842966 kB322 days agoMIT

Local Development Servers and Tooling for Frontend Workflows

Choosing the right local server tool impacts your daily development speed, testing accuracy, and deployment confidence. While all seven packages help you run code locally, they solve different problems β€” from simple file serving to complex module hot-swapping. Let's compare how they handle common engineering tasks.

πŸš€ Live Reloading and Hot Module Replacement

Live reloading refreshes the browser when files change, while Hot Module Replacement (HMR) updates code without a full refresh. This distinction matters for preserving application state during development.

browser-sync injects a script to reload the browser or sync interactions.

# browser-sync: Watch files and reload
browser-sync start --server "app" --files "*.css, *.html"

lite-server enables live reload out of the box using browser-sync underneath.

// lite-server: Default bs-config.json behavior
{
  "server": { "baseDir": "./app" },
  "files": ["*.html", "*.css"]
}

live-server watches files and triggers a full page reload.

# live-server: Watch and reload
live-server --port=8080 --watch=css

webpack-dev-server supports true HMR for JavaScript modules.

// webpack-dev-server: webpack.config.js
module.exports = {
  devServer: {
    hot: true,
    static: "./dist"
  }
};

http-server does not support live reloading natively.

# http-server: Static only, no reload
npx http-server ./dist

serve does not support live reloading natively.

# serve: Static only, no reload
npx serve ./dist

nodemon restarts Node processes, not browser pages.

# nodemon: Restart server process
nodemon server.js

πŸ› οΈ Configuration and Setup Complexity

Some tools work immediately, while others require config files to unlock features. Your choice depends on how much control you need versus how quickly you want to start.

browser-sync offers flexible CLI options or a config file.

// browser-sync: bs-config.js
module.exports = {
  server: { baseDir: "./src" },
  port: 3000
};

lite-server uses a simplified config file for browser-sync.

// lite-server: bs-config.json
{
  "server": { "baseDir": "./public" }
}

live-server relies mostly on CLI flags.

# live-server: CLI flags
live-server --port=3000 --open=/index.html

webpack-dev-server requires a webpack configuration file.

// webpack-dev-server: webpack.config.js
module.exports = {
  mode: "development",
  devServer: { port: 8080 }
};

http-server requires zero configuration.

# http-server: Run anywhere
npx http-server

serve uses optional flags or a serve.json file.

// serve: serve.json
{
  "public": "./build",
  "port": 3000
}

nodemon uses nodemon.json or CLI flags.

// nodemon: nodemon.json
{
  "ext": "js,json",
  "ignore": ["node_modules"]
}

🧭 Single Page Application (SPA) Routing

SPAs require the server to return index.html for all routes so the client-side router can handle navigation. Not all static servers support this fallback behavior.

browser-sync supports SPA fallback via configuration.

// browser-sync: Middleware for SPA
middleware: function (req, res, next) {
  res.setHeader("Cache-Control", "no-cache");
  next();
}
// Requires custom middleware for full SPA fallback

lite-server supports SPA fallback via history API middleware.

// lite-server: Enable history API fallback
{
  "server": { "baseDir": "./app", "middleware": { "1": "connect-history-api-fallback" } }
}

live-server does not support SPA routing fallback natively.

# live-server: No built-in SPA fallback
# Returns 404 on refresh for non-root routes

webpack-dev-server handles SPA routing via historyApiFallback.

// webpack-dev-server: Config for SPA
devServer: {
  historyApiFallback: true
}

http-server does not support SPA routing fallback.

# http-server: No SPA support
# Will 404 on /about if file doesn't exist

serve supports SPA routing with a specific flag.

# serve: Enable single page app mode
npx serve ./build --single

nodemon does not serve static files directly.

// nodemon: Used with express for SPA
app.get("*", (req, res) => res.sendFile("index.html"));

πŸ”— Backend Proxying and Integration

When your frontend needs to talk to a local API, proxying requests avoids CORS issues. Some tools handle this better than others.

browser-sync can proxy an existing local server.

# browser-sync: Proxy existing server
browser-sync start --proxy "localhost:8000"

lite-server supports proxying via config.

// lite-server: Proxy config
{
  "proxy": "http://localhost:8000"
}

live-server has limited proxy support via plugins.

# live-server: Requires custom middleware for proxying
# Not recommended for complex proxy setups

webpack-dev-server supports proxy tables in config.

// webpack-dev-server: Proxy table
devServer: {
  proxy: {
    "/api": "http://localhost:3000"
  }
}

http-server does not support proxying.

# http-server: Static files only
# Cannot proxy API requests

serve does not support proxying.

# serve: Static files only
# Use a separate backend for API

nodemon restarts the backend server itself.

# nodemon: Restart API server
nodemon ./api/server.js

πŸ›‘οΈ Production Parity and Security

Testing locally in an environment that matches production reduces deployment surprises. Security headers and compression matter here.

browser-sync focuses on development, not production security.

# browser-sync: Dev focused
# No production security headers by default

lite-server inherits browser-sync development focus.

# lite-server: Dev focused
# Not suitable for production hosting

live-server has known security vulnerabilities.

# live-server: Security risks
# Avoid using for sensitive projects

webpack-dev-server is strictly for development.

# webpack-dev-server: Dev only
# Never deploy this server to production

http-server is basic and lacks security headers.

# http-server: Basic serving
# No custom security headers

serve includes security headers and compression.

# serve: Production-like
npx serve ./build --prod

nodemon is for process management, not serving security.

# nodemon: Process monitor
# Security depends on the app it runs

πŸ“Š Summary: Key Differences

Featurebrowser-synchttp-serverlite-serverlive-servernodemonservewebpack-dev-server
Live Reloadβœ… Yes❌ Noβœ… Yesβœ… Yes❌ Process Only❌ Noβœ… HMR
SPA Routing⚠️ Custom❌ Noβœ… Yes❌ No⚠️ App Dependentβœ… --singleβœ… Config
Proxyingβœ… Yes❌ Noβœ… Yes⚠️ Limited⚠️ App Dependent❌ Noβœ… Yes
ConfigFlexibleNoneSimpleCLISimpleSimpleComplex
Best ForMulti-deviceQuick StaticAngular/StaticLegacyNode BackendProd TestWebpack Apps

πŸ’‘ The Big Picture

serve and http-server are best for testing static builds β€” choose serve if you need SPA routing or security headers.

browser-sync and lite-server shine when you need live reloading β€” pick lite-server for simplicity or browser-sync for advanced device syncing.

webpack-dev-server is the standard for complex bundler setups β€” use it if you need Hot Module Replacement with webpack.

nodemon belongs in your backend toolkit β€” use it to restart Node APIs, not to serve frontend assets.

live-server should be avoided in new projects β€” security risks and maintenance gaps make it a liability compared to modern alternatives.

Final Thought: Your local tooling should match your deployment target. If you deploy to a static host, test with serve. If you deploy a bundled app, develop with webpack-dev-server. Avoid mixing development-only tools with production testing to catch issues early.

How to Choose: serve vs live-server vs browser-sync vs http-server vs lite-server vs nodemon vs webpack-dev-server

  • serve:

    Choose serve when you need a local server that mimics production behavior, including security headers and SPA routing support. It is excellent for testing build outputs before deployment to ensure your static site behaves correctly in a production-like environment.

  • live-server:

    Avoid live-server for new projects due to known security vulnerabilities and slower maintenance cycles. If you must use it, restrict it to isolated local environments, but prefer browser-sync or vite for safer, modern alternatives.

  • browser-sync:

    Choose browser-sync if you need to test responsive designs across multiple devices simultaneously or require advanced proxying features. It is ideal for teams that need to sync clicks and scrolls across browsers during QA or when working with a existing backend server.

  • http-server:

    Choose http-server for quick, zero-configuration static file serving when live reload is not required. It is best suited for simple tasks like hosting a build output temporarily or testing static assets without installing heavy dependencies.

  • lite-server:

    Choose lite-server if you want live reloading with minimal configuration, especially for Angular or static projects. It wraps browser-sync with sensible defaults, making it a good choice for developers who want sync features without managing complex config files.

  • nodemon:

    Choose nodemon when developing Node.js backend services or build scripts that need to restart on file changes. It is not a static server itself, so pair it with a server package if you need to serve HTML or assets alongside your API.

  • webpack-dev-server:

    Choose webpack-dev-server if your project relies heavily on webpack for bundling and you need Hot Module Replacement (HMR). It is the standard choice for complex frontend applications using webpack, offering deep integration with loaders and plugins.

README for serve

Serve Logo


serve helps you serve a static site, single page application or just a static file (no matter if on your device or on the local network). It also provides a neat interface for listing the directory's contents:

Listing UI

Once it's time to push your site to production, we recommend using Vercel.

Usage

serve v14 onwards requires Node v14 to run. Please use serve v13 if you cannot upgrade to Node v14.

The quickest way to get started is to just run npx serve in your project's directory.

If you prefer, you can also install the package globally (you'll need at least Node LTS):

> npm install --global serve

Once that's done, you can run this command inside your project's directory...

> serve

...or specify which folder you want to serve:

> serve folder-name/

Finally, run this command to see a list of all available options:

> serve --help

Now you understand how the package works! :tada:

Configuration

To customize serve's behavior, create a serve.json file in the public folder and insert any of these properties.

API

The core of serve is serve-handler, which can be used as middleware in existing HTTP servers:

const handler = require('serve-handler');
const http = require('http');

const server = http.createServer((request, response) => {
  // You pass two more arguments for config and middleware
  // More details here: https://github.com/vercel/serve-handler#options
  return handler(request, response);
});

server.listen(3000, () => {
  console.log('Running at http://localhost:3000');
});

You can also replace http.createServer with micro.

Issues and Contributing

If you want a feature to be added, or wish to report a bug, please open an issue here.

If you wish to contribute to the project, please read the contributing guide first.

Credits

This project used to be called list and micro-list. But thanks to TJ Holowaychuk handing us the new name, it's now called serve (which is much more definite).

Author

Leo Lamprecht (@leo)