I would suspect that this is related to to the fact that reading/writing dirs have no atomic semantics in POSIX fs, and same directories are easily read/written simultaneously by unrelated processes, but surely is cause to edge cases bugs, especially in a world with backup system based on fs snapshots.
This is a sad state of affairs.
https://gregoryszorc.com/blog/2018/10/29/global-kernel-locks...
I have not dug deeper into this aside from raising my open file limits and closing some apps I thought might be the culprit (but ended up not being the cause).
It's annoying because it's not consistent. The dev server will work just fine for a while then randomly slow down. It sucks because sometimes I spend a decent amount of time trying to figure out why my change/fix/etc isn't working only to realize I haven't been testing updated code (I made a code change and thought it hot-reloaded but it didn't).
APFS does suck though, don't get me wrong
edit: I just tested, 36s for an `npm i` on a decently large project I have locally, 46s with an overlay fs
`rm -rf node_modules && docker run --rm -ti -v $PWD:/app node:20.19.0-alpine3.20 sh -c "cd /app && npm i"`
So an overlay FS (if I'm understanding you/the OP correctly), not the VM's disk
If I exclude my git directories (one of the most important things on my computer) then I really don't see the point of using TM at all with the other backups I do regularly.
Even if I don't want to push to a server, I use a different disk or USB as an additional remote in git and push to that. Although I do that only for financial data, so only done once a month so it's not too big a hassle.
From https://eclecticlight.co/2025/10/02/why-did-that-macos-upgra...
> Backup utilities including Time Machine normally make a snapshot with each backup, and retain them for 24 hours, following which they’re automatically deleted. As snapshots can’t exclude folders in the way that Time Machine can in its backups, if you’ve been working with a couple of 100 GB VMs then they will be retained in snapshots even though you probably exclude them from being backed up.
Couldn’t these tests be instrumented to give a deeper dive into what may be happening here?
1) APFS's snapshot feature, driven by Time Machine, adds a heavy tax on the massive number of file writes and deletes performed by pnpm and git.
2) macOS's less efficient handling of parallel I/O negates the speed benefits of modern, concurrent tooling, creating a bottleneck that is particularly severe when combined with the overhead from snapshots
The difficult backup migration is just one symptom of a larger problem: Time Machine isn't robust. It has sharp edges and can fail in ways that are hard to recover from, like the network backup I lost. That lack of reliability and breaking changes not just in backup software but in whole ecosystem is the real issue for me. Apple "obsoletes" things in its own timeframe regardless of userbase. I've got enormous respect for Apple products and people who are building them and with them. I wish Apple would have "LTS" version of MacOS and better documentation - often tools exist but aren't easy accessible.
Why do you consider the chance of that to be low? APFS is functional and I trust to not eat my data, but it isn't a battle tested high performance file system that's done the rounds in the arena like, say, XFS.
I mean, I don't use NPM, but I recently copied over some small-ish raw Git repositories between machines, and had several WTF moments when I looked at what was actually going over the wire.
Instead of refactoring two of the planet's most widely-used 'consumer' file systems, perhaps https://www.sqlite.org/appfileformat.html should be seen as a more reasonable way forward?
But in the end both npm and git ends up having mass writing files in their use cases, regardless of meta data that could be put in a sqlite-like db. Making things faster safely really implies having those apps operating on some OS features that would allow of acquiring lock and committing semantics on fs subtrees or equivalent.
Lets take that given, i.e. massive IO works reliably only when a single process has access.
How will SQLite handle concurrent access by multiple processes when git/npm/whoever switches over to it?
(A: It doesn't, even in a single process, you need to obtain a global lock to write while all readers pause.)
Readers don't have to pause.
Sqlite lives inside a single file. I've never heard of any corruption issues in practice, even with thousands of high-throughput reads and writes -- the kinds that are being complained about. Because this is something SQLite is really good at.
But, the original post sort of handwaves about what pathological filesystem use is.
The examples they chose (git & npm) imply # of files.
I posit that as easy as it was to handwave that SQLite is obviously superior for npm/git than using N files, it'll be equally easy to handwave that it won't be a problem because SQLite is one file instead of many.
This is because C: has additional file system filters for system integrity that are not present on other drives; and also because C: has 8.3 name compatibility enabled by default, but additional NTFS partitions have that disabled. (so if your filenames are longer than the 8.3 format, Windows has to write twice the number of directory entries)
Even excluding directories (like D:\MyProject) from defender isn't a full solution, the fs filter will still use the file handle to do lookup of the file path to see if it is in an excluded directory (at least on win10), but excluding an entire drive (like D:\) does solve this.
I have found that adding git.exe to the process exclusion list makes the biggest difference here, although git is still slow when dealing with lots of files, it goes from unbearable to bearable.
- the claim that pathological filesystem behavior => git/npm/whoever should use a SQLite DB as a flat file rather than having multiple files.
- no pushback
- the reply w/"yes, definitely, by shoving all the files into a SQLite DB, concurrency & contention issues simply disappear"
There's a sort of comic "turtles all the way down" aspect to it.
Why not just have the filesystem be a SQLite DB then? (A: because it would suffer from all of the same problems, except worse, because it is not a filesystem)
What is notable here is that it would be both better aligned with how the underlying storage hardware works, and simultaneously also offers more usable interface for applications.
It is pretty apparent that the biggest reason why we commonly use posixy files is inertia rather than them being very good fit for anything these days
One major reason not to is that there needs to be a guaranteed way to free up space, e.g. by deleting a file, or doing something similar. Currently SQLite doesn't provide any means to reliably reclaim space without allocating even more first.
Also the API is quite different, e.g. if you can write(2) a single byte at a time if you really want to, and it's relatively fast compared to doing e.g. an INSERT each time, since it goes to the temp VFS buffer first
A lot of people have proposed exactly this, that modern filesystems ought to be relational databases at the directory/metadata level.
It would be amazing to be able to interface with the file system using SQL and have the power of transactions.
> A: because it would suffer from all of the same problems, except worse, because it is not a filesystem
Not really. Database technologies really are far more advanced in many ways. It would not suffer from many filesystem problems, and would actually be better in many ways.
Still, it doesn't stop people constantly bringing it up as a wish. Technically it would be amazing, and it wouldn't be hard to build. It just feels impossible to figure out how to migrate to.
The unfiltered reaction I have is “the filesystem is essentially Map<String, ByteData>, how would adding another abstraction layer _help_? How could it be impossible to migrate?” - you’ve been really informative, ignore my kvetching here, the kvetching side firmly holds if this was such a great idea _someone_ would have landed it _somewhere_ or there’d be more clear benefits stated than handwaving git and npm got it horribly wrong or more clear problems stated than “we don’t know how to migrate to it if we did it”
https://sqlite.org/fasterthanfs.html
I think it might be a lot more than that, on Windows and macOS.
Edit: Yeah, 5x boost on Win10. I wish author had included XP for reference!
Edit 2: Author achieved 14x boost with a certain SQLite mode, over Windows 10.
> The third chart shows that reading blob content out of SQLite can be twice as fast as reading from individual files on disk for Mac and Android, and an amazing ten times faster for Windows.
Already exists: https://github.com/narumatt/sqlitefs
No idea what the performance is like, though… it uses FUSE, so that is going to add some overhead compared to an in-kernel filesystem
Assuming you are using WSL2 (which is essentially Linux in a VM, unlike WSL1 which was a compatibility layer with processes running more directly on Windows) you will see this difference (any performance cost imposed by the VM will be small compared to the difference in process spin-up costs).
I don't think that this will apply to git, though.