GuidesAPI Development

Code Generators

Scaffold modules, controllers, services, middleware, guards, and routes from the command line

The nextrush generate command (alias nextrush g) creates new files from templates with the correct structure, imports, and naming conventions — matching the layouts the create-nextrush scaffolds emit.

Usage

nextrush generate <type> <name>
nextrush g <type> <name>

Generator Types

Available generators

PropertyTypeDescription
module (m)stringClass-based feature module with @Module, controllers, and providers
controller (c)stringClass-based controller with @Controller, @Get, @Post, @Param, @Body, constructor DI
service (s)stringInjectable service class with @Service decorator and HttpError paths
middleware (mw)stringAsync middleware function with timing pattern
guard (g)stringGuard function with authorization token check pattern
route (r)stringFunctional router (named export) with GET, GET/:id, and POST routes

Examples

Generate a Module

nextrush g module todos

Creates src/modules/todos/todos.module.ts:

src/modules/todos/todos.module.ts
import { Module } from 'nextrush/class';

import { TodosController } from './todos.controller.js';
import { TodosService } from './todos.service.js';

@Module({
  controllers: [TodosController],
  providers: [TodosService],
})
export class TodosModule {}

A feature module composes its controller and service. Generate all three for a complete feature:

nextrush g m todos
nextrush g controller todos
nextrush g service todos

Then register the module in your root module's imports.

Generate a Controller

nextrush g controller user

In a class-based project (one with a src/modules/ directory) the controller is placed inside its feature module: src/modules/user/user.controller.ts. In a module-less project it lands at src/controllers/user.controller.ts.

src/modules/user/user.controller.ts
import { Body, Controller, Get, Param, Post } from 'nextrush/class';
import { UserService } from './user.service.js';

@Controller('/user')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Get()
  findAll() {
    return this.userService.findAll();
  }

  @Get('/:id')
  findOne(@Param('id') id: string) {
    return this.userService.findOne(id);
  }

  @Post()
  create(@Body() data: unknown) {
    return this.userService.create(data);
  }
}

Generate a Service

nextrush g service user

Creates src/modules/user/user.service.ts in a module project, or src/services/user.service.ts otherwise:

src/modules/user/user.service.ts
import { HttpError } from 'nextrush';
import { Service } from 'nextrush/class';

@Service()
export class UserService {
  findAll() {
    return [];
  }

  findOne(id: string) {
    if (!id) throw new HttpError(404, 'Not found');
    return { id };
  }

  create(data: unknown) {
    if (!data || typeof data !== 'object') throw new HttpError(400, 'Invalid input');
    return data;
  }
}

Generate Middleware

nextrush g middleware request-logger

Creates src/middleware/request-logger.ts:

src/middleware/request-logger.ts
import type { Middleware } from 'nextrush';

export const requestLogger: Middleware = async (ctx) => {
  const start = Date.now();
  await ctx.next();
  const duration = Date.now() - start;
  console.log(`${ctx.method} ${ctx.path} ${ctx.status} ${duration}ms`);
};

Generate a Guard

nextrush g guard auth

Creates src/guards/auth.guard.ts:

src/guards/auth.guard.ts
import type { GuardFn } from 'nextrush/class';

export const authGuard: GuardFn = async (ctx) => {
  const token = ctx.get('authorization');
  if (!token) return false;
  // TODO: Validate token
  return true;
};

Generate a Route

nextrush g route product

Creates src/routes/product.ts — a named-export router, matching the functional template's mounting idiom (import { productRouter } from './routes/product.js' + app.route('/product', productRouter)):

src/routes/product.ts
import { createRouter } from 'nextrush';

export const productRouter = createRouter();

productRouter.get('/', (ctx) => {
  ctx.json([]);
});

productRouter.get('/:id', (ctx) => {
  ctx.json({ id: ctx.params.id });
});

productRouter.post('/', (ctx) => {
  ctx.status = 201;
  ctx.json(ctx.body);
});

Output Directories

TypeDefault DirectoryModule project (src/modules/ exists)File Suffix
modulesrc/modules/<name>/src/modules/<name>/.module.ts
controllersrc/controllers/src/modules/<name>/.controller.ts
servicesrc/services/src/modules/<name>/.service.ts
middlewaresrc/middleware/src/middleware/.ts
guardsrc/guards/src/guards/.guard.ts
routesrc/routes/src/routes/.ts

In a class-based project (one with a src/modules/ directory), controllers and services co-locate inside their feature module so the module, controller, service, and tests live together. In module-less (functional/full) projects they use the flat directories above. Directories are created automatically if they don't exist.

Naming Convention

Names must be lowercase with optional hyphens. The generator converts them to PascalCase for class names and camelCase for function names:

InputClass NameFunction Name
userUserControlleruser
user-profileUserProfileControlleruserProfile
authAuthControllerauthGuard

Wiring generated files

Generators create files; they do not edit existing source. Add generated modules to your root module's imports, mount generated routes with app.route(...), and register guards/middleware where they apply.

Existing Files

The generator will not overwrite existing files. If the target file already exists, the command exits with an error.

What's Next?

Was this helpful?

On this page