Best database for Node.js

For most Node.js projects, PostgreSQL with the pg driver is the safest choice. Use MongoDB for documents with a varying shape, Redis for caching and queues, and SQLite for single-process apps.

Updated 6 min read

Learning objectives

After reading this article you will be able to:

  • Apply practical criteria to pick the database for a Node.js project
  • Know the drivers and pitfalls of PostgreSQL, MySQL, MongoDB, Redis and SQLite in Node.js
  • Choose the right database for a bot, API or site, with a recommendation per scenario
On this page

Node.js works well with practically any database. Every popular database has a maintained driver on npm, and all of them work with Promises and async/await. So the question "what is the best database for Node.js" has less to do with Node and more to do with your project: the shape of your data, the guarantees you need and how many processes will access the database.

This guide compares the five most common options in the ecosystem (PostgreSQL, MySQL, MongoDB, Redis and SQLite) from the point of view of someone writing JavaScript. For each one you get the driver, an example and the pitfalls that show up in daily use.

Your Node.jsappPromises andasync/awaitbetter-sqlite3SQLitelocal file,one processnetworkpgPostgreSQLrelations, transactionsmysql2MySQLlegacy PHP systemsmongodbMongoDBvarying documentsredisRediscache and queues
Every popular database has an npm driver: the shape of your data and how many processes connect decide, not Node.

Which criteria matter?#

Five criteria settle almost every case:

  1. Data shape. Users, orders and inventories that relate to each other call for a relational database. Settings and profiles whose fields vary from item to item fit documents.
  2. Transactions. If two writes must happen together or not at all (debit one balance and credit another), prefer a database with mature transactions.
  3. Access pattern. Reading by exact key in milliseconds, such as a session or a cooldown, is a job for Redis. Reports that join tables are a job for SQL.
  4. How many processes connect. A single process can use a local file (SQLite). Several processes, several applications or replicas need a database server reached over the network.
  5. Driver quality. All five databases in this guide have mature drivers on npm. This criterion weighs more for less popular databases.

If you are still choosing a database in general, without a Node.js focus, see which database to choose.

PostgreSQL with Node.js#

PostgreSQL is relational, has full transactions, extensions and the jsonb type, which stores JSON with index support. That lets you mix fixed columns with a flexible field in the same table, which covers many of the cases where someone would pick a document database.

The most widely used driver is pg (node-postgres). Its docs recommend creating a single pool for the application and using pool.query whenever you can, because the driver then returns the connection to the pool for you:

js
// npm install pg
import pg from "pg";

// One pool for the whole application, created once
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });

export async function findUser(email) {
  // $1 is a parameter: the driver sends the value separately, no SQL injection risk
  const { rows } = await pool.query(
    "SELECT id, name, created_at FROM users WHERE email = $1",
    [email],
  );
  return rows[0] ?? null;
}

export async function countUsers() {
  const { rows } = await pool.query("SELECT count(*) AS total FROM users");
  return Number(rows[0].total); // count(*) is int8 and arrives as a string
}

Pros: transactions and integrity, jsonb for flexible data, json/jsonb columns arrive as JavaScript objects and dates arrive as Date.

Cons and pitfalls: the driver returns int8 (including the result of count(*)) as a string, because a 64-bit integer can exceed the safe range of Number. Opening a new Client on every request instead of using the pool exhausts the server's connections; if that has already happened, see the "too many connections" error.

MySQL with Node.js#

MySQL is also relational, very popular with hosting providers and in the PHP ecosystem, with plenty of tutorials and tools. In Node.js, the most widely used driver is mysql2, which has a Promise API (mysql2/promise), connection pools and prepared statements.

Pros: familiar if you come from PHP or shared hosting, transactions with the InnoDB engine, broad ORM support.

Cons: fewer advanced types than PostgreSQL, and some behavior differences between versions and SQL modes. For a new project with no constraints, the practical difference is usually small. The detailed comparison is in PostgreSQL vs MySQL.

MongoDB with Node.js#

MongoDB stores JSON-like documents in collections, with no required schema. In Node.js a document arrives as a JavaScript object, which makes the first contact very comfortable. The official driver is the mongodb package; Mongoose is a popular layer on top of it that adds schemas and validation.

js
// npm install mongodb
import { MongoClient } from "mongodb";

// The client keeps an internal pool: create one and reuse it
const client = new MongoClient(process.env.MONGODB_URI);
const configs = client.db("mybot").collection("configs");

// Saves or updates the settings of a Discord server
export async function saveConfig(guildId, config) {
  await configs.updateOne({ guildId }, { $set: config }, { upsert: true });
}

export async function readConfig(guildId) {
  return configs.findOne({ guildId });
}

Pros: great when you read and write the whole object at once (per-server settings in a bot, profiles with optional fields, catalogs whose items have different attributes). Changing the shape does not require a migration.

Cons: without a schema, validation is on you (in code, in Mongoose or in database rules). Relations and multi-document transactions exist, but they cost more than in a relational database. The step-by-step connection guide is in how to connect MongoDB to Node.js.

Redis with Node.js#

Redis keeps data in memory, accessed by key, and answers very fast. It is rarely the only database: its classic role is to be the second one, next to PostgreSQL or MongoDB, for caching, sessions, queues, counters and request limits. The official npm client is the redis package (node-redis):

js
// npm install redis
import { createClient } from "redis";

const redis = await createClient({ url: process.env.REDIS_URL })
  .on("error", (err) => console.error("Redis error", err))
  .connect();

// 10-second cooldown per user: NX only writes if the key does not exist yet
export async function onCooldown(userId) {
  const result = await redis.set(`cooldown:${userId}`, "1", {
    expiration: { type: "EX", value: 10 },
    condition: "NX",
  });
  return result === null; // null = the key already existed
}

Pros: very low latency, automatic key expiry, ready-made structures (lists, sets, hashes).

Cons: data has to fit in memory, and anything not yet persisted can be lost in a crash. Do not use it as the main store for data you cannot lose. More in what is Redis.

What about SQLite?#

SQLite is a whole database inside a file, with no server. Node.js has two routes: the widely used better-sqlite3 package, and the built-in node:sqlite module, included in recent Node versions (check the docs for your version to see its stability level).

Pros: zero setup, great for prototypes, scripts, command-line tools and small single-process bots.

Cons: one writer at a time, and the file lives on that machine's disk. If you run several replicas, or another service needs to read the same data, move to a client-server database.

Which database for each scenario?#

Scenario Recommendation Driver
REST API with users, orders and payments PostgreSQL pg
Site or system migrating from legacy PHP MySQL mysql2
Discord bot with economy, levels and inventory PostgreSQL pg
Bot with per-server settings and optional fields MongoDB or PostgreSQL with jsonb mongodb or pg
Cache, sessions, queues, rate limits, cooldowns Redis, next to the main database redis
Prototype, CLI or single-process app SQLite better-sqlite3 or node:sqlite

When in doubt, start with PostgreSQL. If you already use TypeScript and want types generated from your schema, an ORM such as Prisma or Drizzle on top of PostgreSQL or MySQL is a good addition, but not a requirement. Once you have chosen, the next step is to host the Node.js app and the database in the same place to keep latency low.

How to do this on Square Cloud#

Square Cloud offers MongoDB, PostgreSQL, MySQL and Redis hosting from the Standard plan (Hobby does not include databases). You create the database in the dashboard, picking a name, memory and engine, and it is provisioned in seconds in the same datacenter as your applications, with an average latency of about 1 ms between them.

In practice: copy the full connection URL the dashboard hands you (it is shown once at creation; resetting the password shows it again) into an environment variable of your Node.js application, such as DATABASE_URL or MONGODB_URI. Download the certificate: TLS is mandatory, the driver must trust the downloaded CA and, on PostgreSQL and MongoDB, also present the .pem certificate. On Redis, the URL uses rediss://. Keep one pool for the whole process, since each database accepts up to 512 connections and there is no pooler in front.

PostgreSQL is native PostgreSQL, without extensions, and Redis has persistence. You take manual snapshots whenever you want, and every plan that includes databases also has an automatic daily snapshot. A snapshot can be restored into the same database, another one of the same engine or a new database, or downloaded as a .zip. See the options on Databases.

Database hosting

MongoDB, PostgreSQL, MySQL and Redis next to your app

Learn more

FAQs

What is the best database for Node.js?

There is no single best one, but PostgreSQL fits most projects: it is relational, has transactions, stores JSON with the jsonb type and the pg driver is mature. MongoDB is the alternative when your data is documents with a varying shape.

Is MongoDB a better match for Node.js because it uses JSON?

MongoDB documents become JavaScript objects with no conversion, which is comfortable. But PostgreSQL jsonb columns also come back as objects in the pg driver. Choose by the shape of your data and your need for transactions, not by the language.

Do I need an ORM to use a database in Node.js?

No. The official drivers (pg, mysql2, mongodb, redis) are enough and teach you what happens underneath. ORMs such as Prisma and Drizzle help with types and migrations, and Mongoose plays a similar role for MongoDB.

Why does PostgreSQL's count(*) arrive as a string in Node.js?

Because count(*) returns int8, a 64-bit integer, and the pg driver returns int8 as a string so it does not lose precision beyond JavaScript's safe integer limit. Convert it with Number() when you know the value is small.

Next articleBest database for PythonPostgreSQL is the safest choice for most Python projects, and SQLite is enough for scripts and small apps. See when MySQL, MongoDB or Redis make more sense.

More in Databases

See all 24 articles