Over the years, our package serve has grown to a widely used solution for everything related to static sites and single page applications.
Today I am very happy to announce a completely new iteration of the project – equipped with many features for configuring every aspect of your static project.

Slimmer Core

Previously, the project's issue list consisted mostly of feature requests. Because serve is used by many developers for various different reasons (each requiring different features), the core eventually became big – leading to slower bootup and installation times.
As of serve 7.0.0, the project only consists of:
With these changes, we carefully re-evaluated all existing features and only left the ones we truly saw a future for within the package.


Before rewriting the project, we refactored out the request handler that was responsible for serving files, rendering directory listings and handling errors.
It is now available as a separate package called serve-handler.
As a result, you can now easily emulate serve programmatically by firing up any HTTP server and adding serve-handler to it. This is how it would look using the native http module:
const handler = require('serve-handler');
const http = require('http');

const server = http.createServer(handler);

server.listen(3000, () => {
  console.log('Listening on http://localhost:3000');
If you would like to use it in conjunction with micro, that is not a problem either.
Technically, you only need to replace http.createServer(handler) with micro(handler), but here is how it would look if you need handle certain things yourself before eventually passing the request on to serve-handler:
const handler = require('serve-handler');
const micro = require('micro');

const server = micro((request, response) => {
  // Do anything you would like with the request or response here
  return handler(request, response);

server.listen(3000, () => {
  console.log('Listening on http://localhost:3000');
Out of the box, serve-handler will give you everything that serve gives you. But there is more:


A great side-effect of serve being powered by serve-handler is that it now provides plenty of configuration options:
  • public (Set a sub directory to be served)
  • cleanUrls (Have .html and .htm extension stripped from paths)
  • rewrites (Rewrite paths to different paths)
  • redirects (Forward paths to different paths or external URLs)
  • headers (Set custom headers for specific paths)
  • directoryListing (Disable directory listing or restrict it to certain paths)
  • unlisted (Exclude paths from the directory listing)
  • trailingSlash (Remove or add trailing slashes to all paths)
In order to use any of them, put them into a serve.json file and place it in the target directory. As an example, the following rewrites rules allow for single page applications to work:
  "rewrites": [{
    "source": "**",
    "destination": "/index.html"
Alternatively, you can also use the --single flag, which simply defaults to the above rule being used as a preset.

Full Compatibility with Firebase/Superstatic

The configuration was inspired by superstatic and works with your existing superstatic.json file right out of the box – you only need to rename it to serve.json.
The options directoryListing and unlisted only exist in serve and are not part of superstatic and responsible for the directory listing:

Unlike before this release, the directory listing is now rendered by serve-handler.

Furthermore, serve allows for rewrites containing path segments:
  "rewrites": [{
    "source": "/:name",
    "destination": "/page-:name.html"
With the above config, a request to /test will lead to the file page-test.html being served.

Picking the Right Response Type

Assuming you would like to consume serve's renderings on the client side, we now have you covered by respecting the value of the Accept header.
By default, a response with a Content-Type of text/html is returned for directory listings and errors. But if you set the Accept header to include application/json, you will receive a JSON response instead:

Depending on the value of Accept, you will receive a different response.


If you have any suggestions for new configuration properties, please head to the serve-handler repository. We are very happy about all the feedback we can get.
In the case, however, that you would like to fix a bug in the command line interface or suggest changes, head to serve.
Also make sure to join our new Spectrum channel if you have any questions.