HazelJS CLI

npm downloads

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 suffix property, so files are consistently named (name.controller.ts, name.service.ts, name.guard.ts, etc.)
  • Shared utilitiestoPascalCase, toKebabCase, toCamelCase, and renderTemplate live in one place and are used by all generators
  • --dry-run support — 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 proper HazelApp bootstrap
  • src/app.module.ts — root module with @HazelModule decorator
  • src/hello.controller.ts — example controller
  • package.json — dependencies, scripts (build, start, dev, test, lint, format), ESLint devDependencies
  • tsconfig.json — TypeScript config with decorators, strict mode, and rootDir: ./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:

  1. Description — project description for package.json
  2. Author — your name
  3. License — Apache-2.0 (default), MIT, GPL-3.0, BSD-3-Clause, or ISC
  4. Packages — select additional HazelJS packages to install

When you select packages in interactive mode, the CLI automatically:

  • Installs the npm packages
  • Updates app.module.ts with the correct imports and module registration
  • Creates .env and .env.example files when Config is selected
  • Sets up Swagger integration in index.ts when Swagger is selected

Available packages in interactive mode

PackageWhat gets scaffolded
@hazeljs/aiAIModule in app module
@hazeljs/agentAgentModule in app module
@hazeljs/authJwtModule.forRoot() in app module
@hazeljs/cacheCacheModule in app module
@hazeljs/configConfigModule.forRoot() + .env files
@hazeljs/cronCronModule in app module
@hazeljs/dataDataModule.forRoot() in app module
@hazeljs/discoveryInstalled — use ServiceRegistry/DiscoveryClient programmatically
@hazeljs/event-emitterEventEmitterModule.forRoot() in app module
@hazeljs/gatewayGatewayModule in app module
@hazeljs/graphqlGraphQLModule in app module
@hazeljs/grpcGrpcModule in app module
@hazeljs/kafkaKafkaModule in app module
@hazeljs/messagingMessagingModule in app module
@hazeljs/mlMLModule.forRoot() in app module
@hazeljs/mcpInstalled — use createMcpServer() for Model Context Protocol
@hazeljs/pdf-to-audioPdfToAudioModule in app module
@hazeljs/promptsInstalled — use PromptTemplate, PromptRegistry for typed prompts
@hazeljs/prismaPrismaModule in app module
@hazeljs/queueQueueModule in app module
@hazeljs/ragRAGModule in app module
@hazeljs/resilienceInstalled — use CircuitBreaker, WithRetry decorators in services
@hazeljs/serverlessInstalled — use createLambdaHandler in handler files
@hazeljs/swaggerSwaggerModule + updated index.ts with Swagger setup
@hazeljs/websocketWebSocketModule in app module

Options

FlagDescription
-d, --dest <path>Destination directory (default: .)
--skip-installSkip running npm install
--skip-gitSkip git init
-i, --interactiveInteractive 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

CommandAliasCreates
hazel g controller <name>cname.controller.ts
hazel g service <name>sname.service.ts
hazel g module <name>mModule + controller + service + DTOs
hazel g dto <name>dname.dto.ts + update-name.dto.ts
hazel g guard <name>guname.guard.ts
hazel g interceptor <name>iname.interceptor.ts
hazel g middleware <name>mwname.middleware.ts
hazel g filter <name>fname.filter.ts
hazel g pipe <name>name.pipe.ts
hazel g crud <name>Full CRUD resource
hazel g authAuth module + JWT guard + DTOs
hazel g gateway <name>wsname.gateway.ts
hazel g repository <name>reponame.repository.ts
hazel g ai-service <name>ainame.ai-service.ts
hazel g agent <name>name.agent.ts
hazel g serverless <name>slsname.handler.ts
hazel g configapp.config.ts
hazel g cache <name>name.cache.ts
hazel g cron <name>jobname.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/:

FileDescription
users.module.tsModule with @HazelModule decorator
users.controller.tsController with @Controller
users.service.tsService with @Injectable
dto/create-users.dto.tsCreate DTO
dto/update-users.dto.tsUpdate 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/:

FileDescription
product.controller.tsFull CRUD controller (GET, POST, PUT, DELETE)
product.service.tsService with all CRUD operations
dto/product.dto.tsCreate and Update DTOs with class-validator
product.module.tsModule 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/:

FileDescription
auth.module.tsAuth module with providers and exports
auth.service.tsService with register() and login() methods
auth.controller.tsController with POST /auth/register and /auth/login
jwt-auth.guard.tsJWT Bearer token guard using @hazeljs/auth
dto/register.dto.tsRegister DTO with email, name, password validation
dto/login.dto.tsLogin DTO with email, password validation

After generating, follow the next steps printed by the CLI:

  1. Import AuthModule in your app module
  2. Configure JwtModule.forRoot({ secret: "your-secret", expiresIn: "1d" })
  3. Install bcryptjs: npm install bcryptjs @types/bcryptjs
  4. 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 namenpm packageUsage hint
ai@hazeljs/aiAIModule
agent@hazeljs/agentAgentModule
auth@hazeljs/authJwtModule.forRoot()
cache@hazeljs/cacheCacheModule
config@hazeljs/configConfigModule.forRoot()
cron@hazeljs/cronCronModule
data@hazeljs/dataDataModule.forRoot()
discovery@hazeljs/discoveryServiceRegistry, DiscoveryClient
event-emitter@hazeljs/event-emitterEventEmitterModule.forRoot()
gateway@hazeljs/gatewayGatewayModule
graphql@hazeljs/graphqlGraphQLModule
grpc@hazeljs/grpcGrpcModule
kafka@hazeljs/kafkaKafkaModule
messaging@hazeljs/messagingMessagingModule
ml@hazeljs/mlMLModule.forRoot()
mcp@hazeljs/mcpcreateMcpServer()
pdf-to-audio@hazeljs/pdf-to-audioPdfToAudioModule
prisma@hazeljs/prismaPrismaModule
prompts@hazeljs/promptsPromptTemplate, PromptRegistry
queue@hazeljs/queueQueueModule
rag@hazeljs/ragRAGPipeline, RAGModule
resilience@hazeljs/resilienceCircuitBreaker, WithRetry, WithTimeout
serverless@hazeljs/serverlesscreateLambdaHandler
swagger@hazeljs/swaggerSwaggerModule
websocket@hazeljs/websocketWebSocketModule

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

  1. Use modules to organize features — Run hazel g module <feature> to get the full structure, then customize from there.

  2. Always use --dry-run first — Preview what will be generated before committing to disk.

  3. Leverage aliases — Use hazel g c, hazel g s, hazel g m for speed.

  4. Use -p for organization — Place controllers in feature directories: hazel g c users -p src/users.

  5. Start with CRUD — For standard REST resources, hazel g crud <name> gives you everything in one shot.

  6. Use interactive mode for new projectshazel new my-app -i sets up everything correctly from the start.

What's Next?