Modern TypeScript framework with intelligent routing, ESM, and extreme performance
Build high-performance APIs with intelligent routing that automatically orders middleware execution. Deploy anywhere: Node.js, Vercel Edge, AWS Lambda, or Cloudflare Workers - same code, zero configuration.
Key Features:
- Native C++ Engine - ~102k req/s real-world through the full framework, 572k pipelined, on a single thread
- Intelligent Routing - Automatic middleware ordering, no configuration needed
- Enterprise Auth - Built-in Better Auth with OAuth & RBAC
- Universal Validation - Works with Zod, Joi, Yup, or Class Validator
- Message Queues - Production-ready queues (Bull, RabbitMQ, SQS, Kafka)
- gRPC Support - Native gRPC for high-performance microservices
- Multi-Runtime - Deploy to Node.js, Edge, Lambda, or Workers
- Powerful CLI - Scaffold projects, generate modules, deploy with one command
- Zero third-party dependencies - lightweight core (just Moro's own native engine) with optional integrations
MoroJS is the fastest Node.js framework we've measured (not just because its ours) — its native engine beats uWebSockets.js in both benchmark profiles while running the full framework (routing, validation, middleware): ~102k req/s real-world at 0.9 ms latency and 572k req/s pipelined, on a single thread. That's ~1.5× Fastify and ~2× Express out of the box. Full comparison tables, methodology, and saved results live in the MoroJS Benchmark repo.
npm install @morojs/moro
npm install zod # peer dependency used by the `z` validation helper belowimport { createApp, z } from '@morojs/moro';
// createApp() is async — await it inside an async context
(async () => {
const app = await createApp();
// Intelligent routing - order doesn't matter!
app
.post('/users')
.body(
z.object({
name: z.string().min(2),
email: z.string().email(),
})
)
.rateLimit({ requests: 10, window: 60000 })
.handler((req, res) => {
// req.body is fully typed and validated
return { success: true, data: req.body };
});
app.listen(3000);
})();Scaffold a complete project with auth, database, WebSockets, and deployment ready:
npm install -g @morojs/cli
morojs-cli init my-api --runtime=node --database=postgresql --features=auth,websocket,docs
cd my-api
npm run devLearn more at morojs.com/cli
Moro ships its own native HTTP engine (@morojs/engine) and uses it by default,
falling back to the Node.js http server wherever a prebuilt binary isn't
available. Pick the backend with server.engine:
// createApp() is async — top-level await (ESM) or wrap in an async function
const app = await createApp({
server: {
engine: 'moro', // default - Moro's native engine (Node.js fallback if it can't load)
// engine: 'node' - the Node.js http server (no native engine)
// engine: 'uws' - opt in to uWebSockets.js
},
});
// Check which engine actually booted (logged at startup too)
app.engine; // { server, enginePackage?, engineVersion?, protocols?, fallbackReason? }One server.ssl config flows to whichever runtime serves — the Moro engine terminates TLS in-process, as do the Node https server, uWebSockets.js (file paths only), and the HTTP/2 server. Both shapes are accepted:
// Inline PEM (node-style) — works on engine, node, http2
createApp({ server: { engine: 'moro', ssl: { key, cert, ca } } });
// File paths — works on every runtime incl. uWS
createApp({ server: { engine: 'moro', ssl: { keyFile: './key.pem', certFile: './cert.pem' } } });http2: true serves ALPN h2 + http/1.1. When engine: 'moro' and the engine
build supports h2 it is served natively; otherwise Moro uses its dedicated
HTTP/2 server. Requires TLS.
createApp({ server: { engine: 'moro', http2: true, ssl: { key, cert } } });Every limit is a documented default you can override; values flow through to the engine. Nothing is silently capped.
createApp({
server: {
bodySizeLimit: '10mb', // maxUploadSize: '100mb' for multipart
maxConnections: 0, // 0 = unlimited
timeouts: { request: 30000, idle: 0, keepAlive: 5000, headers: 6000 },
limits: {
maxHeaderSize: '64kb',
maxHeaders: 100,
wsMaxMessageSize: '16mb',
wsBackpressureLimit: '1mb',
multipart: { maxParts: 1000, maxFiles: 20, maxFileSize: '25mb' },
},
},
});See HTTP Engine Guide, HTTP/2 Guide, and the Configuration Reference for the full defaults table.
Same code, multiple platforms:
// Node.js
app.listen(3000);
// Vercel Edge
export default app.getHandler();
// AWS Lambda
export const handler = app.getHandler();
// Cloudflare Workers
export default { fetch: app.getHandler() };📚 Complete guides at morojs.com/docs
Check out working examples for:
- REST APIs with validation
- Real-time WebSocket apps
- Better Auth integration
- Multi-runtime deployment
- Database integration
- And more...
vs Express - Intelligent middleware ordering eliminates configuration complexity and race conditions
vs Fastify - ~1.5x the throughput out of the box (Moro's native engine), plus multi-runtime deployment without adapters
vs NestJS - Functional architecture without decorators, with a fraction of the per-request overhead
Contributions welcome! See CONTRIBUTING.md
MIT © Moro Framework Team
Ready to build high-performance APIs?
Get Started • GitHub • npm • Discord