What are callback functions?

JavaScript

The short answer

A callback function is a function that you pass as an argument to another function. The receiving function then calls (or "calls back") your function at the right time. Callbacks are one of the fundamental patterns for handling asynchronous operations in JavaScript.

How it works

Here is the simplest example:

function greet(name) {
console.log(`Hello, ${name}!`);
}
function processUser(callback) {
const name = 'John';
callback(name);
}
processUser(greet); // "Hello, John!"

We pass the greet function into processUser. Inside processUser, it calls greet when it is ready. That is all a callback is — a function passed to another function to be called later.

Callbacks in everyday code

You use callbacks all the time without realizing it:

Array methods:

const numbers = [1, 2, 3, 4, 5];
numbers.forEach((num) => console.log(num));
numbers.filter((num) => num > 3);
numbers.map((num) => num * 2);

The arrow functions you pass to forEach, filter, and map are all callbacks.

Event listeners:

button.addEventListener('click', () => {
console.log('Button clicked!');
});

The function you pass to addEventListener is a callback. The browser calls it when the user clicks the button.

setTimeout:

setTimeout(() => {
console.log('This runs after 2 seconds');
}, 2000);

The function runs after the timer finishes. You gave JavaScript a function and said "call this back when the time is up."

Synchronous vs asynchronous callbacks

Callbacks can be either synchronous (run immediately) or asynchronous (run later).

Synchronous callbacks run right away:

const numbers = [1, 2, 3];
numbers.forEach((num) => {
console.log(num); // runs immediately for each item
});
console.log('Done');
// 1, 2, 3, "Done"

Asynchronous callbacks run later:

console.log('Start');
setTimeout(() => {
console.log('Timeout'); // runs later
}, 0);
console.log('End');
// "Start", "End", "Timeout"

Even with a 0ms delay, the callback runs after the current code finishes because it goes through the event loop.

The error-first pattern

In Node.js, there is a common pattern where the first argument of a callback is always the error:

function readFile(path, callback) {
const fileExists = path === '/data.txt';
if (!fileExists) {
callback(new Error('File not found'), null);
return;
}
callback(null, 'file contents');
}
readFile('/missing.txt', (error, data) => {
if (error) {
console.log('Error:', error.message); // "File not found"
return;
}
console.log('Data:', data);
});
readFile('/data.txt', (error, data) => {
if (error) {
console.log('Error:', error.message);
return;
}
console.log('Data:', data); // "file contents"
});

This is called the "error-first callback" pattern. You always check for the error first before using the data.

The problem with callbacks — callback hell

When you need multiple async operations in sequence, callbacks get nested:

getUser(userId, (user) => {
getOrders(user.id, (orders) => {
getOrderDetails(orders[0], (details) => {
getShipping(details.shippingId, (shipping) => {
console.log(shipping);
});
});
});
});

This deep nesting is called "callback hell" or the "pyramid of doom." It is hard to read, hard to debug, and hard to handle errors across all levels. This is why promises and async/await were introduced — they solve this nesting problem.

Interview Tip

When explaining callbacks, start with a simple synchronous example (like array methods) before moving to asynchronous ones (like setTimeout or API calls). If the interviewer asks about the downsides, mention callback hell and explain that promises and async/await were introduced to solve that problem. This shows you understand the evolution of async JavaScript.

Why interviewers ask this

Callbacks are the building block of asynchronous JavaScript. Even though we mostly use promises and async/await now, callbacks are still everywhere — in event listeners, array methods, and third-party libraries. Interviewers want to see if you understand this fundamental pattern, can tell the difference between sync and async callbacks, and know when to use callbacks vs promises.