directus-main — pnpm to Yarn migration
Directus's own monorepo is pnpm-native: a 331-entry
catalog:
version table,
pnpm.overrides
, a regex script-filter,
pnpm deploy
,
pnpm fetch
's layer-cache trick, and an
onlyBuiltDependencies
allowlist. None of those have an exact Yarn Berry equivalent — each one got a real decision, tested against a real
install, not a find-and-replace. Two of those first-pass decisions were wrong and got corrected properly. See
System Architecture
for where this manifest layer sits relative to real source.
Six mechanisms, six outcomes: two required no special handling once verified (
overrides
, the regex-script-filter dropped for explicit lists), two got a working replacement built (
catalog:
,
pnpm deploy
), and two are accepted, disclosed regressions with no real equivalent (
enableScripts
,
pnpm fetch
's layer-caching).
isolated-vm@5.0.3 — incompatible with Node 26's V8
The version inherited from Directus's own catalog failed to compile identically on Windows and the GitHub Actions
Ubuntu runner. Real compiler output (
gh run view --log-failed
) showed the native addon calling V8 APIs Node 26's bundled V8 has since removed or changed —
Template::SetAccessor
,
GetPrototype
, internal-field accessor signatures. Every
other
native module in the ~2,150-package graph built cleanly, ruling out a missing-toolchain theory first. Fixed by
bumping to
7.0.1
, verified with a real
yarn install
.
"Yarn has no shared-catalog feature" — wrong, corrected
Stood documented as fact — in this repo's own docs, its wiki, and several commit messages — until
yarn config -v
's full settings dump (not
yarn help
, which doesn't mention it) surfaced real
catalog
/
catalogs
config keys. Verified in a throwaway scratch project before touching this repo.
First pass — wrong
// "Yarn has no catalog: // equivalent" — assumed, // never actually checked "lodash": "4.17.21"
Corrected — verified
// .yarnrc.yml catalog: { lodash: 4.17.21 } // package.json "lodash": "catalog:"
deploy-production.mjs — pruned the live repo's own node_modules
pnpm deploy --legacy --prod
has no Yarn equivalent; the first replacement script pruned this repo's own root
node_modules
in place — a real regression from pnpm's separately-built deploy output. Reconsidered:
yarn workspaces focus --production
only needs
a
checkout at the right commit, not the live working tree, so the script now runs inside a disposable
git worktree
instead. Verified end-to-end — a working
dist/
with 724
node_modules
entries came out the other side.
@directus/tsconfig — neither config sets rootDir
A real gap in Directus's own published
@directus/tsconfig
npm package (v4.0.0): with
outDir
set but no explicit
rootDir
, TypeScript falls back to inferring it from the include set's "common source directory." Real
tsc
5.9.3 builds identically either way — confirmed by running it directly and diffing output before/after — but newer
TS tooling errors on the implicit inference. Fixed with an explicit
"rootDir": "./src"
in
packages/types/tsconfig.json
, the value already being inferred.
Webhint — stale bundled schema flagged a valid tsconfig value
The VS Code Webhint extension's
typescript-config/is-valid
hint flagged
lib: ["ES2023"]
as invalid. It isn't — TypeScript 5.9.3 (the version actually installed) has supported
ES2023
as a
lib
value since 5.2; the hint's bundled schema is just out of date. Confirmed against the real installed TypeScript
version before suppressing, and scoped the suppression to that one hint only.
release-notes-generator — still imports removed pnpm internals
package.json
no longer lists
@pnpm/workspace.find-packages
,
@pnpm/workspace.pkgs-graph
, or
@pnpm/logger
— but the actual source file that imports them,
src/utils/process-packages.ts
, hasn't been rewritten yet. Caught and tracked rather than assumed fixed just because the manifest looked clean.
Planned replacement: read each workspace's
package.json
directly and build the dependency graph from
workspace:*
references — no package-manager-specific API needed at all.
enableScripts: true — a real security-posture downgrade
pnpm's
onlyBuiltDependencies
is a default-deny list for which packages may run install/postinstall scripts. Yarn Berry has no scoped equivalent
—
enableScripts: true
is its permissive default. Accepted and documented rather than silently inherited.
Docker build-cache regression — no pnpm fetch equivalent
pnpm fetch
populates the store from just the lockfile, before the full source tree is copied in — a real Docker layer-caching
optimization. Yarn workspaces need every workspace's
package.json
present to resolve at all, so there's no equivalent partial-copy trick without fragile wildcards. Both Dockerfiles
now do one
COPY . .
then
yarn install
— any source change invalidates the install layer too.
Five gaps found and fixed, one tracked openly, two accepted trade-offs — all six categories recorded in this repo's own todo.md , not just here. See Known Gaps for the rest of what's still open across CI, testing, and Docker.