<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/recursive-make-and--j-hcnzegp83" -->

---
title: Recursive make and -j | daily.dev
description: A deep dive into recursive make invocations examines how GNU Make's jobserver mechanism (used for -j parallelism) behaves differently across versions 3.81...
canonical: https://daily.dev/posts/recursive-make-and--j-hcnzegp83
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Recursive make and -j | daily.dev
og:description: A deep dive into recursive make invocations examines how GNU Make's jobserver mechanism (used for -j parallelism) behaves differently across versions 3.81...
og:url: https://daily.dev/posts/recursive-make-and--j-hcnzegp83
og:image: https://api.daily.dev/og/posts/HcnzEgP83.png
og:image:alt: Recursive make and -j
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Recursive make and -j

**[Arthur O'Dwyer](https://daily.dev/sources/quuxplusone)** · 5 min read · 0 upvotes · 0 comments

## Summary

A deep dive into recursive make invocations examines how GNU Make's jobserver mechanism (used for -j parallelism) behaves differently across versions 3.81 through 4.3. When a Makefile recipe calls make directly instead of using +make or $(MAKE), parallelism is lost and warnings appear. The post documents exact behavioral tables for each version, showing how warning messages and effective parallelism levels changed, particularly around GNU Make 4.0's introduction of the 'jobserver unavailable' warning and 4.2.1/4.3's refinement of the '-jN forced in submake' message to include the actual N value and to preserve unlimited parallelism (∞) instead of collapsing to 1.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://quuxplusone.github.io/blog/2026/09/30/recursive-make-j>

## Questions this post answers

### Why does make -j2 print 'jobserver unavailable: using -j1' when I run a recursive make recipe?

This warning was introduced starting with GNU Make 4.0 and appears when a Makefile recipe invokes make directly (e.g. 'make -C bar') without forwarding the jobserver. Because the jobserver token isn't passed to the child process, the submake falls back to running serially (-j1) instead of inheriting the parent's parallelism level. GNU Make 3.81 did not emit this warning at all.

_Developers debugging build parallelism regressions can track version-specific make behavior changes on daily.dev._

### How do I fix the 'jobserver unavailable' warning in a recursive Makefile?

Prefix the make invocation with a plus sign, like '+make -C bar', or replace 'make' with '$(MAKE)' in the recipe line. Both approaches restore jobserver forwarding so the child make inherits the parent's -j parallelism setting and uses the same make binary invoked by the parent, rather than whatever make is found in the path.

_Anyone tuning Makefile parallelism can compare these fixes before touching build scripts, via daily.dev._

### Did GNU Make change how -jN forced-in-submake warnings behave between version 4.2.1 and earlier releases?

Yes, GNU Make 4.2.1 and 4.3 changed the warning text from a generic '-jN forced in submake: disabling jobserver mode' to one that names the actual value of N, such as '-j2 forced in submake: resetting jobserver mode'. They also changed the behavior of unrestricted -j recursive rules so that running with -j2 or -j4 on the parent no longer collapses them to a fixed job count, keeping them unlimited (∞) instead.

_Teams upgrading their toolchain can check exact make version gotchas like this on daily.dev before a build breaks._

## Similar posts on daily.dev

- [A Simple Makefile Tutorial](https://daily.dev/posts/a-simple-makefile-tutorial-p5u1o7top) · Lobsters · 0 upvotes · 0 comments
- [Adding a Makefile help Target](https://daily.dev/posts/adding-a-makefile-help-target-1prwzdhz9) · Embedded Artistry · 0 upvotes · 0 comments
- [GNU Automake 1.19 Released With More Than One Year Worth Of Fixes](https://daily.dev/posts/gnu-automake-1-19-released-with-more-than-one-year-worth-of-fixes-m6536wcyo) · Phoronix · 0 upvotes · 0 comments
- [Repeating Ourselves Less with M4](https://daily.dev/posts/repeating-ourselves-less-with-m4-meax6hzos) · Lobsters · 0 upvotes · 0 comments
- [Nix wrote half of my debugger](https://daily.dev/posts/nix-wrote-half-of-my-debugger-gnc47givc) · Farid Zakaria’s Blog · 0 upvotes · 0 comments

---

Tags: [#build-systems](https://daily.dev/tags/build-systems)

[View this post on daily.dev](https://daily.dev/posts/recursive-make-and--j-hcnzegp83)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Recursive make and -j","url":"https://daily.dev/posts/recursive-make-and--j-hcnzegp83","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/recursive-make-and--j-hcnzegp83"},"datePublished":"2026-09-30T16:50:30.660Z","dateModified":"2026-09-30T16:50:52.910Z","description":"A deep dive into recursive make invocations examines how GNU Make's jobserver mechanism (used for -j parallelism) behaves differently across versions 3.81...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/e3a9783d2dc46301158849c96a3b989b?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/e3a9783d2dc46301158849c96a3b989b?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Arthur O'Dwyer","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Arthur O'Dwyer","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/a789aa2fcdb64c219980d6d6901791e9","url":"https://daily.dev/sources/quuxplusone"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/recursive-make-and--j-hcnzegp83","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"build-systems","timeRequired":"PT5M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Arthur O'Dwyer","item":"https://daily.dev/sources/quuxplusone"},{"@type":"ListItem","position":3,"name":"Recursive make and -j"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/recursive-make-and--j-hcnzegp83#faq","mainEntity":[{"@type":"Question","name":"Why does make -j2 print 'jobserver unavailable: using -j1' when I run a recursive make recipe?","acceptedAnswer":{"@type":"Answer","text":"This warning was introduced starting with GNU Make 4.0 and appears when a Makefile recipe invokes make directly (e.g. 'make -C bar') without forwarding the jobserver. Because the jobserver token isn't passed to the child process, the submake falls back to running serially (-j1) instead of inheriting the parent's parallelism level. GNU Make 3.81 did not emit this warning at all. Developers debugging build parallelism regressions can track version-specific make behavior changes on daily.dev."}},{"@type":"Question","name":"How do I fix the 'jobserver unavailable' warning in a recursive Makefile?","acceptedAnswer":{"@type":"Answer","text":"Prefix the make invocation with a plus sign, like '+make -C bar', or replace 'make' with '$(MAKE)' in the recipe line. Both approaches restore jobserver forwarding so the child make inherits the parent's -j parallelism setting and uses the same make binary invoked by the parent, rather than whatever make is found in the path. Anyone tuning Makefile parallelism can compare these fixes before touching build scripts, via daily.dev."}},{"@type":"Question","name":"Did GNU Make change how -jN forced-in-submake warnings behave between version 4.2.1 and earlier releases?","acceptedAnswer":{"@type":"Answer","text":"Yes, GNU Make 4.2.1 and 4.3 changed the warning text from a generic '-jN forced in submake: disabling jobserver mode' to one that names the actual value of N, such as '-j2 forced in submake: resetting jobserver mode'. They also changed the behavior of unrestricted -j recursive rules so that running with -j2 or -j4 on the parent no longer collapses them to a fixed job count, keeping them unlimited (∞) instead. Teams upgrading their toolchain can check exact make version gotchas like this on daily.dev before a build breaks."}}]}
```

