How to Fix: Static worker unexpectedly exited with code: null and signal: SIGTERM while building in Jenkins
How to Fix “Static worker unexpectedly exited with code: null and signal: SIGTERM” During Next.js Builds in Jenkins
This error usually means your Next.js build worker did not crash because of bad application code first—it was terminated from the outside while generating static pages. In Jenkins, that commonly points to memory pressure, container limits, process timeouts, or CI-specific environment constraints that kill the worker before next build finishes.
The issue was reported in the Next.js tracker and is reproducible for some teams specifically in Jenkins rather than on local machines. You can review the original report on GitHub.
Understanding the Root Cause
The key clue is this part of the error: signal: SIGTERM. A process that exits with code: null and a termination signal was usually not allowed to fail naturally. It was told to stop by the operating system, the container runtime, Jenkins, or a parent process.
During next build, Next.js may spawn static generation workers to pre-render pages. In Jenkins, those workers can be terminated when one of the following happens:
- Out-of-memory conditions: the JVM for Jenkins, Node.js, and other parallel jobs compete for RAM. When memory gets tight, the environment may terminate worker processes.
- Docker or Kubernetes resource limits: if Jenkins agents run inside containers, the container may hit memory or CPU limits before the host itself does.
- Jenkins pipeline timeouts or agent shutdowns: a pipeline step, shell wrapper, or ephemeral agent may stop child processes with SIGTERM.
- Too many pages being statically generated at once: large builds with expensive
getStaticProps, image processing, MDX transforms, or API fetches can amplify memory use. - Node.js heap configuration mismatch: Node may have a lower effective heap ceiling in CI than expected, especially across Node versions or containerized agents.
In short, this is rarely just a random Next.js bug. It is usually a build environment stability issue exposed by how Next.js parallelizes static work.
Step-by-Step Solution
The most reliable fix is to reduce build pressure and make Jenkins resource limits explicit.
1) Confirm the process is being killed by the environment
Start by collecting more detail in Jenkins. Print Node version, memory settings, and cgroup/container limits if applicable.
node -v
npm -v
printenv | sort
cat /proc/meminfo || true
cat /sys/fs/cgroup/memory.max || true
cat /sys/fs/cgroup/memory/memory.limit_in_bytes || true
If the build dies without a JavaScript stack trace and consistently shows SIGTERM, that strongly suggests an external termination.
2) Increase Node memory for the build
Set NODE_OPTIONS so the build has a larger heap. This is one of the most effective mitigations in Jenkins.
export NODE_OPTIONS="--max-old-space-size=4096"
npm ci
npm run build
In a Jenkins Pipeline:
pipeline {
agent any
environment {
NODE_OPTIONS = '--max-old-space-size=4096'
}
stages {
stage('Build') {
steps {
sh 'node -v'
sh 'npm ci'
sh 'npm run build'
}
}
}
}
If your Jenkins agent has less than 4 GB available, use a smaller value like 2048. The correct value must fit the actual agent or container limit.
3) Check Jenkins agent and container memory limits
If Jenkins runs builds inside Docker, Kubernetes, or ephemeral cloud agents, verify the resource ceiling. Increasing NODE_OPTIONS alone will not help if the container itself is capped too low.
docker inspect <container-id> | grep -i memory
For Kubernetes-based Jenkins agents, review the pod template resources and increase both requests and limits if the current values are too low.
resources:
requests:
memory: "2Gi"
cpu: "1000m"
limits:
memory: "4Gi"
cpu: "2000m"
If your build includes many static pages, 2 GiB is often not enough.
4) Reduce build-time work in getStaticProps and page generation
If you are doing heavy data fetching, large JSON transforms, markdown compilation, syntax highlighting, image processing, or loading huge datasets during static generation, optimize that logic.
Typical improvements:
- Fetch only required fields.
- Cache expensive remote API responses.
- Precompute content outside the build when possible.
- Avoid loading entire datasets in memory at once.
- Split very large page-generation jobs into smaller inputs.
Example optimization pattern:
export async function getStaticProps() {
const res = await fetch(process.env.API_URL + '/posts?fields=id,title,slug')
const posts = await res.json()
return {
props: {
posts
},
revalidate: 60
}
}
If your static build is generating thousands of pages, consider whether some routes should use Incremental Static Regeneration instead of fully rendering everything during CI.
5) Avoid unnecessary parallel workload in the Jenkins job
On shared agents, a Next.js build may compete with test runners, Docker builds, browsers, or other pipelines. If possible:
- Run
next buildin its own stage. - Disable unnecessary parallel stages on the same node.
- Use a dedicated build agent for large frontend builds.
Example pipeline separation:
pipeline {
agent any
environment {
NODE_OPTIONS = '--max-old-space-size=4096'
}
stages {
stage('Install') {
steps {
sh 'npm ci'
}
}
stage('Build Next.js') {
steps {
sh 'npm run build'
}
}
stage('Test') {
steps {
sh 'npm test'
}
}
}
}
6) Disable CI wrappers that may terminate child processes early
Some Jenkins shell wrappers, timeout blocks, or agent cleanup behaviors can send SIGTERM to child processes. Review pipeline configuration for:
timeout(...)steps that are too aggressive- agent shutdown or workspace cleanup during long builds
- custom wrappers that kill child processes after log inactivity
If a timeout is the cause, increase it:
timeout(time: 30, unit: 'MINUTES') {
sh 'npm run build'
}
7) Align Node.js and Next.js versions between local and Jenkins
If the issue only happens in Jenkins, compare versions first. Differences in Node.js, package manager behavior, native dependencies, or libc can change memory usage and worker behavior.
node -v
npm ls next
npm ls react
npm ls react-dom
Use the same Node version locally and in CI, ideally through .nvmrc, Volta, or a pinned Docker image.
{
"engines": {
"node": ">=18.17.0"
}
}
8) Test the build with resource diagnostics enabled
To validate the fix, rerun the build while logging memory usage before and after the Next.js build step.
free -h || true
node -e "console.log(process.memoryUsage())"
npm run build
node -e "console.log(process.memoryUsage())"
free -h || true
If the build becomes stable after increasing memory or reducing static generation work, you have confirmed the root cause.
9) Practical Jenkinsfile example
This example combines the most common fixes into one reproducible setup:
pipeline {
agent any
environment {
NODE_OPTIONS = '--max-old-space-size=4096'
CI = 'true'
}
options {
timeout(time: 30, unit: 'MINUTES')
}
stages {
stage('Environment') {
steps {
sh 'node -v'
sh 'npm -v'
sh 'free -h || true'
sh 'cat /proc/meminfo | head || true'
}
}
stage('Install') {
steps {
sh 'npm ci'
}
}
stage('Build') {
steps {
sh 'npm run build'
}
}
}
}
Common Edge Cases
Large dynamic route generation
If getStaticPaths returns a huge number of routes, memory and build time can spike. Move infrequently visited pages to fallback strategies or ISR where appropriate.
Remote APIs hanging in CI
Sometimes the worker is terminated because static generation blocks too long on a slow internal API only reachable from Jenkins. Add request timeouts, retries, and better logging around fetch calls.
const controller = new AbortController()
const timeout = setTimeout(() => controller.abort(), 10000)
const res = await fetch(url, { signal: controller.signal })
clearTimeout(timeout)
Native dependency differences
Packages used for image manipulation, MDX, canvas, or syntax parsing may behave differently on Jenkins Linux images than on local macOS or Windows machines. Rebuild native modules and ensure system libraries are present.
Monorepo memory amplification
In a monorepo, workspace tooling can increase memory usage before Next.js even starts building. If Turbo, Nx, or custom scripts run in the same step, isolate the frontend build.
Build log truncation hides the real cause
Jenkins sometimes makes it look like Next.js failed first, when the real issue was an earlier warning, OOM event, or agent interruption. Review full console output and host/container logs when possible.
FAQ
Why does this happen only in Jenkins and not locally?
Because Jenkins often runs inside a more constrained environment: smaller memory limits, shared CPU, timeouts, containers, or ephemeral agents. Your local machine may simply have more available resources and fewer process restrictions.
Does SIGTERM mean Next.js itself is broken?
Usually no. SIGTERM means the worker was asked to stop by something external. Next.js is the visible failing process, but the underlying cause is typically CI resource management, build workload size, or environment configuration.
What is the fastest fix to try first?
Start with three changes: set NODE_OPTIONS=–max-old-space-size=4096, increase Jenkins agent or container memory, and reduce expensive static generation logic. Those fix the majority of real-world cases.
Final Recommendation
If you see “Static worker unexpectedly exited with code: null and signal: SIGTERM” during Next.js builds in Jenkins, treat it as a CI process termination problem first, not just an application bug. Increase available memory, verify container limits, relax timeout settings, and reduce static build workload. Once Jenkins stops killing the worker, the build usually becomes stable without code changes to Next.js itself.