# vercel/serve: static file serving and directory listing from the command line

> serve is a Node CLI that turns any folder into an HTTP server with a browsable directory listing. It is small, MIT licensed, and built on serve-handler, which you can also mount inside your own Node server.

**vercel/serve** — Static file serving and directory listing

- Repository: https://github.com/vercel/serve
- Website: https://npmjs.com/package/serve
- Stars: 9,904 · Forks: 708
- Language: TypeScript
- License: MIT
- Published: 2026-09-21 · Updated: 2026-09-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/vercel-serve

## The gap serve fills between a file manager and a web server

Opening an HTML file directly in a browser works until the page requests anything over HTTP. Module scripts, fetch calls, and absolute asset paths all fail under the file:// scheme. serve closes that gap by starting an HTTP server rooted at a directory you choose, so relative and absolute URLs resolve the way they will in production.

The audience is narrow and specific. Front-end developers checking a build output, people testing a single static file, and anyone who wants to look at a folder's contents over the local network without configuring nginx or Apache. The README frames it as serving "a static site, single page application or just a static file (no matter if on your device or on the local network)". That last clause matters: the server binds to a port you can reach from another machine, which is the difference between this and a browser extension.

It is not a general purpose application server. There is no routing layer, no template rendering, no database connection, and no documented authentication. If your project needs any of those, serve is the wrong shape of tool, and the README's own advice to use Vercel once the site goes to production signals where the authors draw the line.

## serve-handler is the actual engine, and that shapes what you can configure

The CLI is a thin wrapper. The README states plainly that "the core of serve is serve-handler, which can be used as middleware in existing HTTP servers". That single sentence explains most of the project's behaviour: request handling, content type resolution, directory listing, and compression all live in that separate package, and the CLI mostly parses arguments, picks a port, and prints a banner.

The practical consequence is that configuration is not defined by serve itself. To change behaviour you create a serve.json file in the public folder, and its accepted keys are the options documented in the serve-handler repository. If a setting is not in that list, serve will not honour it. This is a deliberate separation, and it is also the project's sharpest limitation for newcomers: the CLI's own documentation does not enumerate the available options, so you end up reading a second repository to learn what you can configure.

On the dependency side, package.json lists serve-handler 6.1.7 alongside compression, ajv and @zeit/schemas. The presence of a JSON schema validator is consistent with validating serve.json against a known shape rather than accepting arbitrary keys.

## Installing serve and serving a folder on the first try

The fastest route requires no install at all. Run this inside the directory you want to expose, and npx fetches the package, starts the server, and prints a local URL you can open in a browser, along with a network URL for other devices on the same LAN.

```bash
npx serve
```

If you would rather have the command available permanently, install it globally. The README notes you need at least Node LTS for this route, and separately warns that serve v14 onwards requires Node v14 to run, with v13 as the fallback for older runtimes.

```bash
npm install --global serve
```

With the binary on your PATH, you can start the server from anywhere and point it at a specific folder rather than the current directory. This is the pattern to use when your build output lives in a subfolder such as dist or build.

```bash
serve folder-name/
```

When you want to know what else the CLI accepts, ask it directly. This prints the full option list for the installed version, which is more reliable than any third party summary, including this one.

```bash
serve --help
```

To change behaviour, place a serve.json file inside the public folder you are serving. The README points to the serve-handler options page for the properties it accepts. There is no separate global config file documented.

## Using serve-handler as middleware instead of running the CLI

If you already have a Node HTTP server and only want static file handling inside it, the README shows mounting serve-handler directly. This is the more interesting integration path, because it lets you add your own routes around the static handler.

```js
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');
});
```

Two details in that snippet are easy to miss. The handler returns the result of the call, so the arrow function returns it rather than using a block body. And the comment notes that config and middleware are passed as additional arguments, which is how you would supply the same options that serve.json carries when using the CLI. The README also mentions that http.createServer can be replaced with micro.

Note that the example uses require and listens on port 3000. The package itself is published as type module, so this snippet is the CommonJS style shown in the README rather than a reflection of the project's own source layout.

## Where serve stops being the right tool

The most obvious boundary is production. The README recommends Vercel once it is time to push the site to production, and nothing in the documentation describes TLS termination, access control, rate limiting, or running as a supervised service. Serving a directory to colleagues on a trusted network is a different risk profile from exposing the same directory to the internet.

The second limitation is configuration discoverability. Because serve.json keys are defined by serve-handler, a reader of the serve README alone cannot tell which options exist. If your requirement is a specific rewrite rule or header behaviour, you have to confirm it exists in serve-handler's option list before assuming the CLI supports it. The README does not document any rollback or migration path between major versions either, beyond the Node version note about v13 versus v14.

The runtime floor is a real constraint for some teams. serve v14 and later require Node v14, and the global install route asks for Node LTS. On a locked-down machine where you cannot change the Node version, the documented answer is to stay on serve v13, which means you inherit whatever that line of releases supports.

Finally, this is a static server. Anything requiring server side rendering, session state, or request-time data fetching falls outside it, and no amount of serve.json configuration changes that.

## How serve compares with http-server and with a full reverse proxy

The closest alternative in the same niche is http-server, which also serves a directory over HTTP from a Node process and is commonly reached through npx. The difference in approach is architectural: serve delegates request handling to serve-handler, a package designed to be embedded as middleware, while http-server is structured as a standalone binary. In practice that means serve gives you a documented path to reuse the same handler inside your own application, and the README's API section is the evidence for that claim. If you never intend to embed static handling in a Node server, the two tools occupy nearly the same role and the choice comes down to which configuration surface you prefer.

At the other end of the spectrum sits a reverse proxy such as nginx. That is not a like-for-like swap. A reverse proxy is configured for long-running production traffic, with process management and TLS handled outside your application. serve is a foreground process you start and stop. Choosing serve for a laptop demo and nginx for a public endpoint is the split the README itself implies when it points production deployments at Vercel.

## Licence, release cadence and what maintenance costs you

serve is MIT licensed, stated both in package.json and in the repository's license.md file. For most teams that means the usual obligations: keep the copyright and permission notice with any distribution, and understand that the software comes without warranty. This is not legal advice, and if you are redistributing serve inside a product, have your own counsel read the licence text rather than relying on a summary.

The repository is not archived, and the last push was on 2026-06-30. Releases are not frequent: v14.2.6 landed on 2026-03-03, v14.2.5 on 2025-09-04, and 14.2.4 on 2024-10-15. That cadence is worth weighing if you need a fix turned around quickly. It also suggests the surface area is stable, which cuts both ways: fewer surprises on upgrade, and less appetite for new features.

Upgrade cost is dominated by the Node version floor rather than API churn, since the CLI's own option set is small and the real configuration lives in serve-handler and its schema. The repository uses changesets, visible in the .changeset directory and the changeset scripts in package.json, so version bumps and changelog entries are generated from committed changeset files. The CHANGELOG.md at the repository root is the place to check before moving between minor versions.

## Conclusion

Adopt serve when you need to expose a build output folder over HTTP in seconds, or when you want serve-handler as middleware in an existing Node server. Do not adopt it as a production web server: the README points at Vercel for that stage, and there is no documented TLS, access control or process supervision. Before relying on it, verify your Node version is 14 or newer, decide whether a serve.json belongs in your public folder, and read the serve-handler options page, since that is where the actual configuration surface lives.

## FAQ

### How do I install vercel/serve?

The README gives two routes: run npx serve in your project directory for a one-off, or install it globally with npm install --global serve, which requires at least Node LTS. serve v14 and later need Node v14, and the README points at v13 for anyone who cannot upgrade.

### Can I configure vercel/serve beyond the command line flags?

Yes. The README says to create a serve.json file in the public folder and fill it with the properties listed on the serve-handler options page. That page, not the serve README, is where the accepted keys are documented.

### Can I use vercel/serve as middleware inside my own Node server?

The README states that the core of serve is serve-handler and shows it being used as middleware, passed to http.createServer with config and middleware as additional arguments. It notes that http.createServer can be replaced with micro.

### Is vercel/serve meant for production deployments?

The README recommends using Vercel once it is time to push the site to production, and it documents no TLS, access control or process supervision. Treat it as a local and network development server rather than a production endpoint.

## Sources

- [License: MIT](https://github.com/vercel/serve/blob/main/LICENSE)
- [Project website](https://npmjs.com/package/serve)
- [README](https://github.com/vercel/serve/blob/main/README.md)
- [Releases](https://github.com/vercel/serve/releases)
- [vercel/serve on GitHub](https://github.com/vercel/serve)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/vercel-serve
