Building Type-Safe APIs with Nuxt 3 and Prisma
Learn how to build end-to-end type-safe APIs using Nuxt 3 server routes and Prisma ORM for a seamless developer experience.
Go beyond console.log. Master the Node.js debugger, memory profiling, async stack traces, and production debugging techniques.
Mbeah Essilfie
April 30, 2026 at 06:04 AM
Console.log debugging works, but it's slow and messy. Professional debugging tools save hours.
# Start with debugger attached
node --inspect server.js
# Break on first line
node --inspect-brk server.js
Then open chrome://inspect in Chrome, or use VS Code's debugger.
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Nuxt",
"type": "node",
"request": "launch",
"command": "pnpm dev",
"cwd": "${workspaceFolder}",
"console": "integratedTerminal",
"serverReadyAction": {
"pattern": "Local:.*?(https?://\\S+)",
"uriFormat": "%s",
"action": "debugWithChrome"
}
}
]
}
In VS Code, right-click the gutter → "Conditional Breakpoint":
// Only break when userId matches
userId === "abc-123"
// Only break on the 50th iteration
i === 49
// Only break when error occurs
error !== null
# Enable long async stack traces
node --async-stack-traces server.js
// Or in code
Error.stackTraceLimit = 50 // Default is 10
# Generate a heap snapshot
node --inspect server.js
# Then in Chrome DevTools: Memory tab → Take Heap Snapshot
Common leak sources:
// Quick leak detector
function trackMemory(label: string) {
const usage = process.memoryUsage()
console.log(`[${label}] Heap: ${Math.round(usage.heapUsed / 1024 / 1024)}MB`)
}
setInterval(() => trackMemory('periodic'), 10000)
# CPU profile for 5 seconds
node --prof server.js
# Process the output
node --prof-process isolate-*.log > profile.txt
Or use the built-in profiler:
import { performance, PerformanceObserver } from 'node:perf_hooks'
performance.mark('start-db')
const users = await db.user.findMany()
performance.mark('end-db')
performance.measure('db-query', 'start-db', 'end-db')
const obs = new PerformanceObserver((items) => {
items.getEntries().forEach((entry) => {
console.log(`${entry.name}: ${entry.duration.toFixed(2)}ms`)
})
})
obs.observe({ entryTypes: ['measure'] })
When you can't attach a debugger:
// 1. Structured logging with request IDs
function createRequestLogger(requestId: string) {
return {
info: (msg: string, data?: unknown) =>
console.log(JSON.stringify({ requestId, level: 'info', msg, data })),
error: (msg: string, error?: Error) =>
console.error(JSON.stringify({ requestId, level: 'error', msg, stack: error?.stack })),
}
}
// 2. Debug endpoint (protected!)
app.get('/debug/health', requireAdmin, (req, res) => {
res.json({
uptime: process.uptime(),
memory: process.memoryUsage(),
cpu: process.cpuUsage(),
connections: server.connections,
})
})
debugger statement for quick breakpointsconsole.table() for arrays of objectsconsole.trace() for quick stack tracesconsole.time() / console.timeEnd() for timingutil.inspect(obj, { depth: null }) for deep objectsThe fastest path to fixing a bug is understanding how to reproduce it and inspect the state at the right moment.
Fullstack Software Developer
Learn how to build end-to-end type-safe APIs using Nuxt 3 server routes and Prisma ORM for a seamless developer experience.
Go beyond basic utility classes and learn how to build cohesive, maintainable design systems with Tailwind CSS.
Understand the power of Vue 3's Composition API through practical, real-world composable patterns that you can use today.
