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

Belfast, Ireland
Joined March 2010
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 馃槑
12
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
47
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
39
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
33
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
45
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
51
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
65
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
69
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
57
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
99
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
44
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
67
The Next.js 16 stuff teams still skip: - cacheComponents + 'use cache' - cacheLife / cacheTag / updateTag - Suspense holes for PPR - Server Actions instead of form route handlers - await params and searchParams - proxy.ts instead of middleware.ts - forbidden() / unauthorized() - next/font + Image priority on the LCP - after() for non-blocking work - generateMetadata Ship one of these this week. Stop wrapping a fetch in useEffect. #NextJS #WebDev
1
1
83
Parallel routes are slots, not nested pages you hope will line up. app/@modal/(.)photo/[id]/page.tsx app/@feed/page.tsx app/layout.tsx // receives { modal, feed, children } default.tsx is required or a hard refresh 404s the slot. Intercepting routes (.) keep the list mounted while the photo opens as a modal. #NextJS #WebDev
1
49
generateStaticParams is the static set, not a cache hint. export async function generateStaticParams() { const posts = await db.post.listSlugs() return posts.map((p) => ({ slug: p.slug })) } Build knows those URLs. Unknown slugs can still render dynamically. Empty array means "do not prerender this segment." #NextJS #WebDev
1
58
connection() opts a subtree into request time. On purpose. import { connection } from 'next/server' export async function Personalized() { await connection() const session = await cookies() return <p>{session.get('uid')?.value}</p> } Calling cookies() or headers() already does this. connection() is the explicit version when the dynamic bit is not a request API. Do not sprinkle it on the layout. #NextJS #WebDev
1
40
after() is the work that should not block the response. import { after } from 'next/server' export async function POST(request: Request) { const payload = await request.json() after(() => logEvent(payload)) return Response.json({ ok: true }) } Analytics, audit rows, email enqueue. The client already has the answer. Do not await the side effect on the critical path. #NextJS #WebDev
1
55
Link prefetches the route. prefetch={false} when the list is huge. import Link from 'next/link' <Link href={`/blog/${slug}`} prefetch={false}>{title}</Link> Default prefetch on viewport is why the dashboard feels instant and why a 200-row table hammers the server. Turn it off on low-intent links. #NextJS #WebDev
1
2
60
proxy.ts replaced middleware.ts. // proxy.ts export function proxy(request: NextRequest) { const token = request.cookies.get('session') if (!token) return NextResponse.redirect(new URL('/login', request.url)) return NextResponse.next() } Auth gate and rewrites live here. Do not fetch your database in the proxy. Check a cookie, then do the work in the server component. #NextJS #WebDev
2
48
forbidden() and unauthorized() are the status, not a redirect to /login disguised as a 200. import { forbidden, unauthorized } from 'next/navigation' if (!session) unauthorized() if (!session.isAdmin) forbidden() Pair with unauthorized.tsx and forbidden.tsx. A redirect() to the login page is navigation. These are HTTP. #NextJS #WebDev
2
61