
Introduction
Strapi load testing is essential if your CMS powers customer-facing websites, e-commerce storefronts, mobile apps, or headless content APIs. Strapi is popular because it gives teams a flexible way to manage content and expose it through REST or GraphQL APIs, but that flexibility can also create performance challenges when traffic spikes.
If your Strapi instance serves product catalogs, landing pages, blog content, or localized marketing content, slow API responses can quickly become a business problem. A content backend that performs well at low traffic may struggle under concurrent reads, authenticated admin actions, media-heavy responses, or complex filtered queries. That’s why load testing, performance testing, and stress testing your Strapi APIs should be part of your deployment process.
In this guide, you’ll learn how to use LoadForge to performance test Strapi with realistic Locust scripts. We’ll cover basic public content endpoints, authenticated API requests, content creation workflows, and heavier e-commerce CMS scenarios. Along the way, we’ll show how LoadForge’s distributed testing, real-time reporting, cloud-based infrastructure, and CI/CD integration can help you validate that your Strapi environment scales reliably.
Prerequisites
Before you begin load testing Strapi, make sure you have:
- A running Strapi application, either self-hosted or deployed in the cloud
- API endpoints exposed through Strapi REST APIs
- At least one public content type, such as
articles,products, orcategories - A test user account for authenticated requests
- Optional seeded data so your tests hit realistic content volumes
- Permission settings configured in Strapi for public and authenticated roles
- A LoadForge account to run distributed load tests at scale
It also helps to know which version of Strapi you’re running. Modern Strapi APIs often use endpoint patterns like:
GET /api/articlesGET /api/products?populate=*POST /api/auth/localPOST /api/ordersGET /api/categories?filters[slug][$eq]=electronics
For performance testing, use a staging or pre-production environment whenever possible. Running stress testing against production can impact editors, customers, and downstream systems like databases, search clusters, and CDNs.
Understanding Strapi Under Load
Strapi is typically used as a headless CMS, meaning frontend applications rely on it for structured content delivery. Under load, Strapi performance depends on several layers:
- Strapi application server performance
- Database performance, often PostgreSQL or MySQL
- Query complexity from filters, sorting, and population
- Authentication overhead with JWT-based login flows
- Media and relation population costs
- Caching behavior in front of Strapi
- Infrastructure scaling, such as containers, CPU, memory, and connection pooling
Common Strapi bottlenecks
When load testing Strapi, the most common bottlenecks include:
Overuse of populate=*
This is convenient during development, but expensive at scale. Deeply nested relations can dramatically increase response times and database load.
Expensive filters and sorting
Queries like filters[category][slug][$eq]=electronics&sort=publishedAt:desc can become slow if your database indexes are missing or poorly designed.
Authentication bursts
If many users log in simultaneously using /api/auth/local, JWT generation and user lookup can become a hotspot.
Admin-like write traffic
Content creation, updates, and order submissions create heavier database load than read-only CMS traffic.
Large payload responses
Product listings, article feeds, and homepage content with multiple nested relations can produce large JSON responses that increase latency and bandwidth usage.
Media-heavy content delivery
Even if media files are served from object storage or a CDN, Strapi may still spend time resolving media metadata and relationships.
A good Strapi load testing strategy should include both read-heavy and write-heavy scenarios, because real-world traffic often mixes public browsing with authenticated actions.
Writing Your First Load Test
Let’s start with a simple load test for public Strapi content endpoints. This is the most common first step in performance testing a CMS-backed application.
Imagine your Strapi app powers a storefront and blog with these public endpoints:
GET /api/articles?pagination[page]=1&pagination[pageSize]=10&sort=publishedAt:descGET /api/products?pagination[page]=1&pagination[pageSize]=12&populate=thumbnailGET /api/categories
This basic Locust script simulates anonymous users browsing public content.
from locust import HttpUser, task, between
class StrapiPublicApiUser(HttpUser):
wait_time = between(1, 3)
@task(3)
def list_articles(self):
self.client.get(
"/api/articles?pagination[page]=1&pagination[pageSize]=10&sort=publishedAt:desc",
name="/api/articles [list]"
)
@task(5)
def list_products(self):
self.client.get(
"/api/products?pagination[page]=1&pagination[pageSize]=12&populate=thumbnail",
name="/api/products [catalog]"
)
@task(2)
def list_categories(self):
self.client.get(
"/api/categories",
name="/api/categories"
)What this test does
This script models a simple anonymous browsing pattern:
- Product listing is weighted highest because catalog pages are often the busiest
- Article listing is moderately frequent
- Category listing is lower frequency
Why this matters for Strapi
This test helps you answer basic performance testing questions:
- Can Strapi serve public content quickly under concurrent traffic?
- Are list endpoints fast enough for frontend page rendering?
- Does response time degrade as user count increases?
- Is the database handling repeated listing queries efficiently?
In LoadForge, you can run this script with hundreds or thousands of concurrent users using cloud-based infrastructure and global test locations. That makes it easy to simulate regional traffic bursts without provisioning your own load generators.
Advanced Load Testing Scenarios
A realistic Strapi load test should go beyond simple GET requests. Below are more advanced scenarios that reflect how Strapi is used in production.
Authenticated Strapi API Testing
Many Strapi deployments expose protected endpoints for customer dashboards, partner portals, or internal apps. In this scenario, users log in through Strapi’s local auth endpoint and then retrieve account-specific data.
from locust import HttpUser, task, between
import random
class StrapiAuthenticatedUser(HttpUser):
wait_time = between(1, 2)
credentials = [
{"identifier": "buyer1@example.com", "password": "TestPassword123!"},
{"identifier": "buyer2@example.com", "password": "TestPassword123!"},
{"identifier": "editor1@example.com", "password": "TestPassword123!"},
]
def on_start(self):
user = random.choice(self.credentials)
response = self.client.post(
"/api/auth/local",
json={
"identifier": user["identifier"],
"password": user["password"]
},
name="/api/auth/local [login]"
)
if response.status_code == 200:
data = response.json()
self.token = data["jwt"]
self.headers = {
"Authorization": f"Bearer {self.token}"
}
else:
self.token = None
self.headers = {}
@task(4)
def get_profile(self):
if self.token:
self.client.get(
"/api/users/me?populate=role",
headers=self.headers,
name="/api/users/me"
)
@task(3)
def get_saved_orders(self):
if self.token:
self.client.get(
"/api/orders?filters[user][email][$eq]=buyer1@example.com&populate[items][populate]=product",
headers=self.headers,
name="/api/orders [user orders]"
)
@task(2)
def get_wishlist(self):
if self.token:
self.client.get(
"/api/wishlists?populate[products][populate]=thumbnail",
headers=self.headers,
name="/api/wishlists"
)What this scenario tests
This script measures:
- Login performance through
/api/auth/local - JWT-authenticated request handling
- Protected content retrieval
- Relation-heavy queries using
populate
Why it’s realistic
Many Strapi-backed e-commerce and CMS applications use authenticated APIs for:
- Customer accounts
- Order history
- Wishlist data
- Editorial dashboards
- Membership content
If authentication is slow, users feel it immediately. If protected relation-heavy endpoints are inefficient, account pages may become unusable during traffic spikes.
Load testing tip
For larger tests, use a bigger credential pool and avoid hardcoding a single user filter in order requests. In LoadForge, you can parameterize user data and run distributed performance testing against login flows from multiple regions.
Testing Product Detail, Search, and Filter Queries
Strapi often powers product catalogs where frontend apps request filtered, sorted, and populated content. These are some of the most important endpoints to load test because they closely affect conversion rates.
from locust import HttpUser, task, between
import random
class StrapiCatalogUser(HttpUser):
wait_time = between(2, 5)
product_slugs = [
"wireless-mechanical-keyboard",
"gaming-mouse-pro",
"usb-c-docking-station",
"4k-monitor-27-inch"
]
category_slugs = [
"keyboards",
"mice",
"monitors",
"accessories"
]
@task(4)
def browse_category(self):
slug = random.choice(self.category_slugs)
self.client.get(
f"/api/products?filters[category][slug][$eq]={slug}&pagination[page]=1&pagination[pageSize]=24&sort=publishedAt:desc&populate=thumbnail",
name="/api/products [category filter]"
)
@task(3)
def view_product_detail(self):
slug = random.choice(self.product_slugs)
self.client.get(
f"/api/products?filters[slug][$eq]={slug}&populate[thumbnail]=true&populate[gallery]=true&populate[category]=true&populate[seo]=true",
name="/api/products [detail by slug]"
)
@task(2)
def featured_products(self):
self.client.get(
"/api/products?filters[featured][$eq]=true&pagination[pageSize]=8&populate=thumbnail&sort=updatedAt:desc",
name="/api/products [featured]"
)
@task(1)
def homepage_content(self):
self.client.get(
"/api/homepage?populate[heroBanners][populate]=image&populate[featuredCategories][populate]=icon&populate[seo]=true",
name="/api/homepage"
)Why this matters
This scenario tests the kinds of API calls that drive:
- Product listing pages
- Product detail pages
- Featured product modules
- Dynamic homepage content
These endpoints are often more expensive than they first appear because they combine:
- Filters
- Sorting
- Pagination
- Nested population
- SEO metadata
- Media references
If your Strapi APIs are used by a Next.js, Nuxt, React, or mobile frontend, these are exactly the requests you should include in load testing.
Testing Content Creation or Order Submission Workflows
Strapi isn’t just for reading content. Many teams use it for transactional or semi-transactional use cases such as contact forms, quote requests, bookings, or lightweight order capture. Writes are especially important to stress test because they place direct pressure on the database.
In this example, we simulate authenticated users submitting orders to a Strapi collection type.
from locust import HttpUser, task, between
import random
import uuid
class StrapiOrderSubmissionUser(HttpUser):
wait_time = between(3, 6)
def on_start(self):
response = self.client.post(
"/api/auth/local",
json={
"identifier": "buyer1@example.com",
"password": "TestPassword123!"
},
name="/api/auth/local [login]"
)
if response.status_code == 200:
self.token = response.json()["jwt"]
self.headers = {
"Authorization": f"Bearer {self.token}",
"Content-Type": "application/json"
}
else:
self.token = None
self.headers = {}
@task
def create_order(self):
if not self.token:
return
order_number = f"ORD-{uuid.uuid4().hex[:10].upper()}"
payload = {
"data": {
"orderNumber": order_number,
"status": "pending",
"currency": "USD",
"subtotal": 249.98,
"shippingCost": 12.99,
"taxAmount": 21.25,
"totalAmount": 284.22,
"customerEmail": "buyer1@example.com",
"shippingAddress": {
"firstName": "Ava",
"lastName": "Turner",
"line1": "145 Market Street",
"city": "San Francisco",
"state": "CA",
"postalCode": "94105",
"country": "US"
},
"items": [
{
"productSku": "KB-1001",
"productName": "Wireless Mechanical Keyboard",
"quantity": 1,
"unitPrice": 129.99
},
{
"productSku": "MS-2003",
"productName": "Gaming Mouse Pro",
"quantity": 1,
"unitPrice": 119.99
}
],
"paymentMethod": "card"
}
}
with self.client.post(
"/api/orders",
json=payload,
headers=self.headers,
name="/api/orders [create]",
catch_response=True
) as response:
if response.status_code in (200, 201):
response.success()
else:
response.failure(f"Unexpected status code: {response.status_code}")
@task(2)
def list_recent_orders(self):
if self.token:
self.client.get(
"/api/orders?sort=createdAt:desc&pagination[pageSize]=5",
headers=self.headers,
name="/api/orders [recent]"
)What this scenario reveals
This test is useful for identifying:
- Database write latency
- Validation bottlenecks
- Slow lifecycle hooks
- Webhook side effects
- Lock contention under concurrent writes
If your Strapi project uses custom controllers, lifecycle hooks, or integrations with payment, ERP, or email systems, write-heavy performance testing is especially valuable.
Analyzing Your Results
After running your Strapi load test in LoadForge, focus on a few key metrics.
Response time percentiles
Average response time is useful, but percentiles tell the real story. Pay close attention to:
- P50 for typical user experience
- P95 for degraded but still common requests
- P99 for worst-case latency under load
For Strapi APIs, a low average can hide serious spikes on filtered or populated endpoints.
Requests per second
This helps you understand throughput. Compare endpoint throughput against infrastructure limits and business expectations. For example:
- Can your catalog endpoints handle traffic from a flash sale?
- Can homepage content APIs support a major campaign launch?
- Can authenticated account APIs handle login surges?
Error rate
Look for:
- 401 or 403 errors from auth misconfiguration
- 429 errors if rate limiting is enabled
- 500 errors from application crashes or database issues
- 502 or 504 errors from reverse proxies or upstream timeouts
Endpoint-level breakdown
In LoadForge’s real-time reporting, review endpoint names you set in Locust, such as:
/api/products [catalog]/api/auth/local [login]/api/orders [create]
This makes it easier to pinpoint which Strapi workflows degrade first.
Response size and payload complexity
If endpoints with deep populate options are much slower than simpler requests, that’s a strong sign to reduce response complexity or redesign your content model.
Ramp-up behavior
A Strapi environment may perform well at 50 users and fail at 300. Use LoadForge’s distributed testing and cloud-based infrastructure to ramp traffic gradually and identify the point where latency or error rates begin to climb.
Performance Optimization Tips
Once load testing reveals bottlenecks, these optimizations often help Strapi scale better.
Reduce unnecessary population
Avoid populate=* in production APIs unless absolutely necessary. Request only the fields and relations your frontend actually needs.
Add database indexes
If you frequently filter by fields like:
slugpublishedAtcategoryfeaturedemail
make sure those columns are indexed appropriately in your database.
Paginate aggressively
Do not return huge datasets in a single request. Use pagination for article lists, product catalogs, and category pages.
Cache public content
For public CMS content, use caching layers such as a CDN, reverse proxy, or application cache where appropriate. This is especially effective for homepage and product listing endpoints.
Optimize media delivery
Serve images and static assets from object storage or a CDN instead of routing them inefficiently through your app stack.
Review custom logic
Custom controllers, lifecycle hooks, and plugins can introduce hidden latency. If write endpoints are slow during stress testing, inspect every downstream operation.
Scale infrastructure horizontally
If your Strapi deployment is containerized, horizontal scaling may improve concurrency handling, especially when combined with proper database tuning and connection pooling.
Test continuously
Integrate performance testing into CI/CD so regressions are caught before release. LoadForge supports CI/CD integration, making it easier to validate Strapi performance as schemas, plugins, and frontend traffic patterns evolve.
Common Pitfalls to Avoid
Strapi load testing can produce misleading results if the test design is unrealistic. Avoid these common mistakes.
Testing only public GET endpoints
Strapi applications often include authenticated APIs, admin workflows, and writes. If you only test public reads, you may miss critical bottlenecks.
Using unrealistic payloads
A minimal JSON body may pass, but real users create richer content and more complex requests. Use realistic order, article, or form submission payloads.
Ignoring relation-heavy queries
Endpoints with nested population are often much slower than basic list requests. Include them in your performance testing plan.
Not seeding enough content
A Strapi endpoint with 10 products behaves very differently than one with 100,000 products. Test against realistic data volume.
Reusing one account for all traffic
If every virtual user logs in as the same account, you may create artificial caching or locking behavior. Use a pool of test users where possible.
Forgetting downstream dependencies
Strapi performance can be affected by:
- Database servers
- Search services
- Object storage
- Email providers
- Webhooks
- Reverse proxies
A slow integration may surface as a Strapi API slowdown.
Running a single-user script and calling it load testing
True load testing requires concurrency, ramp-up, sustained traffic, and endpoint mix. LoadForge makes this easier by letting you run large-scale distributed tests from global test locations with real-time reporting.
Conclusion
Strapi is a powerful headless CMS for e-commerce and content-driven applications, but its performance under load depends heavily on your content model, query patterns, authentication flow, and infrastructure. By load testing Strapi APIs with realistic Locust scripts, you can uncover slow endpoints, validate scaling behavior, and prevent CMS bottlenecks from impacting users.
Start with public content endpoints, then expand into authenticated requests, filtered catalog queries, and write-heavy workflows like order submission. Use LoadForge to run distributed load testing at scale, analyze response times in real time, and integrate performance testing into your CI/CD pipeline.
If you want to make sure your Strapi backend is ready for real-world traffic, try LoadForge and start building performance tests that reflect how your application actually works.
LoadForge Team
LoadForge is a load and performance testing platform built on Locust. Our team has been shipping load tests against production systems since 2018, and we write these guides from real customer engagements.
Related guides
Keep going with more guides from the same category.

Contentful Load Testing: How to Load Test Contentful APIs with LoadForge
Learn how to load test Contentful APIs with LoadForge to measure content delivery performance and handle traffic surges.

Ghost Load Testing: Performance Testing Ghost CMS with LoadForge
Learn how to load test Ghost CMS with LoadForge to benchmark publishing performance and keep content delivery fast under load.

Magento Load Testing: Performance Testing Magento Stores with LoadForge
Run Magento load tests with LoadForge to identify slow pages, optimize checkout flows, and validate store performance at scale.