Features
Docs
CLI
Migrations
Benchmarks
Examples

© 2024 MoroJs

The TypeScript framework that figures itself out

200k+ req/sec.Zero config.Every runtime.

Build production APIs with intelligent routing, end-to-end type safety, and built-in everything. Deploy the same code to Node, Edge, Lambda, or Workers.

200k+
req/sec
with uWebSockets.js
0
config
Files required
4
runtimes
One codebase
100%
typed
End-to-end safety
zsh — morojs
~$
The Status Quo

Every Node frameworkmakes you choose.

Speed or features. Simplicity or power. Type-safety or flexibility. You wire middleware in the right order and pray nothing breaks at 3am.

Express

Designed in 2010. No types, no validation, no async-aware errors. Every project rebuilds the same wheels.

Fastify

Fast, but you assemble the framework yourself — schemas, plugins, decorators, lifecycle hooks.

NestJS

Powerful, but heavy. Decorators, modules, providers, DI container — Java in TypeScript clothing.

Hono / Elysia

Minimal and fast — but minimal. You still need auth, validation, websockets, gRPC. Plug and pray.

MoroJS gives you all of it. By default.
The Solution

One framework.Everything included.

Routing, validation, auth, real-time, multi-runtime — every primitive you need, with the ergonomics you want.

Schema-first routing in 6 lines

Validate, type, document, and handle a route in one chain. No middleware files, no DTOs, no decorators.

  • Type inference
    req.body and req.query are fully typed from your schema.
  • Auto-validation
    400 with a structured error before your handler ever runs.
  • Universal validators
    Swap Zod for Joi, Yup, or Class Validator without rewriting.
app.ts
import { createApp, z } from '@morojs/moro'

const app = await createApp()

app.post('/users')
  .body(z.object({
    name: z.string().min(1),
    email: z.string().email(),
    age: z.number().int().min(18),
  }))
  .handler((req) => {
    // req.body is fully typed and already validated
    return { id: crypto.randomUUID(), ...req.body }
  })

app.listen(3000)
The signature feature

Middleware thatorders itself.

Add cors, auth, rate-limit, and validation in any order. MoroJS analyzes dependencies and runs them in the correct sequence — every time.

app.ts — as you wrote itSource
app.post('/users')
// any order works
.cache({ ttl: 60 })
.body(CreateUserSchema)
.rateLimit({ requests: 100, window: 60_000 })
.auth({ roles: ['user'] })
.handler(createUser)
MoroJS execution order
1cache
2body(schema)
3rateLimit
4auth
5handler
No race conditions
Auth always runs before authorization. Validation always before handler.
Order-agnostic
Refactor freely — your middleware will not silently break.
Predictable performance
Cheap middleware (cors, rate-limit) runs first. Heavy work runs last.
Same endpoint, every framework

Less code.More guarantees.

One validated POST endpoint, in four frameworks. Same behavior — radically different effort.

morojs — POST /users
13 lines
import { createApp, z } from '@morojs/moro'

const app = await createApp()

app.post('/users')
  .body(z.object({
    name: z.string().min(1),
    email: z.string().email(),
    age: z.number().int().min(18),
  }))
  .handler((req) => {
    return { id: crypto.randomUUID(), ...req.body }
  })

app.listen(3000)
Result
All of it.
In one chainable call.
  • Schema, validation, types — one chain
  • req.body fully typed, already validated
  • Errors handled by intelligent defaults
  • No plugins. No boilerplate.
Proof, not promises

Up to 226,253 req/sec.Reproduce it yourself.

Every number below is sourced — pulled straight from each framework's own published benchmarks. Same autocannon profile. Click source ↗ on any row.

Requests / second— higher is better
NestJS
9,164
Express
28,104
Koa
36,152
Hono
37,320
Fastify
46,193
Elysia
71,202
MoroJS — single
93,992
MoroJS — clustered
190,717
MoroJS — uWS
226,253
vs Fastify · uWS
+390%
226k vs 46k
vs Elysia (Bun)
+218%
226k vs 71k
vs Hono · clustered
+411%
190k vs 37k
vs Express · clustered
+579%
190k vs 28k

Same autocannon profile (-c100 -d40 -p10). Express, Koa, Hono, Fastify from fastify/benchmarks (Apr 2026, Node 24). NestJS (Fastify adapter) from Sharkbench (Aug 2025, Node 22). Elysia from APIScout 2026 on Bun. MoroJS variants from the published suite on M2 Ultra.

Full methodology
Feature parity, side by side

Everything in the box.Nothing to install.

Auth, validation, websockets, GraphQL, gRPC, HTTP/2 — all first-class. No plugin ecosystem to navigate.

FeatureExpressFastifyNestJSHonoMoroJS
Core
TypeScript native
Zero-config
Intelligent middleware ordering
Multi-runtime (Node/Edge/Lambda/Workers)
Validation
Zod / Joi / Yup support
Type inference from schema
Auth
Built-in OAuth providers
RBAC + sessions, zero deps
Real-time
WebSockets
Server-Sent Events
GraphQL
gRPC
HTTP/2 native
Background work
Built-in job scheduler
Worker threads facade
Mail (SES, SendGrid, Resend)
Performance
uWebSockets transport
Built-in clustering
req/sec (peak, MoroJS suite)28k46k22kn/a226k
Built-in
Via plugin / community
Not supported
Write once. Deploy anywhere.

Same code.Every runtime.

Your business logic does not care where it runs. Switch from Node to Edge to Lambda by changing the entry file — never the routes.

app.ts
Identical in every runtime
// app.ts — your application code, identical in every runtime
import { createApp, z } from '@morojs/moro'

export const app = await createApp()

app.get('/users/:id')
  .params(z.object({ id: z.string().uuid() }))
  .handler((req) => {
    return { id: req.params.id, name: `User ${req.params.id}` }
  })

app.post('/users')
  .body(z.object({ name: z.string(), email: z.string().email() }))
  .handler((req) => ({ id: crypto.randomUUID(), ...req.body }))
server.tsNode.js
// server.ts
import { app } from './app'

app.listen(3000, () => {
  console.log('Ready on :3000 — node runtime')
})

Long-running server, full uWebSockets.js perf available.

More than just an HTTP server

Versioned modules.Built-in scheduler.

Drop a folder, get a versioned API surface. Schedule cron jobs, send mail, run workers — all from the same app instance.

modules/users/index.ts
Module system
// modules/users/index.ts — versioned, isolated, testable
import { defineModule } from '@morojs/moro'
import * as actions from './actions'
import * as schemas from './schemas'

export const usersModule = defineModule({
  name: 'users',
  version: '1.0.0',
  routes: [
    {
      method: 'POST',
      path: '/users',
      handler: actions.createUser,
      validation: { body: schemas.CreateUserSchema },
      rateLimit: { requests: 10, window: 60_000 },
      description: 'Create a new user',
    },
  ],
})

// Mounted at /api/v1.0.0/users — versioning is automatic.
jobs.ts
Job scheduler
// background work, in the same app
import { app, createApp } from '@morojs/moro'

// Cron expression
app.job('cleanup', '0 2 * * *', async () => {
  await db.sessions.deleteExpired()
})

// Macro
app.job('daily-report', '@daily', async (ctx) => {
  await mail.send({ subject: 'Daily report', html: report() })
})

// Interval string — '5m', '1h', '30s'
app.job('health-check', '5m', async (ctx) => {
  ctx.logger.debug('alive', ctx.executionId)
})
Versioned modules

Auto-mounted at /api/v{version}/{module}.

Cron + intervals

Cron expressions, @daily macros, "5m" strings.

Mail adapters

SES, SendGrid, Resend, Nodemailer — same API.

DB adapters

PostgreSQL, MySQL, MongoDB, SQLite, Redis, Drizzle.

Batteries included

Everything you need.Built in. Type-safe.

22 first-class features. No plugin ecosystem to navigate. No "what library do I use for X?". The answer is always: it is already there.

Try it now

No install.Just run it.

A real MoroJS endpoint, executing right here. Change the input, hit run, see the response.

import { createApp, z } from '@morojs/moro'

const app = await createApp()

app.get('/hello')
  .query(z.object({
    name: z.string().optional().default('World'),
  }))
  .handler((req) => ({
    message: `Hello, ${req.query.name}!`,
    timestamp: new Date().toISOString(),
  }))

app.listen(3000)
GET/hello?name=
Response
Press Run to execute.

Build it inthe next 60 seconds.

One command. A typed, validated, production-ready API. No framework decisions left to make.

MIT licensed · No telemetry · Open governance