§ 038 · Postgres

Instant Strapi Performance Without Changing Your Code

How to scale your Strapi data layer using a wire compatible caching proxy and what the results look like on 43,000 real restaurants.

Strapi is an excellent tool for building content driven applications quickly. As a project grows and data becomes more interconnected, keeping the API layer snappy is a common goal for development teams. When you have deeply nested relations like a restaurant linked to locations, menus, and reviews, the database workload naturally increases.

This is a typical stage in the lifecycle of a successful application. Rather than viewing performance bottlenecks as a flaw, they are better seen as an opportunity for architectural optimization. By using a caching proxy, you can make hot queries 10 to 19 times faster at the SQL layer with a one line environment variable change.

What is Strapi

For those new to the ecosystem: Strapi is an open source headless CMS written in Node.js. It allows you to define content types in an admin UI and then auto generates REST and GraphQL APIs for you. Under the hood, it is a Koa app backed by knex. It usually runs on Postgres, MySQL, or SQLite in production, issuing standard SQL just like any other web application.

To test this at scale, we used the official FoodAdvisor example app. This app features nested relations between restaurants, categories, and reviews, making it a perfect candidate for performance testing.

Growing with Strapi

The Strapi architecture is flexible, but like any ORM based system, it can face challenges with complex data. As noted in the official documentation, using broad population can lead to many database queries. Specifically, the ORM can generate one SQL query per relation per row. A single request for a restaurant list might issue 150 or more queries to hydrate all the related fields.

Since Strapi does not have a built in database query cache, teams often look for external solutions. Common approaches include rewriting queries or manually managing Redis, but these add significant code complexity. We wanted a solution that improves performance without adding a heavy maintenance burden.

How Readyset Helps

Readyset is a wire compatible caching proxy for Postgres and MySQL. It sits between Strapi and your database. It uses logical replication to materialize the results of queries and keeps them fresh incrementally as writes stream in.

The integration is a zero code change. Strapi continues to speak Postgres; it just speaks it to Readyset instead of directly to the database. The setup is two lines in your configuration:

Why this approach works:

  • Automatic Invalidation: Readyset monitors the database replication stream.
  • Instant Refresh: When you edit content, the cache updates instantly without writing TTL logic.
  • SQL Level Caching: It caches by SQL structure (shape), not just the URL.
  • Safe Fallbacks: Writes, DDL, and transactions go straight to the main database automatically.

The Benchmark

We built a test stack with Postgres and Strapi, seeded with real data for 43,320 restaurants. We tested the specific queries that Strapi emits for a restaurant list page, which you can view in our benchmark script.

Query Type Postgres Readyset Speedup
Pagination Count 3.5 ms 0.33 ms 10x
Sorted List Page 8.6 ms 0.45 ms 19x
Place Aggregation 3.3 ms 0.33 ms 10x

Honest Caveats:

  • Point Lookups: Simple queries by ID are already very fast on Postgres (~0.3 ms) and do not see a massive boost.
  • Application Overhead: While the database layer becomes sub millisecond, the Strapi Node.js layer still handles JSON assembly and authentication. Overall HTTP response times typically see a 2 times improvement.

Try It Yourself

The full demo is open source and reproducible on any machine with Docker.

The script sets up the stack, loads the data, and prints the performance table to your terminal.

How to Reach Out

If you are scaling a Strapi project, we would love to hear from you. We want to build these tools in the open with real feedback from the community.

Written by

Vinicius Grippa

Writes this blog. Mostly about databases. Boring on purpose.

More about me →

The floor is yours.

0 comments · Moderated · civil & on-topic

First comment appears here once approved. Questions, corrections, and counterpoints welcome — just no self-promotion.

Add a comment

Your email address is never published. * required

Subscribe · Posted when ready

A quiet, technical email about databases.

One post per send, corrections when I’m wrong, nothing else. No social-media cross-posts. No “what we learned.”

Unsubscribe with any reply