vercel/micro: asynchronous HTTP microservices in about 260 lines
Asynchronous HTTP microservices
At a glance
- What is it?
- Micro is a tiny Node.js HTTP framework built around async functions and no middleware. It suits single-purpose container services, and the README explicitly says it is not intended for serverless environments.
- Who is it for?
- Adopt Micro when you are shipping single-purpose Node services in containers and want the request handler to be a plain async function with no middleware stack. Skip it for serverless deployments, which the README explicitly excludes, and for applications that need routing, sessions or plugin composition.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 131 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem Micro solves: a handler function, not a framework
Most Node HTTP frameworks ask you to learn their object model before you can answer a request. Micro inverts that. A service is a function that receives the standard http.IncomingMessage and http.ServerResponse objects, or, in the shorter form the README shows, a function that returns a value. The repository describes the whole project as roughly 260 lines of code, and the feature list names explicit dependency declaration as the replacement for middleware: modules declare all dependencies rather than sharing a global request pipeline.
The intended audience is narrow on purpose. The README states that Micro was created for use within containers and is not intended for use in serverless environments. For Vercel users it goes further and says there is no requirement to use Micro, because the utilities it offers, json among them, are available as Serverless Function helpers. So the target reader is someone running a container that answers one kind of request, not someone assembling a web application.
How the request flow works: return values, helpers and send
The core mechanism is a return value. `return 'Hello World'` is documented as equivalent to `send(res, 200, 'Hello World')`. That means the framework inspects what your function returns and writes it to the response, which is why the shortest example in the README is a function with no arguments at all.
Body parsing is opt-in. The package exports `buffer`, `text` and `json`, each an async function you await. All three accept a `limit` option defaulting to `'1mb'` and an `encoding` defaulting to `'utf8'`. The raw request body is cached on first read, so calling the helpers more than once does not consume the stream twice. Limits are enforced: exceeding the limit throws an Error with `statusCode` 413, and a JSON parse failure throws an Error with `statusCode` 400. Those status codes are the framework's contract for error handling, and they come from the README's API section.
The `send` helper handles the response types for you. A Stream is piped as an octet-stream, a Buffer is written as an octet-stream, an object is serialized as JSON, and a string is written as-is, with `Content-Type` and `Content-Length` set automatically. One caveat is stated plainly: when you pass a Stream, handling the `error` event is your responsibility.
The repository is a pnpm workspace with a `packages/` directory, a separate `test` workspace, and Lerna scripts for publishing. That layout matters if you plan to send patches: the root `package.json` is private and delegates the test run to the test workspace.
Installing Micro and serving your first response
The README is explicit that Micro is meant for production and that development should use `micro-dev`, a separate tool belt for developing microservices. Install the production package with npm:
npm install --save microThen create an `index.js` that exports a function. The minimal version returns a string, and Micro turns that into a 200 response:
module.exports = () => 'Welcome to Micro';Point the `main` property at that file and add a start script that invokes the `micro` binary:
{
"main": "index.js",
"scripts": {
"start": "micro"
}
}Running `npm start` starts the server, and the README says to open `http://localhost:3000`. The CLI listens on `0.0.0.0:3000` by default, looks first for `main` in `package.json` and then for `index.js`, and accepts one or more `-l` or `--listen` arguments. Note the documented behaviour: a single `--listen` argument overwrites the default rather than adding to it. Endpoints can be TCP, UNIX domain sockets, or Windows named pipes, for example `micro -l tcp://hostname:1234` or `micro -l unix:/path/to/socket.sock`. For a platform that injects a port, the README gives `micro -l tcp://0.0.0.0:$PORT`, with `${PORT-3000}` as a Bash-only fallback when the variable is unset.
Reading a JSON body and returning a custom status
A realistic first service parses the incoming body and controls the status code. The README's body parsing example destructures the helpers from the package and awaits them in sequence:
const { buffer, text, json } = require('micro');
module.exports = async (req, res) => {
const buf = await buffer(req);
const txt = await text(req);
const js = await json(req);
console.log(js.price);
return '';
};The README's own comments show the three views of the same payload: a Buffer, the string `'{"price": 9.99}'`, and a parsed object whose `price` is `9.99`. Because the raw body is cached, the three calls do not conflict.
To send something other than 200, import `send`. The status code is always required and is a Number:
const { send } = require('micro');
module.exports = async (req, res) => {
send(res, 400, { error: 'Custom error message' });
};Here the object is serialized as JSON and the content headers are set for you. If you would rather work with `async`/`await` inside the handler, the README's example awaits a sleep call and then returns `'Ready!'`, which is the pattern the feature list means by designed for usage with async and await.
Where Micro is the wrong tool
The most important limitation is written by the maintainers themselves. Micro is not intended for serverless environments, and on Vercel the README says there is no requirement to use it because its utilities are already provided as Serverless Function helpers. If your deployment target is a function platform, the design premise of a long-lived listening server does not apply, and you would be adding a dependency for behaviour the platform already gives you.
The second limitation follows from the absence of middleware. There is no router, no plugin registry and no shared request pipeline in the documented API. A service that needs path-based routing, authentication chains or session handling has to implement them inside the handler or compose separate modules, and the README points readers to an external list of Micro modules rather than shipping one. For a single endpoint that is a feature; for a small web application it is a rewrite waiting to happen.
The third is operational. The README documents the 413 and 400 errors thrown by the body helpers, but it does not document a rollback path, a migration guide between major versions, or a supported Node range. The most recent release listed is 10.0.1 from 2022-11-26, and the repository's last push was on 2026-05-21, so the codebase sees activity while the published release line has been stable for years. Treat the absence of a documented upgrade path as something to check against the repository before you pin a version.
Micro compared with Express
Express is the obvious alternative and the difference is architectural rather than cosmetic. Express builds a middleware stack: every request passes through an ordered list of functions that can mutate the request, the response, or both, and routing is part of that stack. Micro has no such list. A Micro service is one function, dependencies are declared by the module that needs them, and the framework's job is limited to invoking your function and writing its return value.
That changes what you debug. With Express you reason about which middleware ran and in what order. With Micro you reason about your own function, plus the documented helper behaviour around body limits and status codes. The trade is capability for predictability. Express gives you routing, templating conventions and a large ecosystem of middleware; Micro gives you a handler signature and three body helpers. If your service is one endpoint in a container, the smaller surface is the better fit. If it is a product with pages, choose Express or a framework built on it.
Maintenance, licence and the cost of upgrading
Micro is MIT licensed, both in the repository's LICENSE file and in the root `package.json`. That is a permissive licence, and it means you can use the code in commercial and closed-source services; the usual obligations around including the licence text apply, and this is not legal advice.
The repository is not archived, and its last push was on 2026-05-21. The release history tells a different story: 10.0.1 landed on 2022-11-26, 10.0.0 on 2022-11-25, and 9.4.1 on 2022-07-31. Development activity in the repository and published releases are not moving at the same pace, so the version you install from npm is likely to be older than the tree you read on the default branch.
Upgrade cost is hard to estimate from the README alone, because it documents no migration steps between major versions. The surface you would have to audit is small, which works in your favour: the exported helpers are `buffer`, `text`, `json` and `send`, and the CLI accepts `--help`, `--version` and `--listen`. If you depend on the CLI's endpoint parsing or on the exact error objects thrown by the body helpers, pin your version and re-read the release notes before moving.
Editorial conclusion
Adopt Micro when you are shipping single-purpose Node services in containers and want the request handler to be a plain async function with no middleware stack. Skip it for serverless deployments, which the README explicitly excludes, and for applications that need routing, sessions or plugin composition. Before committing, verify two things yourself: that the micro CLI's --listen endpoint syntax matches your deployment target, and that your Node version satisfies the package's engines field, since the README does not state a supported Node range.
Frequently asked questions
How do I install vercel/micro?
Install it with npm install --save micro. The README notes that this package is meant for production and that development should use micro-dev instead.
Can I use vercel/micro on Vercel or in a serverless environment?
No. The README states that Micro was created for use within containers and is not intended for use in serverless environments, and that on Vercel there is no requirement to use it because its utilities are available as Serverless Function helpers.
How does vercel/micro parse a JSON request body?
It exports async helpers named buffer, text and json. You await json(req) to get the parsed object; the raw body is cached on first read, so calling the helpers more than once is safe, and the default limit is '1mb'.
What port does the micro CLI listen on by default?
The CLI listens on 0.0.0.0:3000 by default. You can override it with -l or --listen, and the README warns that a single --listen argument overwrites the default rather than supplementing it.
Is vercel/micro a replacement for Express?
It is a different design rather than a drop-in replacement. Express runs requests through an ordered middleware stack with routing, while Micro invokes a single exported function and documents no middleware; the README points to an external list of modules for extra functionality.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/vercel-micro)