Getting Started
Quick Start
One command scaffolds a typed, validated MoroJS API. You'll have a running server in under a minute.
What You'll Learn
- Scaffold a MoroJS project with the CLI
- Run the dev server and hit your first endpoints
- Add a typed, validated route
Scaffold Your Project
Run the CLI. You'll be prompted for runtime, validation library, and optional features. Press enter to accept the defaults for a typed REST API.
1npx @morojs/cli init my-apiWhat this does: Creates my-api/ with TypeScript, ESM, validation, and a working src/index.ts wired up. The CLI auto-detects your package manager and installs dependencies.
Want a full project, not just a basic API? The Interactive Project Builder lets you pick a database, auth, runtime, validation, and features, then copies the exact init command to scaffold it all.
Run It
Start the dev server with hot reload:
1cd my-api
2npm run devYou'll see the server come up on port 3000. Hit the welcome and health endpoints already scaffolded for you:
GET http://localhost:3000/: welcome endpointGET http://localhost:3000/health: health check
Add a Typed, Validated Route
Open src/index.ts and add a parameterized GET, a validated POST and a literal health route. Save, and the dev server reloads automatically.
1import { param } from '@morojs/moro';
2import { z } from 'zod';
3
4// Parameterized route — req.params.id is typed as string
5app.get('/users/:id').handler((req) => {
6 return {
7 userId: req.params.id,
8 message: `User ${req.params.id} retrieved`,
9 };
10});
11
12// POST route with body validation (chainable pattern)
13const CreateUserSchema = z.object({
14 name: z.string().min(1),
15 email: z.string().email(),
16 age: z.number().min(18).max(120),
17});
18
19app.post('/users')
20 .validate({ body: CreateUserSchema })
21 .handler((req) => {
22 // req.body is fully typed and validated
23 return {
24 message: 'User created',
25 user: {
26 id: crypto.randomUUID(),
27 ...req.body,
28 createdAt: new Date().toISOString(),
29 },
30 };
31 });
32
33// A literal body is the whole handler: on Moro's native engine it is
34// answered without entering JS at all - and so is param('id'), which
35// echoes that path parameter as the body
36app.get('/health').handler('ok');
37app.get('/user/:id').handler(param('id'));Result: TypeScript knows the shape of req.body from the Zod schema. Invalid requests are rejected automatically before your handler runs.
Prefer to set up MoroJS by hand instead of using the CLI?