Have you ever noticed your web app getting slower the more data it displays? The hidden culprit is often a sneaky database performance issue called the N+1 query problem.

  • What an N+1 query actually is under the hood
  • Why this common issue slows down your web application
  • How to spot N+1 queries in your server logs
  • How to fix the problem using eager loading

What is an N+1 query problem?

An N+1 query happens when your code asks the database for a list of items, and then makes a separate database trip for every single item to fetch its details. If you have 100 users, your app might make 1 database query to get the users, and then 100 more queries to get each user's profile. That is 101 total queries for a single page load, which bogs down your database.

Here is a classic example of backend code written in JavaScript that triggers the N+1 problem:

async function getPostsWithAuthors() {
  // 1 query to get all posts
  const posts = await db.query('SELECT * FROM posts');
  
  for (let post of posts) {
    // N queries: 1 for each post to get the author
    post.author = await db.query('SELECT * FROM authors WHERE id = ?', [post.author_id]);
  }
  
  return posts;
}

The key takeaway is that running database queries inside a loop is a major performance bottleneck that will crash your app under heavy traffic.

Render development Photo by Growtika on Unsplash

How to fix N+1 queries with eager loading

The solution to this problem is called eager loading. Instead of fetching data piece by piece in a loop, you ask the database for everything you need in one single query using a SQL JOIN.

Here is how you fix the previous example by grabbing all the required data upfront:

async function getPostsWithAuthorsFixed() {
  // 1 single query using a JOIN to get posts and authors together
  const posts = await db.query(`
    SELECT posts.*, authors.name as author_name 
    FROM posts 
    JOIN authors ON posts.author_id = authors.id
  `);
  
  return posts;
}

The key takeaway here is replacing multiple loop queries with a single JOIN query, which drops your database load down from hundreds of queries to just one.

Common mistakes to watch out for

Many developers think N+1 queries only happen in massive enterprise applications, but they frequently pop up in simple loops or nested component renders. Another common mistake is relying blindly on Object-Relational Mappings (ORMs) like Prisma or Sequelize without checking the actual SQL queries being generated in your development logs. Always keep your browser network tab and database query logs open while building features.

Open up an existing project today, look at a page that lists related items, and check your terminal logs to see if you are accidentally running queries inside a loop.