billgil (@billgil) header
billgil (@billgil) profile picture

Point your agent ay my profile. Vibe like a pro. A big fan of coding, digital freedom and pizza

Belfast, Ireland
Joined March 2010
Photo by billgil (@billgil)Photo by billgil (@billgil)Photo by billgil (@billgil)Photo by billgil (@billgil)Photo by billgil (@billgil)Photo by billgil (@billgil)Photo by billgil (@billgil)Photo by billgil (@billgil)Photo by billgil (@billgil)Photo by billgil (@billgil)
The NestJS stuff teams still skip: - Standard Schema (Zod etc.) on @Body/@Query (v12) - @nestjs/observe for framework-aware traces - Dynamic modules + custom providers - Reflector + custom metadata decorators - Fastify adapter for lower latency - BullMQ + CacheInterceptor - Hybrid HTTP + microservice apps - Vitest + oxlint defaults on new ESM projects Ship one of these this week. Stop writing everything in the controller. #NestJS #WebDev
47
Retro gamer tribute, built with HTML & CSS
35,985
NestJS 12: native observability. import { ObserveModule } from '@nestjs/observe' ObserveModule.forRoot({ apiKey: process.env.OBSERVE_KEY }) Hooks into Nest lifecycle (controllers, providers, jobs) instead of only patching the HTTP server. Traces know about your modules. #NestJS #WebDev
55
NestJS 12: Standard Schema validation on route decorators. @Post() create(@Body({ schema: createUserSchema }) body: CreateUser) { return this.users.create(body) } Zod, Valibot, ArkType work directly once the pipe is registered. class-validator still fine; this removes the wrapper packages. #NestJS #WebDev
1
1
92
Queues with BullMQ keep heavy work off the request. @Processor('emails') export class EmailProcessor { @Process('welcome') async handle(job: Job) { await this.mailer.send(job.data) } } Inject the queue and add jobs from a service. Workers run in the same process or separate. #NestJS #WebDev
36
Custom parameter decorators extract what you need. export const User = createParamDecorator( (data: unknown, ctx: ExecutionContext) => { return ctx.switchToHttp().getRequest().user } ) @Get() me(@User() user: UserEntity) { return user } Stops repeating req.user extraction. Pair with a guard that attaches the user. #NestJS #WebDev
1
65
Queues with BullMQ keep heavy work off the request. @Processor('emails') export class EmailProcessor { @Process('welcome') async handle(job: Job) { await this.mailer.send(job.data) } } Inject the queue and add jobs from a service. Workers run in the same process or separate. #NestJS #WebDev
55
Exception filters turn errors into HTTP responses. @Catch(HttpException) export class HttpExceptionFilter implements ExceptionFilter { catch(exception: HttpException, host: ArgumentsHost) { const ctx = host.switchToHttp() const res = ctx.getResponse() res.status(exception.getStatus()).json(exception.getResponse()) } } Global or per-route. Keep domain errors mapped consistently. #NestJS #WebDev
44
Man @StarWarsOutlaws is the game I didn't know I needed my whole life. Its like Fallout in space with all the weird Star Wars aliens you know and love. This is my life now 😂 10/10 I'm a thieving, double crossing, space pirate with a bounty on my head 😎
69
CacheModule + CacheInterceptor for free speed. @UseInterceptors(CacheInterceptor) @CacheTTL(30) @Get() findAll() { return this.users.findAll() } Redis store for multi-instance. @CacheKey when the default key is wrong. Invalidate on writes. #NestJS #WebDev
62
Interceptors wrap the method call. @Injectable() export class LoggingInterceptor implements NestInterceptor { intercept(ctx: ExecutionContext, next: CallHandler) { const now = Date.now() return next.handle().pipe( tap(() => console.log(`done in ${Date.now() - now}ms`)) ) } } Use for logging, caching, response mapping. RxJS operators give you the result stream. #NestJS #WebDev
48
Testing is first-class. const module = await Test.createTestingModule({ controllers: [UsersController], providers: [{ provide: UsersService, useValue: mockService }], }).compile() const app = module.createNestApplication() await app.init() Override providers with mocks. Supertest for HTTP. Vitest is the new default in Nest 12 ESM projects. #NestJS #WebDev
39
Guards decide if a request may continue. @Injectable() export class AuthGuard implements CanActivate { canActivate(ctx: ExecutionContext): boolean { const req = ctx.switchToHttp().getRequest() return !!req.user } } @UseGuards(AuthGuard) on routes or controllers. Reflector reads metadata for role checks. #NestJS #WebDev
49
Middleware runs early, like Express. export function logger(req, res, next) { console.log(req.method, req.url) next() } Apply with consumer.apply(logger).forRoutes('*') in a module. Prefer guards/interceptors unless you need raw req/res before Nest routing. #NestJS #WebDev
56
Pipes transform and validate. @Post() create(@Body(ValidationPipe) dto: CreateUserDto) { return this.users.create(dto) } Global ValidationPipe + class-validator DTOs catch bad input early. whitelist: true strips extra fields. #NestJS #WebDev
1
68
Services hold the business logic. Controllers stay thin. @Injectable() export class UsersService { constructor(private readonly db: DatabaseService) {} async findOne(id: string) { return this.db.user.find(id) } } @Inject the dependencies. No direct HTTP knowledge inside the service. #NestJS #WebDev
1
70
DTOs + class-validator keep input honest. export class CreateUserDto { @IsEmail() email: string @MinLength(8) password: string } ValidationPipe on the controller or globally. transform: true turns plain objects into class instances. #NestJS #WebDev
1
61
Modules group related code. @Module({ imports: [DatabaseModule], controllers: [UsersController], providers: [UsersService], exports: [UsersService], }) export class UsersModule {} imports = other modules you need. exports = what you share. The root AppModule wires everything. #NestJS #WebDev
1
1
100
Providers are the injectable units. @Injectable() export class UsersService { findAll() { return [] } } Register in the module providers array. Nest creates and injects them. Tokens can be classes, strings, or symbols. #NestJS #WebDev
45
Controllers are the HTTP entry point. @Controller('users') export class UsersController { @Get(':id') findOne(@Param('id') id: string) { return { id } } } Routes live on methods. @Param, @Query, @Body extract data. One controller per resource keeps it scannable. #NestJS #WebDev
68