How to Implement Connection Pooling in Node.js
This article explains how to implement connection pooling in a Node.js application to optimize database performance and manage concurrent connections efficiently. You will learn the core concepts of connection pooling, why it is vital for scaling backends, and how to set it up step-by-step using popular database drivers for PostgreSQL and MySQL.
What is Connection Pooling?
Opening and closing a new database connection for every single HTTP request is computationally expensive and introduces significant latency. Connection pooling solves this issue by maintaining a cache of active database connections (a “pool”) that are kept open.
When your Node.js backend needs to query the database, it temporarily borrows an idle connection from the pool. Once the query is complete, the connection is returned to the pool for another request to reuse, rather than being destroyed. This drastically reduces connection overhead and protects your database from being overwhelmed by too many simultaneous connections.
Implementing
Connection Pooling with PostgreSQL (pg)
The standard PostgreSQL client for Node.js, pg, has
built-in support for connection pooling via the Pool
class.
First, install the package:
npm install pgNext, configure and export the pool in a database configuration file
(e.g., db.js):
const { Pool } = require('pg');
// Create a new pool instance
const pool = new Pool({
host: 'localhost',
user: 'database_user',
password: 'your_password',
database: 'my_database',
port: 5432,
// Pooling settings
max: 20, // Maximum number of clients in the pool
idleTimeoutMillis: 30000, // Close idle clients after 30 seconds
connectionTimeoutMillis: 2000, // Return an error if a connection takes longer than 2 seconds
});
// Export a query method to use throughout the application
module.exports = {
query: (text, params) => pool.query(text, params),
};You can now import and use this pool in your route handlers:
const db = require('./db');
async function getUser(req, res) {
try {
const { rows } = await db.query('SELECT * FROM users WHERE id = $1', [req.params.id]);
res.json(rows[0]);
} catch (err) {
console.error(err);
res.status(500).send('Database Error');
}
}Implementing
Connection Pooling with MySQL (mysql2)
If you are using MySQL, the mysql2 package provides a
highly performant implementation of connection pooling.
First, install the package:
npm install mysql2Configure the pool in your database module:
const mysql = require('mysql2/promise');
// Create the connection pool
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
database: 'test_db',
password: 'your_password',
waitForConnections: true,
connectionLimit: 10, // Max number of concurrent connections
queueLimit: 0 // Unlimited queued requests when pool is full
});
module.exports = pool;Using the promise-based MySQL pool in your application:
const pool = require('./db');
async function getProducts(req, res) {
try {
const [rows] = await pool.query('SELECT * FROM products');
res.json(rows);
} catch (err) {
console.error(err);
res.status(500).send('Database Error');
}
}Key Configuration Best Practices
To get the most out of your connection pool, consider the following settings:
- Pool Size (
maxorconnectionLimit): Do not set this number arbitrarily high. It should be determined by your database server’s capacity and the number of application instances running. If you have 5 application servers and your database can handle 100 connections, set each pool max to20. - Idle Timeout: Configures how long a connection can sit unused in the pool before being closed. This helps release resources during low-traffic periods.
- Error Handling: Always listen to error events on the pool itself. If a connection dies in the background, the pool needs to handle the destruction of that client gracefully.