Framework
midwayjs/midway avatar
midwayjs/midway

Midway: a TypeScript Node.js framework that runs the same code on a VM and in a FaaS

🍔 A Node.js Serverless Framework for front-end/full-stack developers. Build the application for next decade. Works on AWS, Alibaba Cloud, Tencent Cloud and traditional VM/Container. Super easy integrate with React and Vue. 🌈

7,746 stars584 forksTypeScriptMIT

At a glance

What is it?
Midway is an MIT-licensed, decorator-and-DI Node.js framework for web apps, serverless functions and microservices. It is a real option for teams that already think in TypeScript and want one codebase to leave a container later, and a poor fit for anyone who wants a small dependency surface.
Who is it for?
Adopt Midway if your team writes TypeScript, wants decorator-based controllers and dependency injection, and needs a path from a container to a FaaS provider without a rewrite. Do not adopt it if you want a framework with a small dependency tree or you cannot accept Koa, Express or Egg.js underneath.
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 received new commits within the last day.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 2, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem Midway targets: one Node.js codebase for a VM and for FaaS

Most Node.js frameworks assume one deployment shape. A Koa or Express app is written for a long-running process, and moving it to a function runtime means rewriting the entry point, the routing layer and the way state is held. Midway takes the opposite position: the README describes it as a framework for building Serverless services, traditional applications, microservices and mini-program backends, and states that it can run on AWS, Alibaba Cloud, Tencent Cloud and traditional VM or container environments. The audience is explicit in the repository description: front-end and full-stack developers who already work in TypeScript and do not want to learn a separate serverless toolchain. The framework also advertises integration with React and Vue, and the samples directory contains react-functional-api, react-functional-api-axios, react-functional-api-rspack, react-hybrid-api, vue-functional-api, functional-api-hybrid and functional-api-service. Those names are the clearest signal of intent: the project expects the same repository to hold front-end code and backend endpoints.

Decorators, DI and a pluggable HTTP layer

The mechanism is dependency injection over TypeScript decorators. The README's first example imports Controller, Get and Provide from @midwayjs/decorator, decorates a class with @Provide() and @Controller('/'), and marks a method with @Get('/'). The class is registered in a container, and the container resolves it when a request arrives. This is the same shape as NestJS, and it is the part of Midway that will feel familiar to anyone coming from Angular or Spring.

What differs is the layer underneath. The README states that Midway can use Koa, Express or Egg.js as the base web framework, and that it supports Koa, Express and Egg.js ecosystem plugins. That is a deliberate compatibility bet: instead of writing its own HTTP stack, Midway normalizes several existing ones behind its decorator API. The cost is that behaviour can differ depending on which base you pick, and the documentation is the place to check which middleware semantics apply.

Beyond HTTP, the README lists standalone solutions for Socket.io, gRPC, Dubbo.js and RabbitMQ. Those are the microservice and RPC paths, and they are separate packages rather than part of the core. The repository layout confirms this: packages/ holds the framework packages, packages-serverless/ holds the serverless-specific ones, and packages-resource/ holds resources. The monorepo is managed with lerna and pnpm, with pnpm-workspace.yaml at the root and packageManager set to [email protected] in package.json.

Installing Midway and writing a first controller

The README's quick start is three commands. It begins by checking the npm version, then scaffolds a project from a template, then starts the dev server.

bash
$ npm -v
$ npm init midway
cd my_midway_app && npm run dev

The npm init midway step is interactive: it asks you to choose a template. What you get depends on that choice, so the template picker is the first real decision, not the install command. After cd my_midway_app && npm run dev, the README implies a dev server starts, though it does not print the expected output or the default port. Check the generated package.json in your project for the dev script and the port it binds.

The controller from the README is the smallest working unit. It imports three decorators and returns a string.

ts
import { Controller, Get, Provide } from '@midwayjs/decorator';

@Provide()
@Controller('/')
export class HomeController {

  @Get('/')
  async home() {
    return `Welcome to midwayjs!`;
  }
}

A GET request to the root path returns the string. There is no manual route registration and no explicit container wiring; the decorators do both.

Midway also has a second, quite different style aimed at full-stack work. The README shows a file at src/apis/lambda/index.ts that exports an Api() wrapper around a handler, using Get() and Query<T>() from @midwayjs/hooks. On the front end, the same function is imported and called directly, and the README's example logs { page: '0', limit: '10' }. The README notes that the same endpoint can be reached manually with fetch('/api/articles?page=0&limit=10'). If you want the zero-API-call experience, this is the path; if you want ordinary HTTP routing, the controller example above is the path. They are not the same API surface, and the README presents them as two separate demos rather than one.

Where Midway is the wrong choice

The clearest limitation is the dependency footprint. Midway is a monorepo with a large package set, and the framework itself depends on a base HTTP layer it does not own. If your project is a single endpoint or a small internal service, the decorator and DI machinery is overhead you will pay for on every cold start and every dependency audit. A plain Koa or Express app, or a single-file function handler, will be smaller and easier to reason about.

The second limitation is portability between the two demo styles. The README shows a decorator-based controller and a hooks-based Api() function, but it does not state that a controller can be reused as a hooks endpoint or the reverse. Treat them as two entry points into the same framework, not as interchangeable code.

The third is documentation depth on the operational side. The README covers features, a demo, a quick start and community links. It does not document rollback, cold-start behaviour, or how a given deployment target maps to the packages under packages-serverless/. The repository has a site/ directory and a tutorial/ directory, so the detail exists somewhere, but the README alone is not enough to plan a production rollout. If your team needs a framework where the front page answers deployment questions, this is not it.

Midway against NestJS: compatibility layer versus single stack

NestJS is the closest comparison, and the difference is architectural rather than cosmetic. NestJS ships its own HTTP abstraction and its own adapter model, and you choose Express or Fastify through an adapter. Midway instead states that it can use Koa, Express or Egg.js as the base framework and that it supports plugins from those ecosystems. In practice that means a Midway project can reuse middleware written for Koa or Express, whereas a NestJS project cannot reuse them without an adapter or a rewrite.

The trade-off runs the other way too. NestJS's single stack means the behaviour of a request pipeline is defined by NestJS and its adapters, one place to look. Midway's compatibility layer means the behaviour depends on which base you selected and which plugins you pulled in. If your team already has a Koa or Egg.js middleware investment, Midway is the more direct path. If you want one documented request lifecycle with no base-framework variable, NestJS is the simpler answer. The repository's own topics list both ioc and dependency-injection-container, which tells you the DI container is treated as a first-class part of the product, not an add-on.

Release cadence, licence and what upgrading costs

The repository is not archived, and the last push was on 2026-09-19. Recent releases are v4.2.1 on 2026-06-14, v4.2.2 on 2026-08-25 and v4.2.3 on 2026-09-06. The default branch is v4-next, which is worth noting: the branch you land on when you clone is ahead of the released 4.2.x line, so pin your dependencies to a released version rather than tracking the default branch.

The version history in the repository is split across CHANGELOG-v1.md, CHANGELOG-v2.md and CHANGELOG.md, which is a sign of how much the API has moved across major versions. The README's own examples import from @midwayjs/decorator and @midwayjs/hooks, and the tutorial/ directory exists alongside them. Before upgrading a major version, read the changelog for that version rather than assuming the decorator imports are stable.

The licence is MIT, stated in the README and present as LICENSE at the repository root. MIT permits commercial use, modification and redistribution, and requires that the copyright notice and permission notice be included. That is the general shape of the licence; it is not legal advice, and if you redistribute Midway inside a product you should have your own counsel read the LICENSE file rather than this paragraph. The README also links a FOSSA status badge, which indicates the project tracks dependency licence scanning, though the README does not describe what that scan covers.

Editorial conclusion

Adopt Midway if your team writes TypeScript, wants decorator-based controllers and dependency injection, and needs a path from a container to a FaaS provider without a rewrite. Do not adopt it if you want a framework with a small dependency tree or you cannot accept Koa, Express or Egg.js underneath. Before committing, run npm init midway, check that the generated template matches the runtime you actually deploy to, and confirm the packages you need exist under packages/ in the repository.

Frequently asked questions

What is Midway used for?

Midway is a TypeScript Node.js framework for building Serverless services, traditional applications, microservices and mini-program backends. It also targets front-end and full-stack developers who want to integrate with React or Vue.

How do I install Midway?

The README's quick start checks your npm version, then runs npm init midway to choose a template, then cd my_midway_app && npm run dev to start the dev server. The template you pick determines the project layout.

Which cloud platforms does Midway run on?

The README states it runs on AWS, Alibaba Cloud, Tencent Cloud and traditional VM or container environments. The repository separates serverless-specific packages into the packages-serverless/ directory.

What licence does Midway use?

The README states the code uses the MIT licence, and a LICENSE file is present at the repository root. MIT allows commercial use and modification provided the copyright and permission notice are included.

Official sources

  1. License: MIT
  2. midwayjs/midway on GitHub
  3. Project website
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/midwayjs-midway.svg)](https://hysenlabs.com/projects/midwayjs-midway)