HazelJS CLI
The @hazeljs/cli provides a powerful command-line interface for scaffolding HazelJS applications, generating components, and managing packages. It eliminates boilerplate, enforces best practices, and accelerates development from day one.
Installation
Install globally to use the hazel command anywhere:
npm install -g @hazeljs/cli
Or use it via npx without installing:
npx @hazeljs/cli new my-app
Architecture
The CLI uses a template-based generation system powered by Mustache. Every generator follows the same pattern: accept a name, resolve template data, render the template, and write the file.
graph LR A["hazel g controller users"] --> B["Generator Base Class"] B --> C["Mustache Template Engine"] C --> D["users.controller.ts"] style A fill:#3b82f6,stroke:#60a5fa,stroke-width:2px,color:#fff style B fill:#8b5cf6,stroke:#a78bfa,stroke-width:2px,color:#fff style C fill:#8b5cf6,stroke:#a78bfa,stroke-width:2px,color:#fff style D fill:#10b981,stroke:#34d399,stroke-width:2px,color:#fff
Key design decisions:
- Unified Generator class — every generator extends a base class with a
suffixproperty, so files are consistently named (name.controller.ts,name.service.ts,name.guard.ts, etc.) - Shared utilities —
toPascalCase,toKebabCase,toCamelCase, andrenderTemplatelive in one place and are used by all generators --dry-runsupport — every generator can preview what it would create without writing anything
Creating a New Application
Basic Usage
hazel new my-app
This scaffolds a complete HazelJS project with:
src/index.ts— entry point with CORS and properHazelAppbootstrapsrc/app.module.ts— root module with@HazelModuledecoratorsrc/hello.controller.ts— example controllerpackage.json— dependencies, scripts (build,start,dev,test,lint,format), ESLint devDependenciestsconfig.json— TypeScript config with decorators, strict mode, androotDir: ./src.eslintrc.js— ESLint config with TypeScript and Prettier.gitignore— sensible defaults
Interactive Mode
hazel new my-app --interactive
# or
hazel new my-app -i
Interactive mode walks you through project setup:
- Description — project description for
package.json - Author — your name
- License — Apache-2.0 (default), MIT, GPL-3.0, BSD-3-Clause, or ISC
- Packages — select additional HazelJS packages to install
When you select packages in interactive mode, the CLI automatically:
- Installs the npm packages
- Updates
app.module.tswith the correct imports and module registration - Creates
.envand.env.examplefiles when Config is selected - Sets up Swagger integration in
index.tswhen Swagger is selected
Available packages in interactive mode
| Package | What gets scaffolded |
|---|---|
@hazeljs/ai | AIModule in app module |
@hazeljs/agent | AgentModule in app module |
@hazeljs/auth | JwtModule.forRoot() in app module |
@hazeljs/cache | CacheModule in app module |
@hazeljs/config | ConfigModule.forRoot() + .env files |
@hazeljs/cron | CronModule in app module |
@hazeljs/data | DataModule.forRoot() in app module |
@hazeljs/discovery | Installed — use ServiceRegistry/DiscoveryClient programmatically |
@hazeljs/event-emitter | EventEmitterModule.forRoot() in app module |
@hazeljs/gateway | GatewayModule in app module |
@hazeljs/graphql | GraphQLModule in app module |
@hazeljs/grpc | GrpcModule in app module |
@hazeljs/kafka | KafkaModule in app module |
@hazeljs/messaging | MessagingModule in app module |
@hazeljs/ml | MLModule.forRoot() in app module |
@hazeljs/mcp | Installed — use createMcpServer() for Model Context Protocol |
@hazeljs/pdf-to-audio | PdfToAudioModule in app module |
@hazeljs/prompts | Installed — use PromptTemplate, PromptRegistry for typed prompts |
@hazeljs/prisma | PrismaModule in app module |
@hazeljs/queue | QueueModule in app module |
@hazeljs/rag | RAGModule in app module |
@hazeljs/resilience | Installed — use CircuitBreaker, WithRetry decorators in services |
@hazeljs/serverless | Installed — use createLambdaHandler in handler files |
@hazeljs/swagger | SwaggerModule + updated index.ts with Swagger setup |
@hazeljs/websocket | WebSocketModule in app module |
Options
| Flag | Description |
|---|---|
-d, --dest <path> | Destination directory (default: .) |
--skip-install | Skip running npm install |
--skip-git | Skip git init |
-i, --interactive | Interactive project setup |
Generating Components
All generators live under hazel generate (alias: hazel g). Every generator supports:
-p, --path <path>— custom output directory--dry-run— preview files without writing them
Quick Reference
| Command | Alias | Creates |
|---|---|---|
hazel g controller <name> | c | name.controller.ts |
hazel g service <name> | s | name.service.ts |
hazel g module <name> | m | Module + controller + service + DTOs |
hazel g dto <name> | d | name.dto.ts + update-name.dto.ts |
hazel g guard <name> | gu | name.guard.ts |
hazel g interceptor <name> | i | name.interceptor.ts |
hazel g middleware <name> | mw | name.middleware.ts |
hazel g filter <name> | f | name.filter.ts |
hazel g pipe <name> | — | name.pipe.ts |
hazel g crud <name> | — | Full CRUD resource |
hazel g auth | — | Auth module + JWT guard + DTOs |
hazel g gateway <name> | ws | name.gateway.ts |
hazel g repository <name> | repo | name.repository.ts |
hazel g ai-service <name> | ai | name.ai-service.ts |
hazel g agent <name> | — | name.agent.ts |
hazel g serverless <name> | sls | name.handler.ts |
hazel g config | — | app.config.ts |
hazel g cache <name> | — | name.cache.ts |
hazel g cron <name> | job | name.cron.ts |
hazel g rag <name> | — | name.rag.ts |
hazel g discovery <name> | — | name.discovery.ts |
Core Generators
Controller
hazel g controller users
# alias: hazel g c users
Generates users.controller.ts:
import { Controller, Get, Post, Body, Param, Delete, Put } from '@hazeljs/core';
import { UsersService } from './users.service';
import { CreateUsersDto } from './dto/create-users.dto';
import { UpdateUsersDto } from './dto/update-users.dto';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
findAll() {
return this.usersService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.usersService.findOne(id);
}
@Post()
create(@Body(CreateUsersDto) createDto: CreateUsersDto) {
return this.usersService.create(createDto);
}
@Put(':id')
update(@Param('id') id: string, @Body(UpdateUsersDto) updateDto: UpdateUsersDto) {
return this.usersService.update(id, updateDto);
}
@Delete(':id')
remove(@Param('id') id: string) {
return this.usersService.remove(id);
}
}
Service
hazel g service users
# alias: hazel g s users
Generates users.service.ts:
import { Service } from '@hazeljs/core';
@Service()
export class UsersService {
constructor() {}
async findAll() {
return [];
}
async findOne(id: string) {
return { id };
}
async create(createDto: any) {
return createDto;
}
async update(id: string, updateDto: any) {
return { id, ...updateDto };
}
async remove(id: string) {
return { id };
}
}
Module
hazel g module users
# alias: hazel g m users
Generates a complete feature module with 5 files in src/users/:
| File | Description |
|---|---|
users.module.ts | Module with @HazelModule decorator |
users.controller.ts | Controller with @Controller |
users.service.ts | Service with @Injectable |
dto/create-users.dto.ts | Create DTO |
dto/update-users.dto.ts | Update DTO |
// users.module.ts
import { HazelModule } from '@hazeljs/core';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
@HazelModule({
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}
DTO (Data Transfer Objects)
hazel g dto product
# alias: hazel g d product
Generates two files in src/dto/:
// product.dto.ts (Create)
import { IsString, IsOptional } from 'class-validator';
export class CreateProductDto {
@IsString()
name: string;
@IsString()
@IsOptional()
description?: string;
}
// update-product.dto.ts (Update)
import { IsString, IsOptional } from 'class-validator';
export class UpdateProductDto {
@IsString()
@IsOptional()
name?: string;
@IsString()
@IsOptional()
description?: string;
}
Guard
hazel g guard auth
# alias: hazel g gu auth
Generates auth.guard.ts:
import { Service, type CanActivate, type ExecutionContext } from '@hazeljs/core';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
// Add your guard logic here
return true;
}
}
Interceptor
hazel g interceptor logging
# alias: hazel g i logging
Generates logging.interceptor.ts:
import { Service, Interceptor, type ExecutionContext } from '@hazeljs/core';
@Injectable()
export class LoggingInterceptor implements Interceptor {
async intercept(context: ExecutionContext, next: () => Promise<unknown>): Promise<unknown> {
// Pre-processing logic here
const result = await next();
// Post-processing logic here
return result;
}
}
Middleware
hazel g middleware logger
# alias: hazel g mw logger
Generates logger.middleware.ts:
import { Service, type MiddlewareHandler, type Request, type Response, type NextFunction } from '@hazeljs/core';
@Injectable()
export class LoggerMiddleware implements MiddlewareHandler {
use(req: Request, res: Response, next: NextFunction) {
console.log(`[LoggerMiddleware] ${req.method} ${req.url}`);
next();
}
}
Exception Filter
hazel g filter http
# alias: hazel g f http
Generates http.filter.ts:
import { Catch, type ExceptionFilter, type ArgumentsHost, HttpError, logger } from '@hazeljs/core';
@Catch(HttpError)
export class HttpExceptionFilter implements ExceptionFilter<HttpError> {
catch(exception: HttpError, host: ArgumentsHost): void {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
const status = exception.statusCode || 500;
const message = exception.message || 'Internal server error';
logger.error(`[${request.method}] ${request.url} - ${message} (${status})`);
response.status(status).json({
statusCode: status,
message,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}
Pipe
hazel g pipe validation
Generates validation.pipe.ts:
import { type PipeTransform, type RequestContext } from '@hazeljs/core';
export class ValidationPipe implements PipeTransform {
transform(value: unknown, context: RequestContext): unknown {
// Transform logic here
return value;
}
}
CRUD Generator
The CRUD generator creates a complete REST resource in one command:
hazel g crud product
This generates 4 files in src/product/:
| File | Description |
|---|---|
product.controller.ts | Full CRUD controller (GET, POST, PUT, DELETE) |
product.service.ts | Service with all CRUD operations |
dto/product.dto.ts | Create and Update DTOs with class-validator |
product.module.ts | Module wiring everything together |
Custom Route Path
hazel g crud product -r api/v1/products
This sets the controller route to /api/v1/products instead of the default /product.
Auth Generator
Scaffolds a complete authentication module in one command:
hazel g auth
Generates 6 files in src/auth/:
| File | Description |
|---|---|
auth.module.ts | Auth module with providers and exports |
auth.service.ts | Service with register() and login() methods |
auth.controller.ts | Controller with POST /auth/register and /auth/login |
jwt-auth.guard.ts | JWT Bearer token guard using @hazeljs/auth |
dto/register.dto.ts | Register DTO with email, name, password validation |
dto/login.dto.ts | Login DTO with email, password validation |
After generating, follow the next steps printed by the CLI:
- Import
AuthModulein your app module - Configure
JwtModule.forRoot({ secret: "your-secret", expiresIn: "1d" }) - Install bcryptjs:
npm install bcryptjs @types/bcryptjs - Implement database integration in
AuthService
Package-Specific Generators
WebSocket Gateway
hazel g gateway chat
# alias: hazel g ws chat
Generates chat.gateway.ts using @hazeljs/websocket:
import { Realtime, OnConnect, OnDisconnect, OnMessage, Subscribe, Client, Data, WebSocketClient } from '@hazeljs/websocket';
@Realtime('/chat')
export class ChatGateway {
@OnConnect()
handleConnection(@Client() client: WebSocketClient) {
console.log('Client connected:', client.id);
}
@OnDisconnect()
handleDisconnect(@Client() client: WebSocketClient) {
console.log('Client disconnected:', client.id);
}
@Subscribe('message')
@OnMessage('message')
handleMessage(@Client() client: WebSocketClient, @Data() data: unknown) {
console.log('Message received from', client.id, ':', data);
}
}
Repository (Prisma)
hazel g repository user
# alias: hazel g repo user
Generates user.repository.ts extending BaseRepository from @hazeljs/prisma:
import { Repository } from '@hazeljs/prisma';
import { PrismaService } from '@hazeljs/prisma';
@Repository({ model: 'user' })
export class UserRepository extends BaseRepository<any> {
constructor(prisma: PrismaService) {
super(prisma.client.modelName);
}
async findByName(name: string) {
return this.findMany({ where: { name } });
}
}
AI Service
hazel g ai-service chat
# alias: hazel g ai chat
Generates chat.ai-service.ts using @hazeljs/ai:
import { Service } from '@hazeljs/core';
import { AIService, AIFunction, AIPrompt } from '@hazeljs/ai';
@Service()
export class ChatAIService {
constructor(private readonly aiService: AIService) {}
@AIFunction({
provider: 'openai',
model: 'gpt-4',
streaming: false,
})
async chatTask(@AIPrompt() prompt: string): Promise<unknown> {
const result = await this.aiService.complete({
provider: 'openai',
model: 'gpt-4',
messages: [{ role: 'user', content: prompt }],
});
return result;
}
}
AI Agent
hazel g agent research
Generates research.agent.ts using @hazeljs/agent:
import { Agent, Tool } from '@hazeljs/agent';
@Agent({
name: 'research',
description: 'A research agent',
systemPrompt: 'You are a helpful Research agent.',
enableMemory: true,
enableRAG: true,
})
export class ResearchAgent {
@Tool({
description: 'Example tool for research',
parameters: [
{ name: 'input', type: 'string', description: 'Input parameter', required: true },
],
})
async exampleTool(input: { input: string }): Promise<{ result: string }> {
return { result: `Processed: ${input.input}` };
}
}
Serverless Handler
# AWS Lambda (default)
hazel g serverless api
# alias: hazel g sls api
# Google Cloud Function
hazel g serverless api --platform cloud-function
Generates api.handler.ts:
// Lambda
import { createLambdaHandler } from '@hazeljs/serverless';
import { AppModule } from './app.module';
export const handler = createLambdaHandler(AppModule);
// Cloud Function
import { createCloudFunctionHandler } from '@hazeljs/serverless';
import { AppModule } from './app.module';
export const handler = createCloudFunctionHandler(AppModule);
Config
hazel g config
Generates app.config.ts with setup instructions for @hazeljs/config:
import { ConfigModule, ConfigService } from '@hazeljs/config';
// Add to your app module imports:
// ConfigModule.forRoot({ envFilePath: '.env' })
//
// Inject and use:
// this.config.get('DATABASE_URL');
// this.config.get('PORT', '3000'); // with default
Cache
hazel g cache product
Generates product.cache.ts with @Cacheable and @CacheEvict decorators from @hazeljs/cache:
import { Service } from '@hazeljs/core';
import { CacheService, Cacheable, CacheEvict } from '@hazeljs/cache';
@Service()
export class ProductCacheService {
constructor(private readonly cacheService: CacheService) {}
@Cacheable({ key: 'product:all', ttl: 60 })
async findAll() {
return [];
}
@CacheEvict({ key: 'product:all' })
async create(data: any) {
return data;
}
}
Cron Jobs
hazel g cron cleanup
# alias: hazel g job cleanup
Generates cleanup.cron.ts with @Cron decorator from @hazeljs/cron:
import { Service } from '@hazeljs/core';
import { Cron, CronExpression } from '@hazeljs/cron';
@Service()
export class CleanupCronService {
@Cron(CronExpression.EVERY_MINUTE)
handleEveryMinute() {
console.log('[CleanupCron] Running every minute...');
}
@Cron('0 0 * * *') // Every day at midnight
handleDaily() {
console.log('[CleanupCron] Running daily task...');
}
@Cron(CronExpression.EVERY_HOUR)
handleHourly() {
console.log('[CleanupCron] Running hourly cleanup...');
}
}
RAG (Retrieval-Augmented Generation)
hazel g rag knowledge
Generates knowledge.rag.ts using @hazeljs/rag:
import { Service } from '@hazeljs/core';
import { RAGPipeline, MemoryVectorStore } from '@hazeljs/rag';
@Service()
export class KnowledgeRagService {
private pipeline: RAGPipeline;
constructor() {
const vectorStore = new MemoryVectorStore();
this.pipeline = new RAGPipeline({ vectorStore, topK: 5 });
}
async addDocument(content: string, metadata?: Record<string, unknown>) {
await this.pipeline.addDocument({ content, metadata: metadata || {} });
}
async query(question: string) {
return this.pipeline.query(question);
}
}
Service Discovery
hazel g discovery app
Generates app.discovery.ts using @hazeljs/discovery:
import { Service } from '@hazeljs/core';
import { ServiceRegistry, DiscoveryClient } from '@hazeljs/discovery';
@Service()
export class AppDiscoveryService {
constructor(
private readonly registry: ServiceRegistry,
private readonly client: DiscoveryClient,
) {}
async registerService() {
await this.registry.register({
name: 'app-service',
host: 'localhost',
port: 3000,
metadata: { version: '1.0.0' },
});
}
async discoverService(serviceName: string) {
return this.client.getInstances(serviceName);
}
}
Adding Packages
The hazel add command installs HazelJS packages and shows usage hints:
hazel add auth
This runs npm install @hazeljs/auth and prints:
Usage:
import { JwtModule } from "@hazeljs/auth";
// JwtModule.forRoot({ secret: "your-secret", expiresIn: "1d" })
Interactive mode
hazel add
Without a package name, it shows an interactive list of all available packages.
Available packages
| Short name | npm package | Usage hint |
|---|---|---|
ai | @hazeljs/ai | AIModule |
agent | @hazeljs/agent | AgentModule |
auth | @hazeljs/auth | JwtModule.forRoot() |
cache | @hazeljs/cache | CacheModule |
config | @hazeljs/config | ConfigModule.forRoot() |
cron | @hazeljs/cron | CronModule |
data | @hazeljs/data | DataModule.forRoot() |
discovery | @hazeljs/discovery | ServiceRegistry, DiscoveryClient |
event-emitter | @hazeljs/event-emitter | EventEmitterModule.forRoot() |
gateway | @hazeljs/gateway | GatewayModule |
graphql | @hazeljs/graphql | GraphQLModule |
grpc | @hazeljs/grpc | GrpcModule |
kafka | @hazeljs/kafka | KafkaModule |
messaging | @hazeljs/messaging | MessagingModule |
ml | @hazeljs/ml | MLModule.forRoot() |
mcp | @hazeljs/mcp | createMcpServer() |
pdf-to-audio | @hazeljs/pdf-to-audio | PdfToAudioModule |
prisma | @hazeljs/prisma | PrismaModule |
prompts | @hazeljs/prompts | PromptTemplate, PromptRegistry |
queue | @hazeljs/queue | QueueModule |
rag | @hazeljs/rag | RAGPipeline, RAGModule |
resilience | @hazeljs/resilience | CircuitBreaker, WithRetry, WithTimeout |
serverless | @hazeljs/serverless | createLambdaHandler |
swagger | @hazeljs/swagger | SwaggerModule |
websocket | @hazeljs/websocket | WebSocketModule |
Utility Commands
Info
Display information about the current HazelJS project:
hazel info
Build
Build the project using TypeScript:
hazel build
hazel build --watch # watch mode
Start
Start the application:
hazel start
hazel start --dev # development mode with hot-reload
Test
Run tests:
hazel test
hazel test --watch # watch mode
hazel test users # run specific test pattern
PDF to Audio
Convert PDF documents to audio via a running HazelJS app with @hazeljs/pdf-to-audio:
hazel pdf-to-audio convert document.pdf -o output.mp3 --api-url http://localhost:3000
hazel pdf-to-audio status <jobId> --api-url http://localhost:3000
The --dry-run Flag
Every generator supports --dry-run to preview what would be created without writing any files:
hazel g module users --dry-run
Output:
[dry-run] Would create /path/to/src/users/users.module.ts
[dry-run] Would create /path/to/src/users/users.controller.ts
[dry-run] Would create /path/to/src/users/users.service.ts
[dry-run] Would create /path/to/src/users/dto/create-users.dto.ts
[dry-run] Would create /path/to/src/users/dto/update-users.dto.ts
This is useful for verifying file locations before generating.
Real-World Workflows
Building a REST API
# 1. Create the project
hazel new my-api -i
# Select: config, swagger, prisma, auth
# 2. Generate the users feature
hazel g crud users
# 3. Generate the products feature
hazel g module products
hazel g repository product
# 4. Add caching
hazel add cache
hazel g cache product
# 5. Add cron jobs for cleanup
hazel add cron
hazel g cron cleanup
Building an AI Application
# 1. Create the project
hazel new ai-app -i
# Select: config, ai
# 2. Generate an AI service
hazel g ai-service chat
# 3. Add RAG for document retrieval
hazel add rag
hazel g rag knowledge
# 4. Create an AI agent
hazel add agent
hazel g agent research
Building a Real-Time Application
# 1. Create the project
hazel new realtime-app -i
# Select: config, auth, websocket
# 2. Generate auth module
hazel g auth
# 3. Generate WebSocket gateways
hazel g gateway chat
hazel g gateway notifications
Going Serverless
# 1. Create the project
hazel new serverless-api
# 2. Add serverless support
hazel add serverless
# 3. Generate the handler
hazel g serverless api --platform lambda
# or for GCP:
hazel g serverless api --platform cloud-function
Best Practices
-
Use modules to organize features — Run
hazel g module <feature>to get the full structure, then customize from there. -
Always use
--dry-runfirst — Preview what will be generated before committing to disk. -
Leverage aliases — Use
hazel g c,hazel g s,hazel g mfor speed. -
Use
-pfor organization — Place controllers in feature directories:hazel g c users -p src/users. -
Start with CRUD — For standard REST resources,
hazel g crud <name>gives you everything in one shot. -
Use interactive mode for new projects —
hazel new my-app -isets up everything correctly from the start.
What's Next?
- Learn about Controllers for building REST APIs
- Explore Modules for organizing your application
- Set up Authentication with JWT
- Add Caching for performance
- Build AI features with the AI package and Agent package