# Nodejs Patterns

> When to activate: Node.js, Express, Fastify, streams, EventEmitter, child_process, cluster, worker_threads, HTTP server

- Skill: `mattakushi432/nodejs-patterns` (Agent Skill)
- Install (CLI): `npx skillmds@latest add mattakushi432/nodejs-patterns`
- Raw SKILL.md: https://api.skillmd.com/api/skills/mattakushi432/nodejs-patterns/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Mattakushi432 (https://skillmd.com/u/mattakushi432)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/mattakushi432/nodejs-patterns

---


# Node.js Patterns

## Fastify (preferred over Express for new services)
```ts
import Fastify from 'fastify'

const app = Fastify({ logger: true })

// Plugin — encapsulated scope
app.register(async (instance) => {
  instance.get('/users', async (request, reply) => {
    const users = await db.user.findMany()
    return users  // Fastify auto-serializes
  })

  instance.post('/users', {
    schema: {
      body: {
        type: 'object',
        required: ['email', 'name'],
        properties: {
          email: { type: 'string', format: 'email' },
          name:  { type: 'string', minLength: 1 },
        },
      },
    },
    handler: async (request, reply) => {
      const user = await db.user.create({ data: request.body as any })
      reply.code(201)
      return user
    },
  })
}, { prefix: '/api/v1' })

await app.listen({ port: 3000, host: '0.0.0.0' })
```

## Express with TypeScript
```ts
import express, { Request, Response, NextFunction } from 'express'

const app = express()
app.use(express.json())

// Typed request handler
interface CreateUserBody { email: string; name: string }

app.post('/users', async (
  req: Request<{}, {}, CreateUserBody>,
  res: Response,
  next: NextFunction
) => {
  try {
    const user = await db.user.create({ data: req.body })
    res.status(201).json(user)
  } catch (err) {
    next(err)
  }
})

// Error middleware (4 args — must match signature)
app.use((err: Error, req: Request, res: Response, _next: NextFunction) => {
  console.error(err)
  res.status(500).json({ error: err.message })
})
```

## Streams
```ts
import { pipeline } from 'node:stream/promises'
import { createReadStream, createWriteStream } from 'node:fs'
import { createGzip } from 'node:zlib'

// Safe pipeline (auto-cleans up on error)
await pipeline(
  createReadStream('input.log'),
  createGzip(),
  createWriteStream('input.log.gz')
)

// Transform stream
import { Transform } from 'node:stream'

const upper = new Transform({
  transform(chunk, _enc, callback) {
    callback(null, chunk.toString().toUpperCase())
  },
})
```

## EventEmitter
```ts
import { EventEmitter } from 'node:events'

interface Events {
  data:  (payload: { id: string }) => void
  error: (err: Error) => void
  drain: () => void
}

class Queue extends EventEmitter {
  declare emit: <K extends keyof Events>(event: K, ...args: Parameters<Events[K]>) => boolean
  declare on:   <K extends keyof Events>(event: K, listener: Events[K]) => this

  push(item: { id: string }) {
    this.emit('data', item)
  }
}
```

## Worker Threads
```ts
import { Worker, isMainThread, parentPort, workerData } from 'node:worker_threads'

if (isMainThread) {
  const worker = new Worker(__filename, { workerData: { input: [1, 2, 3] } })
  worker.on('message', (result) => console.log('Result:', result))
  worker.on('error', console.error)
} else {
  const result = (workerData.input as number[]).map(x => x * 2)
  parentPort!.postMessage(result)
}
```

## Cluster for CPU-bound scaling
```ts
import cluster from 'node:cluster'
import os from 'node:os'

if (cluster.isPrimary) {
  const cpus = os.availableParallelism()
  for (let i = 0; i < cpus; i++) cluster.fork()
  cluster.on('exit', (worker) => {
    console.warn(`Worker ${worker.process.pid} died, restarting`)
    cluster.fork()
  })
} else {
  // Start your HTTP server here — each worker listens on the same port
  startServer()
}
```

## Graceful Shutdown
```ts
async function shutdown(signal: string) {
  console.log(`Received ${signal}, shutting down...`)
  server.close(async () => {
    await db.$disconnect()
    process.exit(0)
  })
  // Force exit after 10s
  setTimeout(() => process.exit(1), 10_000).unref()
}

process.on('SIGTERM', () => shutdown('SIGTERM'))
process.on('SIGINT',  () => shutdown('SIGINT'))
```

## Environment Config
```ts
import { z } from 'zod'

const envSchema = z.object({
  NODE_ENV:     z.enum(['development', 'test', 'production']),
  PORT:         z.coerce.number().default(3000),
  DATABASE_URL: z.string().url(),
  JWT_SECRET:   z.string().min(32),
})

export const env = envSchema.parse(process.env)
// Crashes at startup with a clear error if required vars are missing
```

## HTTP Client (native fetch / undici)
```ts
// Node 18+: global fetch is available
const res = await fetch('https://api.example.com/data', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
  body: JSON.stringify(payload),
  signal: AbortSignal.timeout(5000),
})

if (!res.ok) throw new Error(`HTTP ${res.status}: ${await res.text()}`)
const data = await res.json()
```

## File System (async)
```ts
import { readFile, writeFile, mkdir, rm } from 'node:fs/promises'
import { join } from 'node:path'

const content = await readFile(join(__dirname, 'data.json'), 'utf8')
const parsed  = JSON.parse(content)
await writeFile('output.json', JSON.stringify(parsed, null, 2))
await mkdir('uploads', { recursive: true })
await rm('tmp', { recursive: true, force: true })
```

