Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To query a database with callbacks in Node.js, use the callback API provided by your database driver. This example uses node-postgres (pg) with PostgreSQL: pass a callback as the final argument, check its error first, then use the result. Node.js does not provide one universal callback-based database API.

Run a PostgreSQL query with a callback

For a single query, node-postgres recommends using a connection pool’s query method. The callback receives an error and a result:

const { Pool } = require('pg');
const pool = new Pool();

pool.query('SELECT name FROM users WHERE id = $1', [userId], (err, result) => {
  if (err) {
    console.error('Query failed:', err);
    return;
  }

  console.log(result.rows);
});

Configure the pool for your environment separately; do not put database credentials directly in application code. In this example, $1 is a value placeholder, and [userId] supplies its value. The callback handles failure before reading result.rows, and return prevents success code from running after an error.

Pass values safely instead of building SQL strings

Use parameterized queries for user-controlled values. With node-postgres, query text and values are sent separately, allowing the server to substitute the parameter safely. See the node-postgres query documentation.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
pool.query(
  'SELECT name FROM users WHERE id = $1',
  [userId],
  (err, result) => {
    if (err) return console.error('Query failed:', err);
    console.log(result.rows);
  }
);

Do not interpolate input into SQL, for example with a template string containing userId. Parameters are for values, not SQL identifiers such as table or column names; dynamic identifiers require separate safe handling.

Choose between a pool query and a checked-out client

Pattern Use it for Client lifecycle
pool.query A single query. The pool manages the connection for the operation; there is no checked-out client for your code to release.
pool.connect Multiple related queries or a transaction that must use the same client. Your code must release the checked-out client when its work ends, including after an error.

The pool API’s callback supplies an error, a client, and a release function. Make cleanup explicit. This example executes two queries in sequence and releases the client after the callback work, whether either query fails or succeeds:

pool.connect((connectErr, client, release) => {
  if (connectErr) {
    console.error('Could not acquire a client:', connectErr);
    return;
  }

  client.query('BEGIN', (beginErr) => {
    if (beginErr) {
      release();
      console.error('Could not begin transaction:', beginErr);
      return;
    }

    client.query(
      'UPDATE accounts SET balance = balance - $1 WHERE id = $2',
      [amount, accountId],
      (queryErr, result) => {
        if (queryErr) {
          client.query('ROLLBACK', () => {
            release();
            console.error('Update failed:', queryErr);
          });
          return;
        }

        client.query('COMMIT', (commitErr) => {
          release();
          if (commitErr) {
            console.error('Could not commit transaction:', commitErr);
            return;
          }
          console.log('Updated rows:', result.rowCount);
        });
      }
    );
  });
});

Every path after successful acquisition calls release(), so the client is returned to the pool rather than left unavailable to other work. For more complex transaction error handling, follow the driver’s guidance and ensure rollback and release paths account for errors as well.

Keep callback work brief

A database callback does not make JavaScript work inside it nonblocking. The callback body runs synchronously on the Event Loop, so CPU-heavy loops or large synchronous transformations can delay other requests. Node.js advises: “You should make sure you never block the Event Loop.” Keep callback work short or bound expensive processing.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Callbacks are driver-specific; Node.js SQLite is different

The PostgreSQL method names above apply to node-postgres, not automatically to MySQL, MongoDB, or another database. Check the current documentation for the driver you use. node-postgres supports callbacks as well as promises, and its callback guide describes async/await as the preferred modern Node.js style.

Do not treat Node.js’s built-in node:sqlite API as an asynchronous callback-query example: its documented DatabaseSync methods run synchronously. The Node.js documentation identifies the module as a release candidate and says it was added in Node.js v22.5.0; check the current SQLite documentation for its status and API details.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.