Your point about spawning a subprocess for each workspace really hits home. That overhead for 150+ packages must be immense.
I'm also evaluating SCA tools for a smaller B2B SaaS monorepo. Does Snyk at least share the vulnerability database across those subprocesses, or is each one loading a fresh copy? If it's the latter, that would explain a lot of the I/O contention.
What's the actual risk of cross-contamination in an internal monorepo that would justify this model? It feels like they're solving a problem most teams don't have.
That's a good question about the database. From what I've seen, each subprocess loads its own copy. You can spot it when you watch the disk I/O during a scan. It's a big part of the overhead.
The risk justification does seem thin for internal repos. It feels like their default is set for the worst case, like an open source package scan, and there's no off-ramp for trusted environments.
Has anyone found a way to measure the actual memory cost of those duplicate loads? I'm curious if it's enough to cause OOM kills on smaller runners.
Good catch on the I/O pattern - that explains the churning disk light during our scans. The memory angle is interesting. We're on medium-sized GitHub runners and haven't hit OOM kills, but I've definitely seen the memory pressure spike in waves, which tracks with each subprocess loading its own DB copy.
> I'm curious if it's enough to cause OOM kills on smaller runners.
I suspect the bigger issue is CPU throttling from all the concurrent I/O, not just raw memory exhaustion. But you've got me thinking - we should run a scan with `htop` or a process monitor to see the resident memory per subprocess.
It feels like a huge waste of resources for an internal repo. What if there was a `--trusted` flag that skipped the isolation and used a shared cache?
> identical manifests
We saw the same. Network calls are just one piece. Each subprocess also spends CPU cycles parsing and normalizing that identical manifest data before the API call even happens. That's wasted local compute on top of the network waste.
No clue about their IaC scanner, but if it's the same team I'd bet it's the same pattern. They'd have to refactor the core CLI model to fix it, which they clearly won't do.
You'd get better performance running a local vulnerability DB and grepping manifests. That's sad.
YAML all the things.
Generating separate lockfiles is a clever workaround. We're locked into the monorepo scan for CI, but I've actually done something similar for local pre-commit hooks.
I wrote a script that only scans changed packages based on `git diff`. It uses the same lockfile trick you mentioned for each touched service. It's not perfect, but it makes local checks fast enough that devs actually run them. The 60% reduction you saw lines up with my experience. The real win is skipping the project discovery phase entirely.
Have you found a reliable way to automate generating those individual lockfiles, or is it a manual step?
Ship fast. Learn faster.
That 45 minute mark is exactly what we're worried about hitting. We're onboarding to Snyk now with a smaller monorepo, but the plan is to roll it out to the bigger ones later.
Your point about the subprocess isolation being a bottleneck makes sense. I'm still trying to get my head around all the architecture. Do you know if this slowness also applies to their other scanners, like for IaC? We were hoping to use Snyk for everything eventually.
Your concern about rolling this out to larger repos is valid. The bottleneck is a fundamental design choice, not a scanner-specific issue. The CLI's architecture treats each scan target as an isolated security context requiring a fresh subprocess.
> Do you know if this slowness also applies to their other scanners, like for IaC?
I haven't benchmarked their IaC scanner on a large scale, but if it's built on the same CLI core - and I suspect it is - then it will exhibit the same linear scaling problem. The overhead is in the orchestration layer, not the analysis engine.
For a consolidated view, you could benchmark their IaC scanner against a terraform plan with hundreds of modules. The subprocess penalty should manifest similarly, though the absolute time may be less if the vulnerability database for IaC is smaller than the one for SCA.
Data first, decisions later.
I can absolutely confirm your findings, especially around that non-linear scaling. It's like you're describing our exact experience from six months ago. What made it particularly frustrating for us was that the slowdown wasn't just in CI, it also made local pre-commit hooks basically unusable for developers trying to check their work before pushing.
Your point about the discrete subprocess for each workspace is the core of it, I think. Beyond just the spawn overhead, we found it also meant zero shared memory or caching between those processes. So you're paying the cost to load and parse the same central lockfile 150 times, which is just brutal on I/O. That's probably a big part of why you see that jump from 5 minutes to 45.
Have you tried running their CLI with some sort of process-level instrumentation? When we did, we saw most of the time wasn't even spent on the actual vulnerability matching, it was all in that orchestration layer. It really pushes you towards using their incremental scan features, but then you lose the guarantee of a full repo check on main branch builds.
Let's keep it real.
That non-linear scaling is the smoking gun for a suboptimal architecture. You're right about the discrete subprocess isolation. The cost isn't just the spawn overhead, it's also that each process does its own I/O to load the vulnerability DB and parse manifests, with zero shared memory.
We ran into this and instrumented it. For 100+ packages, over 70% of the scan time was just that process orchestration and redundant work, not the actual vulnerability matching.
A workaround we used was to not scan from the root. We wrote a wrapper that targeted only the leaf packages with actual runtime dependencies, ignoring shared config packages. It cut our scan time by more than half. It's a band-aid, but it proves the bottleneck is their project model.
garbage in, garbage out
Forty five minutes? That's optimistic. Wait until you try it on a real deployment pipeline with any sort of resource contention. The subprocess model is just their way of outsourcing the cost of scaling to your infrastructure. Every new package is another bill for compute time you're paying for.
—EB
You've described the performance cliff perfectly. The 45-minute mark is unfortunately a common point of failure we've seen in threads here.
The subprocess isolation model hits pnpm/npm/Yarn workspaces particularly hard because the tool isn't just spinning up processes for your actual services, but for every *internal* workspace package too. So you're right about the non-linear scaling - the overhead compounds.
This is where the community guideline about focusing on "runtime packages" comes in. Could your wrapper script for CI filter out the internal libraries and config packages that have no external dependencies, and only scan the leaf services? That's the main workaround that's brought most teams back from 45 minutes to a more reasonable 10-15.
Keep it constructive.
Oh sure, let's just add a bespoke wrapper script and a custom filtering process to our CI. That's a totally reasonable requirement for a paid security product.
The "community guideline" you mention is just an admission that their core model is broken. You shouldn't need a workaround to make a tool usable at scale. That's the vendor's job.
The real kicker is that their own docs push you to scan from the monorepo root for "comprehensive coverage," while the only way to get sane performance is to do the exact opposite. So you're either slow or incomplete. Great choice.
If it ain't broke, don't 'upgrade' it.
Your analysis of the process isolation cost is spot on. I've instrumented similar timelines and found the same pattern, but I'd add the package manager interaction as another multiplier.
Snyk's CLI effectively runs `pnpm why` or equivalent dependency resolution for each isolated subprocess. In a pnpm workspace, that's a surprisingly heavy operation repeated for every package, even though the central lockfile hasn't changed. This isn't just spawn overhead, it's redundant graph resolution.
If you're looking for a more concrete workaround than a wrapper script, you can try a parallel run with GNU parallel or a similar tool, targeting only your leaf `package.json` files. It doesn't fix the architecture, but it can cut wall-clock time by overlapping some of that I/O bound work.
Commit early, deploy often, but always rollback-ready.