High-performance multi-runtime framework with intelligent routing Functional • Type-safe • Multi-environment • Production-ready
Moro eliminates the pain points of traditional Node.js frameworks with intelligent routing and automatic middleware ordering. No more debugging middleware order issues or wrestling with type safety!
- Multi-Runtime Support - Deploy to Node.js, Vercel Edge, AWS Lambda, Cloudflare Workers
- Intelligent Routing - Chainable + schema-first APIs with automatic middleware ordering
- Enterprise Authentication - Auth.js integration with RBAC, OAuth, and native adapter
- Universal Validation - Support for Zod, Joi, Yup, Class Validator with full TypeScript inference
- WebSocket Support - Pluggable adapters for Socket.IO, native WebSockets, or auto-detection
- Native Performance - Zero framework overhead, optimized for each runtime
- Functional Architecture - No decorators, pure functional patterns
- Zero Order Dependencies - Framework handles optimal middleware execution
| Framework | Req/sec | Latency | Memory |
|---|---|---|---|
| Moro | 52,400 | 1.8ms | 24MB |
| Express | 28,540 | 3.8ms | 45MB |
| Fastify | 38,120 | 2.9ms | 35MB |
| NestJS | 22,100 | 4.5ms | 58MB |
npm install @morojs/moro
# or
yarn add @morojs/moroimport { createApp, z } from '@morojs/moro';
const app = createApp();
// Intelligent routing - order doesn't matter!
app.post('/users')
.body(z.object({
name: z.string().min(2).max(50),
email: z.string().email()
}))
.rateLimit({ requests: 10, window: 60000 })
.describe('Create a new user')
.handler((req, res) => {
// req.body is fully typed and validated!
return { success: true, data: req.body };
});
app.get('/health', () => ({ status: 'healthy' }));
app.listen(3000, () => {
console.log('Moro server running on http://localhost:3000');
});Deploy the same code everywhere:
// Node.js (default)
import { createApp } from '@morojs/moro';
const app = createApp();
app.listen(3000);
// Vercel Edge Functions
import { createAppEdge } from '@morojs/moro';
const app = createAppEdge();
export default app.getHandler();
// AWS Lambda
import { createAppLambda } from '@morojs/moro';
const app = createAppLambda();
export const handler = app.getHandler();
// Cloudflare Workers
import { createAppWorker } from '@morojs/moro';
const app = createAppWorker();
export default { fetch: app.getHandler() };Traditional frameworks:
// Express - Order matters, easy to break
app.use(cors()); // Must be first
app.use(helmet()); // Must be early
app.use(bodyParser()); // Must be before validation
app.use(rateLimit()); // Must be before routes
app.use(validation()); // Must be before handler
app.post('/users', handler); // Must be lastMoro - Order independent:
// Moro - Framework handles optimal ordering
app.post('/users')
.body(UserSchema) // Framework places in validation phase
.rateLimit({ requests: 10, window: 60000 }) // Rate limit phase
.auth({ roles: ['user'] }) // Auth phase
.handler(createUser); // Always executed last// Use any validation library - Zod (default)
import { z } from '@morojs/moro';
const UserSchema = z.object({
name: z.string().min(2).max(50),
email: z.string().email(),
age: z.number().min(18).optional()
});
// Or Joi with adapter
import { joi } from '@morojs/moro';
import Joi from 'joi';
const UserSchema = joi(Joi.object({
name: Joi.string().min(2).max(50).required(),
email: Joi.string().email().required(),
age: Joi.number().min(18).optional()
}));
app.post('/users')
.body(UserSchema) // Works with any validation library!
.handler((req, res) => {
// req.body is fully typed regardless of validation library
const user = req.body; // ✨ Fully typed
return { success: true, data: user };
});// Chainable API (complex routes)
app.post('/orders')
.body(OrderSchema)
.auth({ roles: ['user'] })
.rateLimit({ requests: 5, window: 60000 })
.cache({ ttl: 300 })
.handler(createOrder);
// Schema-first (simple routes)
app.route({
method: 'GET',
path: '/users/:id',
validation: { params: z.object({ id: z.string().uuid() }) },
handler: getUserById
});Pluggable WebSocket adapters with auto-detection:
import { createApp, SocketIOAdapter, WSAdapter } from '@morojs/moro';
const app = createApp({
// Auto-detect available WebSocket library
websocket: { enabled: true },
// Or use specific adapter
websocket: { adapter: new SocketIOAdapter() },
// Or native WebSockets
websocket: { adapter: new WSAdapter() }
});
// Define WebSocket handlers
app.websocket('/chat', {
connect: (socket) => {
console.log(`Client connected: ${socket.id}`);
socket.join('general');
},
message: (socket, data) => {
socket.to('general').emit('message', {
user: socket.user,
text: data.text,
timestamp: new Date()
});
},
disconnect: (socket) => {
console.log(`Client disconnected: ${socket.id}`);
}
});Built-in Auth.js integration with enterprise features:
import { auth, requireAuth, authUtils } from '@morojs/moro/middleware';
// Setup Auth.js with multiple providers
app.use(auth({
providers: [
providers.github({
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
}),
providers.google({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
}),
],
secret: process.env.AUTH_SECRET!,
}));
// Protect routes with role-based access
app.get('/admin/users', withMiddleware(requireAuth({
roles: ['admin']
}), (req, res) => {
return { users: getAllUsers() };
}));
// Manual authentication checks
app.get('/profile', (req, res) => {
if (!authUtils.isAuthenticated(req)) {
return authResponses.unauthorized(res);
}
return {
user: authUtils.getUser(req),
permissions: authUtils.getUserPermissions(req)
};
});Features:
- OAuth Providers - GitHub, Google, Microsoft, LinkedIn, Discord
- Enterprise SSO - Okta, Auth0, AWS Cognito
- Role-Based Access Control (RBAC) - Fine-grained permissions
- Native Auth.js Adapter - Zero external dependencies
- Security Audit Logging - Track authentication events
- Production Ready - JWT sessions, CSRF protection, secure cookies
export default defineModule({
name: 'users',
routes: [
{
method: 'GET',
path: '/',
validation: {
query: z.object({ limit: z.coerce.number().default(10) })
},
handler: async (req, res) => {
return { users: await getUsers(req.query) };
}
}
]
});
await app.loadModule(UsersModule);- Getting Started - Detailed setup and first app
- Authentication Guide - Complete Auth.js integration with RBAC
- Native Auth Adapter - Custom
@auth/morojsadapter - API Reference - Complete framework API documentation
- Migration Guide - From Express, Fastify, NestJS
- Performance Guide - Optimization and benchmarks
- Runtime System - Multi-runtime deployment guide
- Examples Repository - Working examples
- Multi-Runtime Support - Same API works on Node.js, Edge, Lambda, and Workers
- Intelligent Routing - Automatic middleware ordering eliminates Express.js pain points
- Enterprise Authentication - Auth.js integration with OAuth, RBAC, and native adapter
- Universal Validation - Support for any validation library with full type safety
- WebSocket Flexibility - Choose between Socket.IO, native WebSockets, or auto-detection
- Functional Architecture - No decorators, pure functions, better performance
- Type Safety - Universal validation with compile-time and runtime type safety
Same API everywhere - Write once, deploy to any runtime No middleware dependencies - Framework handles optimal ordering Enterprise authentication - Auth.js integration with native adapter Validation flexibility - Use any validation library (Zod, Joi, Yup, Class Validator) WebSocket choice - Socket.IO, native WebSockets, or auto-detection Full type safety - Universal validation provides end-to-end TypeScript inference Clean APIs - Chainable and schema-first approaches Production ready - Circuit breakers, rate limiting, events, RBAC Performance optimized - Runtime-specific adapters
We welcome contributions! See our Contributing Guide for details.
MIT © Moro Framework Team
Ready to deploy everywhere with one codebase?
Get Started • GitHub • npm • Discord