Documentation•Reference
Migrate from Express to HazelJS
Map Express routes and middleware to HazelJS controllers and modules — then add agents and RAG without bolting on a second stack.
Quick Reference
- Purpose: Move from unopinionated Express APIs to HazelJS modules/DI, optionally with
@hazeljs/ai,@hazeljs/agent, and@hazeljs/rag. - When to use: Express apps growing into structured TypeScript backends or AI product APIs.
- Key concepts:
@Controller,@HazelModule, providers, middleware → guards/middleware, AI packages. - Related: HazelJS vs Express, REST API tutorial, Migrate from NestJS.
Should you migrate?
Move to HazelJS when:
- The Express app is accumulating ad-hoc structure (folders of routers, manual DI)
- You need agents, RAG, or multi-provider LLMs as product features
- You want Nest-style organization without Nest + LangChain glue
Keep Express when:
- The service is a thin webhook or proxy
- You deliberately want zero framework
- There is no AI or growth path that needs modules
Concept mapping
| Express | HazelJS |
|---|---|
app.get/post / Router | @Controller + @Get / @Post |
app.use(middleware) | Middleware + guards / pipes |
| Manual service singletons | @Injectable() providers + DI |
express.json() | Framework body parsing (see core docs) |
openai SDK in a route | @AITask / AIService / agents |
| Ad-hoc folders | @HazelModule composition |
Step 1 — Bootstrap
npm install @hazeljs/core
import { HazelApp, HazelModule, Controller, Get } from '@hazeljs/core';
@Controller({ path: '/health' })
class HealthController {
@Get()
ok() {
return { ok: true };
}
}
@HazelModule({ controllers: [HealthController] })
class AppModule {}
async function bootstrap() {
const app = new HazelApp(AppModule);
await app.listen(3000);
}
bootstrap();
Step 2 — Port a route
Express:
router.post('/chat', async (req, res) => {
const message = req.body.message;
res.json({ reply: message });
});
HazelJS:
import { Controller, Post, Body } from '@hazeljs/core';
@Controller({ path: '/chat' })
export class ChatController {
@Post()
chat(@Body() body: { message: string }) {
return { reply: body.message };
}
}
Step 3 — Add AI when ready
import { Controller, Post, Body } from '@hazeljs/core';
import { AITask } from '@hazeljs/ai';
@Controller({ path: '/chat' })
export class ChatController {
@AITask({ provider: 'openai', model: 'gpt-4o' })
@Post()
async chat(@Body() body: { message: string }) {
return body.message;
}
}
For tools and memory, prefer @Agent / @Tool — see Agent package and Support agent example.
Incremental strategies
- New AI service — Keep Express for legacy; put agents on HazelJS behind your gateway.
- Route group rewrite — Move
/v2/*to HazelJS controllers first. - Strangler — Proxy paths gradually until Express can retire.
Checklist
- Core app listens with a health controller
- Critical routes mapped to controllers
- Auth/rate limits replaced with packages or edge controls
- AI surfaces use
@hazeljs/aior agents (not raw SDK sprawl) - Read HazelJS vs Express for positioning