Error-First Callbacks: Node.js's Original Async Handler
The error-first callback is a Node.js convention: check for rain before unpacking the picnic. The first argument to any async callback is for an error. It's the standard for older core modules like `fs`.
WHY IT EXISTS: Synchronous try...catch blocks don't work for asynchronous code. The try block finishes executing long before an async task—like a file read or database query—completes or fails. Node.js needed a consistent way to pass an error from a future point in the event loop back to the originating code's context.
THE MENTAL MODEL: Think of it as "check for rain before unpacking the picnic." Your callback function receives its arguments, and the very first thing you do is check if the first argument—the error—is present. If it is, you handle the storm and stop. If it's null, you're clear to proceed with the rest of the arguments, which contain the successful result.
HOW IT WORKS: An asynchronous function takes a callback as one of its last arguments. This callback is designed to accept at least one parameter. By convention, the first parameter is always an Error object (or null if no error occurred). Any subsequent parameters are the successful results of the operation. Your callback logic must always start with if (err) { ... handle error ... } and typically stop execution with a return.
WHEN TO USE IT: You will encounter this pattern constantly when working with older but still common Node.js core modules (like fs, crypto), many community packages on npm, and in the function signature for Express error-handling middleware. Understanding it is essential for working with much of the Node.js ecosystem.
WHEN NOT TO USE IT: For new projects, modern JavaScript with async/await and try...catch is almost always a cleaner and more readable choice. Promises and async/await were designed to solve the verbosity and "callback hell" that can arise from deeply nested error-first callbacks. Use the modern syntax unless you are interfacing with an older API that requires a callback.
ONE CANONICAL EXAMPLE: Reading a file using the built-in fs module is the classic example. fs.readFile('path/to/file.txt', 'utf8', (err, data) => { if (err) { console.error('Failed to read file:', err); return; } console.log('File contents:', data); }); If the file doesn't exist, the err object will be populated and data will be undefined. If it succeeds, err will be null.
Read the original → nodejs.org
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.