Why this matters
next.js is the most-watched JS / React framework on GitHub
(~140k stars). It is a hybrid pnpm + Cargo monorepo: a pnpm
workspace (packages/*, apps/*, bench/*, crates/*/js,
turbopack/packages/*, turbopack/crates/*/js) running
alongside a Cargo workspace (crates/* + turbopack/crates/*
scripts/send-trace-to-jaeger).
This is a distinct shape from microsoft/typescript (which IS the TS compiler — flat src/+tests/), from facebook/react (Yarn classic single-language workspace), and from vercel/turbo (modern Rust+TS hybrid with smaller surface). next.js is the canonical hybrid pnpm + Cargo mega-monorepo — and the canonical demonstration that no per-language linter sees the whole tree.
Headline catch
next.js is the first hybrid pnpm + Cargo dual-workspace win.
alint’s polyglot bundle composition (monorepo/cargo-workspace@v1
monorepo/pnpm-workspace@v1layered together) is the tightest fit in the case-study catalogue, and surfaces drift no per-language linter catches because each linter only sees half the tree:
- 3 of 19 npm packages missing license fields
- 4 of 63 crates missing the standard MIT/MPL license
gitattributesEOL pin sliding into drift would silently break Windows test runs- The
validate-externals-doc.jscross-file registry sync is a hand-rolled 600-LOCscripts/check-*.{js,mjs,sh}script family — alint’s v0.10cross_file_value_equalsship-target collapses it to one declarative rule
prettier sees formatting. eslint sees TS/JS AST. cargo clippy sees
Rust AST. None of them sees the cross-language conventions —
license uniformity, EOL pin, husky-hook content integrity, the 19
canary-pinned package versions, the [patch.crates-io] ↔
[workspace] members consistency.
Where alint earns its keep here
- Bundled
monorepo/cargo-workspace@v1+monorepo/pnpm-workspace@v1layered together cover both halves of the tree in one declarative file. No other tool composes ecosystem rules at this layer. - The 11-bundled-ruleset extends + 59 next.js-specific rules (130 rules total post-resolution) cover every structural assertion the existing tooling makes about repo state, plus several next.js doesn’t enforce today (per-crate license uniformity, husky-hook content integrity, gitattributes EOL pin).
- The 7 hand-rolled
scripts/check-*.{js,mjs,sh}(~600 LOC) collapse to 2 v0.10 rule kinds + a fewcommand:shellouts.validate-externals-doc.jsbecomescross_file_value_equals(8+ confirmations: airflow + tokio + next.js + clap + uv + react + pnpm + pytorch + tensorflow).check-manifests.jsbecomesregistry_paths_resolve(6+ confirmations). Codegen + git-state-mutation scripts (check-examples.sh,check-pre-compiled.sh) stay shellouts — alint reads files; it doesn’t regenerate and diff. - Pitfall #16 was discovered authoring this config. JSONPath
rules can’t regex-match against JSON booleans (silent runtime
error: “value at path is not a string (got bool), can’t apply
regex”). Surfaced two existing case studies with silently-broken
rules (
microsoft-typescript+vercel-turbo). Now in the published CONFIG-AUTHORING.md catalogue. Strengthens the smoke-test fixture audit as a v0.10+ DX item. dir_name_matches_fieldextension with unscoping is a next.js-specific demand:packages/font/→name: "@next/font",packages/next-mdx/→name: "@next/mdx". The baredir_name_matches_fieldfrom vercel/turbo would fire on every scoped package; the unscoping transform is the v0.10+ extension this case study motivates.
Future story angles
- Position as the fourth tile on alint.org/examples (after kubernetes, airflow, microsoft/typescript), with the angle: “for hybrid monorepos that span multiple ecosystems, no per-language linter sees the whole tree — alint is the layer that does.” The 11-bundled-ruleset compose-them-together story is the headline hook that no per-language linter (eslint / clippy / typos / ast-grep / alex) can reach.
- Hybrid-monorepo launch narrative — pair next.js with vercel/turbo (Rust monorepo orchestrator with zero hand-rolled scripts) for a “modern monorepo tier” launch tile pair. Same Vercel ecosystem; very different shapes; both have structural drift no per-language linter catches.
scope_filterevolution refactor — the dual pnpm + Cargo workspace shape benefits sharply from named scopes (rust-workspace,js-workspace,js-bench); cuts ~40 lines- makes per-subtree intent explicit. Canonical demonstration of the v0.9.17 named-scope payoff.
compliance/reuse@v1+agent-hygiene@v1adoption ladder rung —alint suggestagainst the live tree flaggedagent-hygiene(medium);compliance/reuseis a deliberate override (next.js uses MIT directly, no per-file SPDX headers). Both worth documented decisions.