Reference configs

vercel/next.js: two workspaces, one config

Next.js is a pnpm workspace and a Cargo workspace in one repository, and each ecosystem's tools read only their own manifests. One config checks both, and on the May tree it found two published npm packages with no license. This config was written to test alint; Next.js doesn't use alint.

What alint found

.alint.yml
- id: nextjs-package-has-license-field
  kind: for_each_dir
  select: "packages/*"
  when_iter: 'iter.has_file("package.json")'
  require:
    - kind: json_path_matches
      paths: "{path}/package.json"
      path: "$.license"
      matches: '^MIT$'
  level: warning

⚠︎ warning nextjs-package-has-license-field

Three packages have no license field. Two of them, @next/plugin-storybook and next-rspack, are published to npm; the third, next-swc, is private.

.alint.yml
- id: nextjs-crate-license-set
  kind: toml_path_matches
  paths: ["crates/*/Cargo.toml", "turbopack/crates/*/Cargo.toml"]
  path: "$.package.license"
  matches: '^(MIT|MPL-2\.0|Apache-2\.0)$'
  level: info

ℹ︎ info nextjs-crate-license-set

Four of the 63 crates declare no license. Three set publish = false, and the fourth, the error-code SWC plugin, is left out of the workspace. The JavaScript tools don't read Cargo manifests, and Cargo doesn't read npm packages.

The bundled GitHub Actions rules (alint 0.16.1, on the workflows as of 7 May 2026) flag 95 action references not pinned to a commit, and 21 workflows that declare no permissions.

The config

The pnpm workspace lists 7 package patterns and the root Cargo.toml 13 members; the 19 packages under packages/ share one canary version, which lerna publishes. The config checks the fields every npm package and crate should carry, the Node and Rust toolchain pins, the husky hooks and lerna's publish settings. The linters and four check scripts run from command_idempotent rules. A fifth runs scripts/check-manifests.js, which fails: the error manifest it reads was deleted in 2023.

.alint.yml
- id: nextjs-package-version-pinned-to-major
  kind: for_each_dir
  select: "packages/*"
  when_iter: 'iter.has_file("package.json")'
  require:
    - kind: json_path_matches
      paths: "{path}/package.json"
      path: "$.version"
      matches: '^16\.\d+\.\d+(-(canary|alpha|beta|rc)\.\d+)?$'
  level: warning

The packages share one version, which lerna publishes from the canary branch. Every package has to be on the current major.

What stays outside alint

What analyzes code or reads git history stays with the Next.js tools:

  • ESLint, tsc, ast-grep and alex, which analyze code or wording, and Clippy, which needs the Rust compiler; alint only runs them;
  • the example and precompiled checks, which regenerate files and diff them, and the release and backport checks, which read git history;
  • the server-externals check, whose docs side is a Markdown table alint can't extract values from reliably;
  • matching each package directory to its package name, such as packages/font and @next/font, which has no rule kind yet.