Skip to main content
meow produces real node_modules directories — not a virtual filesystem and not symlinked package contents. That’s a deliberate choice: V8, Vite, and bundlers resolve through fs.realpath, and symlinked package contents break that. meow gives you the speed of a shared store with the compatibility of real files.

The layout

Packages are materialized into a project-local content-addressed store under node_modules/.meow, and the top-level names you import are edges pointing into it:
This is a flat, deduplicated, pnpm-style graph — but with a crucial difference in how the bytes get there.

Contents are cloned, not linked

The actual package files come from the global cache using the fastest primitive each OS offers: The result: 0 bytes of duplicated disk. A file shared across versions or projects exists once physically; copy-on-write means a write would fork it rather than corrupt the shared copy.
Why edges stay links but contents don’t. The pointer inside a package’s node_modules to another package (a graph edge) is a link — cheap, and traversal through it is fine. But a package’s own files are cloned/hardlinked, never symlinked, so tools that call fs.realpath (V8, Vite) see a normal directory and never trip on symlink traversal.

Incremental & skippable

meow writes a small .materialized sidecar that records the state of the tree. If node_modules is already up to date for the current lockfile, materialization is skipped entirely:
A content hash of the materialized tree is computed so meow can detect drift and repair it on the next install.

Cleaning & rebuilding

Because the global cache holds the bytes, a clean rebuild is cheap — it re-clones from the cache rather than re-downloading.

Vendoring

For fully self-contained, reproducible trees (air-gapped builds, committed dependencies, deterministic CI), use vendor mode, which copies packages instead of linking them and normalizes file metadata for byte-reproducibility:

Run package binaries

meow x, global installs, and searching the registry.