Strapi version:
5.x (latest)
Node.js version:
20.x
Package manager:
yarn 4.12.0
Problem:
server/index.ts
mounts the admin panel, content API, upload handler,
cron jobs, and webhook runner all on one Koa app in one OS process.
There is no built-in mechanism to run multiple worker processes
(Node.js cluster mode). This means:
  1. You can only scale the entire Strapi process — you cannot scale
just the Content API under traffic while leaving the admin panel
on a single instance.
  1. Running multiple instances externally (via pm2 or Kubernetes replicas)
causes cron jobs to fire on every instance simultaneously, producing
race conditions and duplicate side-effects (duplicate emails, duplicate
webhook calls). See also: #15634.
  1. The cron service (
    cron.ts
    ) uses
    node-schedule
    with no leader-
election or instance awareness — every instance runs every cron task.
What the code does today:
In
packages/core/core/src/services/server/index.ts
,
createServer()
builds one Koa app with both
createAdminAPI(strapi)
and
createContentAPI(strapi)
on the same process and same port.
In
packages/core/core/src/services/cron.ts
,
createCronService()
schedules jobs unconditionally with no check for whether this process
is the designated primary.
Proposed solution (monolith fix, no microservices required):
Add opt-in built-in cluster support:
  1. A
    server.cluster.enabled
    config flag (default: false).
  2. When enabled, Strapi's entry point forks N worker processes using
Node.js
cluster
module (default:
os.cpus().length
).
  1. A
    STRAPI_INSTANCE_TYPE
    environment variable (
    primary
    /
    worker
    )
lets services guard singleton behaviour:
- Cron jobs only run on the primary process.
- Webhook runner only runs on the primary process.
- Database migrations only run on the primary process.
  1. Workers handle all HTTP traffic (load-balanced by the OS).
Related issues:
  • #3976 (cluster mode question, closed 2019, no code change made)
  • #15634 (cron race condition, open/stale, no PR merged)
I plan to submit a PR implementing this.
reproduce:
  1. Deploy two Strapi v5 instances pointing to the same database
(e.g. two pm2 instances or two Kubernetes pods).
  1. Configure a cron task in
    config/cron-tasks.ts
    that sends an email
or writes a unique log entry.
  1. Wait for the cron schedule to fire.
  2. Observe: the cron task executes on BOTH instances simultaneously,
producing duplicate emails or duplicate log entries.
For the scaling limitation:
  1. Monitor CPU usage on a single Strapi instance under load.
  2. Attempt to scale only the content API (e.g. by running a second
instance that only serves
/api/*
routes).
  1. Observe: impossible without running a full second Strapi process,
which doubles the cron, webhook, and admin overhead unnecessarily.
#Expected behavior
When
server.cluster.enabled: true
is set in config:
  1. Strapi should fork N worker processes automatically.
  2. Only the primary process should run cron jobs and webhook delivery.
  3. All workers should handle HTTP requests, load-balanced by the OS.
  4. Database migrations should run once on the primary before workers start.
  5. The behaviour should be identical to the current single-process mode
when
cluster.enabled
is false (default), so there is zero breaking
change for existing deployments.