[{"data":1,"prerenderedAt":858},["ShallowReactive",2],{"NoscriptNav_XrRK2e2e8meJ0jKVGkb5ULGQDVi3UiFQ9nupAr7Yns":3,"\u002Freports\u002Fpackage-manager-magic-files":8},["Island",4],{"key":5,"result":6},"NoscriptNav_XrRK2e2e8meJ0jKVGkb5ULGQDVi3UiFQ9nupAr7Yns",{"head":7},{},{"id":9,"title":10,"authors":11,"body":13,"canonicalUrl":844,"canonicalWebsiteName":845,"category":846,"date":847,"description":848,"extension":849,"featured":850,"fullWidthLayout":850,"image":851,"imageAlt":851,"location":851,"meta":852,"metaImage":851,"navigation":853,"path":854,"seo":855,"stem":856,"venue":851,"venueUrl":851,"__hash__":857},"reports\u002Freports\u002Fpackage-manager-magic-files.md","Package Manager Magic Files",[12],"andrew",{"type":14,"value":15,"toc":833},"minimark",[16,33,38,41,82,111,121,153,171,201,219,249,275,289,307,317,333,337,340,385,411,420,424,427,447,460,486,506,510,513,565,586,607,633,659,673,677,680,698,729,746,760,764,767,781,795,816,819],[17,18,19,20,25,26,32],"p",{},"A follow-up to my post on ",[21,22,24],"a",{"href":23},"\u002Freports\u002Fgit-magic-files","git's magic files",". Most package managers have a manifest and a lockfile, and most developers stop there. But across the ecosystems I track on ",[21,27,31],{"href":28,"rel":29},"https:\u002F\u002Fecosyste.ms",[30],"nofollow","ecosyste.ms",", package managers check for dozens of other files beyond the manifest and lockfile, controlling where packages come from, what gets published, how versions resolve, and what code runs during installation. These files tend to be poorly documented, inconsistently named, and useful once you know they exist.",[34,35,37],"h3",{"id":36},"configuration","Configuration",[17,39,40],{},"Registry URLs, auth tokens, proxy settings, cache behavior. Every package manager has a way to configure these, and they almost always live outside the manifest.",[17,42,43,51,52,55,56,59,60,62,63,66,67,70,71,74,75,77,78,81],{},[21,44,47],{"href":45,"rel":46},"https:\u002F\u002Fdocs.npmjs.com\u002Fcli\u002Fv11\u002Fconfiguring-npm\u002Fnpmrc",[30],[48,49,50],"code",{},".npmrc"," is an INI-format file that can live at the project root, in your home directory, or globally. npm and pnpm both read it. It controls the registry URL, auth tokens for private registries, proxy settings, and dozens of install behaviors like ",[48,53,54],{},"legacy-peer-deps"," and ",[48,57,58],{},"engine-strict",". There's a footgun here: if an ",[48,61,50],{}," ends up inside a published package tarball, npm will silently apply those settings when someone installs your package in their project. Less well known are the ",[48,64,65],{},"shell",", ",[48,68,69],{},"script-shell",", and ",[48,72,73],{},"git"," settings, which point at arbitrary executables that npm will invoke during lifecycle scripts and git operations. Research by Snyk and Cider Security showed these as viable attack vectors: a malicious ",[48,76,50],{}," committed to a repository can redirect script execution without touching ",[48,79,80],{},"package.json"," at all.",[17,83,84,91,92,95,96,99,100,103,104,107,108,110],{},[21,85,88],{"href":86,"rel":87},"https:\u002F\u002Fyarnpkg.com\u002Fconfiguration\u002Fyarnrc",[30],[48,89,90],{},".yarnrc.yml"," replaced the INI format of Yarn Classic's ",[48,93,94],{},".yarnrc",". It configures which linker to use (PnP, pnpm-style, or traditional ",[48,97,98],{},"node_modules","), registry auth, and the ",[48,101,102],{},"pnpMode"," setting that controls how strictly Yarn enforces its dependency resolution. The ",[48,105,106],{},"yarnPath"," setting is security-sensitive: it points to a JavaScript file that Yarn will execute as its own binary, so a malicious ",[48,109,90],{}," can hijack the entire package manager.",[17,112,113,120],{},[21,114,117],{"href":115,"rel":116},"https:\u002F\u002Fbun.sh\u002Fdocs\u002Fruntime\u002Fbunfig",[30],[48,118,119],{},"bunfig.toml"," is Bun's config file, covering registry config, install behavior, and the test runner all in one TOML file.",[17,122,123,130,131,134,135,66,138,70,141,144,145,148,149,152],{},[21,124,127],{"href":125,"rel":126},"https:\u002F\u002Fpip.pypa.io\u002Fen\u002Fstable\u002Ftopics\u002Fconfiguration\u002F",[30],[48,128,129],{},"pip.conf"," on Unix and ",[48,132,133],{},"pip.ini"," on Windows, searched at ",[48,136,137],{},"~\u002F.config\u002Fpip\u002Fpip.conf",[48,139,140],{},"~\u002F.pip\u002Fpip.conf",[48,142,143],{},"\u002Fetc\u002Fpip.conf",". The ",[48,146,147],{},"PIP_CONFIG_FILE"," environment variable can override all of these or point to ",[48,150,151],{},"\u002Fdev\u002Fnull"," to disable config entirely. Malformed config files are silently ignored rather than producing errors, so you can have broken configuration for months without realizing it.",[17,154,155,162,163,166,167,170],{},[21,156,159],{"href":157,"rel":158},"https:\u002F\u002Fdocs.astral.sh\u002Fuv\u002Fconcepts\u002Fconfiguration-files\u002F",[30],[48,160,161],{},"uv.toml"," or the ",[48,164,165],{},"[tool.uv]"," section in ",[48,168,169],{},"pyproject.toml",".",[17,172,173,180,181,184,185,188,189,192,193,196,197,200],{},[21,174,177],{"href":175,"rel":176},"https:\u002F\u002Fbundler.io\u002Fman\u002Fbundle-config.1.html",[30],[48,178,179],{},".bundle\u002Fconfig"," stores Bundler's per-project config, created by ",[48,182,183],{},"bundle config set",". RubyGems has its own ",[48,186,187],{},".gemrc"," file, which Bundler deliberately ignores because it calls ",[48,190,191],{},"Gem::Installer"," directly. The credentials file at ",[48,194,195],{},"~\u002F.gem\u002Fcredentials"," must have ",[48,198,199],{},"0600"," permissions or RubyGems refuses to read it.",[17,202,203,210,211,214,215,218],{},[21,204,207],{"href":205,"rel":206},"https:\u002F\u002Fdoc.rust-lang.org\u002Fcargo\u002Freference\u002Fconfig.html",[30],[48,208,209],{},".cargo\u002Fconfig.toml"," is the most interesting of the bunch because it's hierarchical: Cargo walks up the directory tree merging config files as it goes, so you can have workspace-level settings that individual crates inherit. It controls registries, proxy settings, build targets, and command aliases. A backwards-compatibility quirk means Cargo still reads ",[48,212,213],{},".cargo\u002Fconfig"," without the ",[48,216,217],{},".toml"," extension, and if both files exist, the extensionless one wins, which is an easy way to have a stale config file shadow your actual settings.",[17,220,221,228,229,232,233,236,237,240,241,244,245,248],{},[21,222,225],{"href":223,"rel":224},"https:\u002F\u002Fdocs.conda.io\u002Fprojects\u002Fconda\u002Fen\u002Fstable\u002Fuser-guide\u002Fconfiguration\u002Fuse-condarc.html",[30],[48,226,227],{},".condarc"," is searched at six different paths from ",[48,230,231],{},"\u002Fetc\u002Fconda\u002F.condarc"," through ",[48,234,235],{},"~\u002F.condarc"," to ",[48,238,239],{},"$CONDA_PREFIX\u002F.condarc",", plus ",[48,242,243],{},".d\u002F"," directories at each level for drop-in fragments, and you can put one inside a specific conda environment to configure just that environment. Every setting also has a ",[48,246,247],{},"CONDA_UPPER_SNAKE_CASE"," environment variable equivalent.",[17,250,251,258,259,262,263,266,267,270,271,274],{},[21,252,255],{"href":253,"rel":254},"https:\u002F\u002Fmaven.apache.org\u002Fsettings.html",[30],[48,256,257],{},"~\u002F.m2\u002Fsettings.xml"," holds Maven's repositories and credentials, plus ",[48,260,261],{},"~\u002F.m2\u002Fsettings-security.xml"," stores the master password used to decrypt encrypted passwords in the main settings file. Most developers don't know ",[48,264,265],{},"settings-security.xml"," exists. ",[48,268,269],{},".mvn\u002Fmaven.config"," holds per-project default CLI arguments (since Maven 3.9.0, each arg must be on its own line), and ",[48,272,273],{},".mvn\u002Fjvm.config"," sets JVM options.",[17,276,277,284,285,288],{},[21,278,281],{"href":279,"rel":280},"https:\u002F\u002Fdocs.gradle.org\u002Fcurrent\u002Fuserguide\u002Fbuild_environment.html",[30],[48,282,283],{},"gradle.properties"," lives at both project and user level. Init scripts in ",[48,286,287],{},"~\u002F.gradle\u002Finit.d\u002F"," run before every build, which is how enterprises inject internal repository configurations across all projects.",[17,290,291,298,299,302,303,306],{},[21,292,295],{"href":293,"rel":294},"https:\u002F\u002Fgetcomposer.org\u002Fdoc\u002Farticles\u002Fauthentication-for-private-packages.md",[30],[48,296,297],{},"auth.json"," keeps Composer credentials separate from ",[48,300,301],{},"composer.json"," (per-project or at ",[48,304,305],{},"~\u002F.composer\u002Fauth.json",") so you can gitignore it.",[17,308,309,316],{},[21,310,313],{"href":311,"rel":312},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fnuget\u002Freference\u002Fnuget-config-file",[30],[48,314,315],{},"nuget.config"," is XML searched hierarchically from the project directory up to the drive root, then at the user level. Like pip, malformed XML is silently ignored.",[17,318,319,326,327,330,331,170],{},[21,320,323],{"href":321,"rel":322},"https:\u002F\u002Fdocs.deno.com\u002Fruntime\u002Ffundamentals\u002Fconfiguration\u002F",[30],[48,324,325],{},"deno.json"," is both configuration and import map, controlling formatting, linting, test config, lock file behavior, and dependency imports in a single file. If you have a separate ",[48,328,329],{},"import_map.json",", Deno reads that too, though the trend is toward folding everything into ",[48,332,325],{},[34,334,336],{"id":335},"publishing","Publishing",[17,338,339],{},"What gets included or excluded when you publish a package. People accidentally ship secrets and accidentally omit files they need in roughly equal measure.",[17,341,342,349,350,353,354,55,357,360,361,363,364,366,367,369,370,372,373,376,377,380,381,384],{},[21,343,346],{"href":344,"rel":345},"https:\u002F\u002Fdocs.npmjs.com\u002Fcli\u002Fv11\u002Fconfiguring-npm\u002Fpackage-json#files",[30],[48,347,348],{},".npmignore"," works like ",[48,351,352],{},".gitignore"," but for ",[48,355,356],{},"npm pack",[48,358,359],{},"npm publish",". If it doesn't exist, npm falls back to ",[48,362,352],{},". But if you create an ",[48,365,348],{},", it completely replaces ",[48,368,352],{}," for packaging purposes, they are not merged. This means patterns you had in ",[48,371,352],{}," to keep ",[48,374,375],{},".env"," files or credentials out of version control no longer protect you from publishing them.\n",[48,378,379],{},"npm-shrinkwrap.json"," is identical in format to ",[48,382,383],{},"package-lock.json"," but gets included inside published tarballs. It's the only npm lock file that travels with a published package, intended for CLI tools and daemons that want locked transitive dependencies for their consumers rather than letting the consumer's resolver pick versions.",[17,386,387,394,395,66,398,66,401,66,404,70,407,410],{},[21,388,391],{"href":389,"rel":390},"https:\u002F\u002Fpackaging.python.org\u002Fen\u002Flatest\u002Fguides\u002Fusing-manifest-in\u002F",[30],[48,392,393],{},"MANIFEST.in"," controls what goes into a Python source distribution using directives like ",[48,396,397],{},"include",[48,399,400],{},"exclude",[48,402,403],{},"recursive-include",[48,405,406],{},"graft",[48,408,409],{},"prune",". It only matters for sdists, not wheels.",[17,412,413,416,417,419],{},[48,414,415],{},".helmignore"," controls what gets excluded when packaging a Helm chart, following ",[48,418,352],{}," syntax.",[34,421,423],{"id":422},"workspaces","Workspaces",[17,425,426],{},"Monorepo topology and inter-package relationships. The JavaScript ecosystem has the most options here, which probably says something about the JavaScript ecosystem.",[17,428,429,436,437,440,441,443,444,446],{},[21,430,433],{"href":431,"rel":432},"https:\u002F\u002Fpnpm.io\u002Fpnpm-workspace_yaml",[30],[48,434,435],{},"pnpm-workspace.yaml"," defines workspace membership with a ",[48,438,439],{},"packages:"," field. Where npm and Yarn put this in a ",[48,442,422],{}," field in ",[48,445,80],{},", pnpm requires a separate file.",[17,448,449,452,453,55,456,459],{},[48,450,451],{},"lerna.json"," handles versioning and publishing across workspace packages, though Lerna's remaining value is mostly the publishing workflow (changelogs, version bumps). ",[48,454,455],{},"nx.json",[48,457,458],{},"turbo.json"," configure task pipelines and caching for Nx and Turborepo monorepo builds.",[17,461,462,469,470,473,474,477,478,481,482,485],{},[21,463,466],{"href":464,"rel":465},"https:\u002F\u002Fgo.dev\u002Fref\u002Fmod#workspaces",[30],[48,467,468],{},"go.work"," (added in Go 1.18) lists ",[48,471,472],{},"use"," directives pointing to local module directories so you can develop across multiple modules without ",[48,475,476],{},"replace"," directives scattered through your ",[48,479,480],{},"go.mod"," files. It generates a companion ",[48,483,484],{},"go.work.sum"," checksum file.",[17,487,488,491,492,495,496,498,499,502,503,170],{},[48,489,490],{},"settings.gradle"," \u002F ",[48,493,494],{},"settings.gradle.kts"," declares all Gradle subprojects with ",[48,497,397],{}," statements and is mandatory for multi-project builds. Maven uses ",[48,500,501],{},"\u003Cmodules>"," in a parent ",[48,504,505],{},"pom.xml",[34,507,509],{"id":508},"overrides-and-resolution","Overrides and resolution",[17,511,512],{},"When a transitive dependency has a bug or a security vulnerability and you can't wait for every package in the chain to release an update, override files let you force a specific version or patch a package in place. Most developers don't know these mechanisms exist and spend hours working around dependency conflicts that a single config line would fix.",[17,514,515,516,523,524,531,532,539,540,542,543,546,547,550,551,554,555,558,559,55,562,170],{},"In the JavaScript ecosystem, npm has ",[21,517,520],{"href":518,"rel":519},"https:\u002F\u002Fdocs.npmjs.com\u002Fcli\u002Fv11\u002Fconfiguring-npm\u002Fpackage-json#overrides",[30],[48,521,522],{},"overrides",", Yarn has ",[21,525,528],{"href":526,"rel":527},"https:\u002F\u002Fyarnpkg.com\u002Fconfiguration\u002Fmanifest#resolutions",[30],[48,529,530],{},"resolutions",", and pnpm has ",[21,533,536],{"href":534,"rel":535},"https:\u002F\u002Fpnpm.io\u002Fpackage_json#pnpmoverrides",[30],[48,537,538],{},"pnpm.overrides",", all fields in ",[48,541,80],{}," that force specific versions of transitive dependencies. Yarn Berry and pnpm also support patching dependencies in place: Yarn's ",[48,544,545],{},"patch:"," protocol stores diff files in ",[48,548,549],{},".yarn\u002Fpatches\u002F",", and pnpm's ",[48,552,553],{},"pnpm.patchedDependencies"," references diffs in a ",[48,556,557],{},"patches\u002F"," directory, built into the workflow via ",[48,560,561],{},"pnpm patch",[48,563,564],{},"pnpm patch-commit",[17,566,567,574,575,578,579,581,582,585],{},[21,568,571],{"href":569,"rel":570},"https:\u002F\u002Fpnpm.io\u002Fpnpmfile",[30],[48,572,573],{},".pnpmfile.cjs"," goes further than any of these: the ",[48,576,577],{},"readPackage"," hook lets you programmatically rewrite any package's ",[48,580,80],{}," at install time, and ",[48,583,584],{},"afterAllResolved"," can modify the lockfile after resolution. It's the nuclear option for dependency problems, living next to the lockfile and running before anything gets installed.",[17,587,588,595,596,599,600,603,604,606],{},[21,589,592],{"href":590,"rel":591},"https:\u002F\u002Fpip.pypa.io\u002Fen\u002Fstable\u002Fuser_guide\u002F#constraints-files",[30],[48,593,594],{},"constraints.txt"," is used via ",[48,597,598],{},"pip install -c constraints.txt"," to pin versions of packages without triggering their installation. It's been available since pip 7.1, yet almost nobody uses it despite being exactly what large organizations need for base image management and reproducible environments. uv has ",[48,601,602],{},"override-dependencies"," in ",[48,605,165],{}," for the same purpose with better ergonomics.",[17,608,609,616,617,620,621,624,625,628,629,632],{},[21,610,613],{"href":611,"rel":612},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fnuget\u002Fconsume-packages\u002Fcentral-package-management",[30],[48,614,615],{},"Directory.Packages.props"," is worth knowing about if you work in .NET. NuGet's Central Package Management (6.4+) lets you put a single file at the repo root that sets ",[48,618,619],{},"\u003CPackageVersion>"," for all projects, so individual ",[48,622,623],{},".csproj"," files use ",[48,626,627],{},"\u003CPackageReference>"," without version numbers. It eliminates version drift across large solutions and is one of the better implementations of centralized version management I've seen. ",[48,630,631],{},"Directory.Build.props"," can inject shared package references into all projects too.",[17,634,635,642,643,66,646,66,649,70,652,655,656,170],{},[21,636,639],{"href":637,"rel":638},"https:\u002F\u002Fdocs.gradle.org\u002Fcurrent\u002Fuserguide\u002Fversion_catalogs.html",[30],[48,640,641],{},"gradle\u002Flibs.versions.toml"," is Gradle's version catalog, with sections for ",[48,644,645],{},"[versions]",[48,647,648],{},"[libraries]",[48,650,651],{},"[bundles]",[48,653,654],{},"[plugins]",", referenced in build files as typed accessors like ",[48,657,658],{},"libs.someLibrary",[17,660,661,664,665,668,669,672],{},[48,662,663],{},"cabal.project"," supports ",[48,666,667],{},"constraints:"," stanzas for pinning transitive Haskell deps, and ",[48,670,671],{},"cabal.project.freeze"," locks everything down.",[34,674,676],{"id":675},"vendoring-and-integrity","Vendoring and integrity",[17,678,679],{},"Beyond lockfiles, some package managers support vendoring all dependency source code into the repository and tracking its integrity.",[17,681,682,685,686,693,694,697],{},[48,683,684],{},".cargo-checksum.json"," lives in each vendored crate directory after running ",[21,687,690],{"href":688,"rel":689},"https:\u002F\u002Fdoc.rust-lang.org\u002Fcargo\u002Fcommands\u002Fcargo-vendor.html",[30],[48,691,692],{},"cargo vendor",", containing the SHA256 of the original tarball and per-file checksums. If you need to patch vendored source (which you sometimes do for air-gapped builds), setting ",[48,695,696],{},"\"files\": {}"," in the checksum file disables integrity checking for that crate, which is the known workaround and also completely defeats the purpose of the checksums.",[17,699,700,710,711,714,715,718,719,721,722,725,726,728],{},[21,701,704,55,707],{"href":702,"rel":703},"https:\u002F\u002Fgo.dev\u002Fref\u002Fmod#private-modules",[30],[48,705,706],{},"GONOSUMCHECK",[48,708,709],{},"GONOSUMDB"," are Go environment variables that bypass the checksum database for private modules, which is how enterprises use Go modules without leaking internal module paths to Google's infrastructure. Go's ",[48,712,713],{},"vendor\u002Fmodules.txt"," (generated by ",[48,716,717],{},"go mod vendor",") lists vendored packages and their module versions, and the Go toolchain verifies it matches ",[48,720,480],{},". If your repo has a ",[48,723,724],{},"vendor\u002F"," directory and ",[48,727,480],{}," specifies Go 1.14+, vendoring is automatically enabled without any flag, which surprises people who have a stale vendor directory they forgot about.",[17,730,731,55,734,737,738,741,742,745],{},[48,732,733],{},".yarn\u002Fcache\u002F",[48,735,736],{},".pnp.cjs"," make up Yarn Berry's zero-install setup: compressed zip archives of every dependency and the Plug'n'Play loader mapping package names to zip locations, both committed to version control. After ",[48,739,740],{},"git clone",", the project works without running ",[48,743,744],{},"yarn install",", though your repository size will grow substantially.",[17,747,748,755,756,759],{},[21,749,752],{"href":750,"rel":751},"https:\u002F\u002Fdeveloper.hashicorp.com\u002Fterraform\u002Flanguage\u002Ffiles\u002Fdependency-lock",[30],[48,753,754],{},".terraform.lock.hcl"," records Terraform provider version locks with platform-specific hashes, which means a lock file generated on macOS may fail verification on Linux CI unless you've run ",[48,757,758],{},"terraform providers lock"," for multiple platforms.",[34,761,763],{"id":762},"hooks-and-scripts","Hooks and scripts",[17,765,766],{},"Lifecycle scripts that run during install, build, or publish. Supply chain attacks often hide here, but so does a lot of useful automation.",[17,768,769,774,775,777,778,780],{},[21,770,772],{"href":569,"rel":771},[30],[48,773,573],{}," isn't just for overrides. pnpm's hooks API includes ",[48,776,577],{}," for rewriting manifests, ",[48,779,584],{}," for modifying the resolved lockfile, and custom fetchers for alternative package fetching logic.",[17,782,783,786,787,790,791,794],{},[48,784,785],{},".yarn\u002Fplugins\u002F"," contains committed plugin files that hook into Yarn Berry's lifecycle. ",[48,788,789],{},".yarn\u002Fsdks\u002F"," holds editor integration files generated by ",[48,792,793],{},"@yarnpkg\u002Fsdks"," to make PnP work with IDEs.",[17,796,797,800,801,803,804,807,808,811,812,815],{},[48,798,799],{},".mvn\u002Fextensions.xml"," loads Maven extensions that hook into the build lifecycle before anything else runs. Gradle's init scripts in ",[48,802,287],{}," execute before every build and can inject repositories, apply plugins, or configure all projects. Cargo's ",[48,805,806],{},"build.rs"," is a build script that runs before compilation, generating code, linking native libraries, or setting cfg flags. Go's ",[48,809,810],{},"\u002F\u002Fgo:generate"," directives in source files run via ",[48,813,814],{},"go generate"," for code generation, though they're not part of the build itself.",[817,818],"hr",{},[17,820,821,822,827,828,170],{},"I'll keep updating this post as I find more. If you know of package manager magic files I've missed or have corrections, reach out on ",[21,823,826],{"href":824,"rel":825},"https:\u002F\u002Fmastodon.social\u002F@andrewnez",[30],"Mastodon"," or submit a pull request on ",[21,829,832],{"href":830,"rel":831},"https:\u002F\u002Fgithub.com\u002Fandrew\u002Fnesbitt.io",[30],"GitHub",{"title":834,"searchDepth":835,"depth":835,"links":836},"",2,[837,839,840,841,842,843],{"id":36,"depth":838,"text":37},3,{"id":335,"depth":838,"text":336},{"id":422,"depth":838,"text":423},{"id":508,"depth":838,"text":509},{"id":675,"depth":838,"text":676},{"id":762,"depth":838,"text":763},"https:\u002F\u002Fnesbitt.io\u002F2026\u002F03\u002F05\u002Fpackage-manager-magic-files","nesbitt.io","package-management","2026-03-05","Package manager magic files and where to find them: .npmrc, MANIFEST.in, Directory.Packages.props, .pnpmfile.cjs, and more.","md",false,null,{},true,"\u002Freports\u002Fpackage-manager-magic-files",{"title":10,"description":848},"reports\u002Fpackage-manager-magic-files","wqUHcs2gzASzoGfu0YqTaP0PfzHqfCM7m_r2rhmT-mc",1780596102874]