●MAX — Rork Max generates native Swift for iPhone, iPad, Apple Watch, Apple TV, and Vision Pro, with 2-click App Store publishing and no Xcode required●STACK — Standard Rork builds cross-platform mobile apps with React Native (Expo); choosing between the two by use case is the key decision●FOCUS — Unlike web-first tools such as Bolt or Lovable, Rork specializes in native iOS and Android app generation●BUGS — A hands-on review reports Rork resolved about 70% of bugs without manual help, with the remaining 30% needing edits in the exported codebase●FUNDING — Rork raised $2.8M from a16z (Andreessen Horowitz)●PRICING — It is free to start, with paid plans from $25/month, so you can try before committing●MAX — Rork Max generates native Swift for iPhone, iPad, Apple Watch, Apple TV, and Vision Pro, with 2-click App Store publishing and no Xcode required●STACK — Standard Rork builds cross-platform mobile apps with React Native (Expo); choosing between the two by use case is the key decision●FOCUS — Unlike web-first tools such as Bolt or Lovable, Rork specializes in native iOS and Android app generation●BUGS — A hands-on review reports Rork resolved about 70% of bugs without manual help, with the remaining 30% needing edits in the exported codebase●FUNDING — Rork raised $2.8M from a16z (Andreessen Horowitz)●PRICING — It is free to start, with paid plans from $25/month, so you can try before committing
Auditing the Dependencies Rork Generates: A Supply-Chain Hygiene Routine
Even a four-screen Rork app pulls in 900+ transitive dependencies. Before a vulnerability lands and you cannot tell which app is affected, build an audit habit with npm ls, npm audit, overrides, and depcheck — framed for running several apps at once.
I once idly counted the node_modules in an exported Rork project. It was a small app, about four screens. Even so, the installed packages numbered over 900. I recognized maybe a dozen of them by name.
The actual request had been "let the user pick a photo and save it." Rork chose the libraries needed for that, each of which dragged in the libraries it depended on internally, and the total landed at 900. This is not Rork being careless; it is the everyday reality of modern JavaScript development. The problem arises when you carry that everyday reality across several apps as a solo developer.
I run several wallpaper and wellness apps in parallel. When each one carries hundreds of transitive dependencies, the day a vulnerability surfaces in some library, you can no longer tell at a glance which of your apps is affected. Precisely because the AI chooses the dependencies, you need a habit of taking inventory of what was chosen.
Below is the audit routine I actually run to keep the dependencies in Rork-generated apps from quietly expanding your supply-chain risk, alongside the exact commands.
First, make visible what you depend on
The first step of an inventory is to look at direct and transitive dependencies separately. What lines up in package.json is only the direct dependencies; the real risk hides in the transitive ones hanging beneath them. Even in a small app, it is not unusual for transitive dependencies to make up nearly 90% of the total.
I check the direct dependencies by limiting the depth to one level.
# List only direct dependencies (collapse transitive ones)npm ls --depth=0# Count the total including transitive dependenciesnpm ls --all --parseable | wc -l# Reverse-trace WHY a specific library is presentnpm why <package-name>
That last one, npm why, is especially effective. When you find an unfamiliar package, you can trace back which direct dependency dragged it in. Discoveries like "an old compression library came in as a chain reaction for this image library" start here.
Sweep for vulnerabilities once a week, mechanically
After visibility comes checking for known vulnerabilities. I run this with no judgment involved, mechanically on a fixed day each week.
# List known vulnerabilities with severitynpm audit# Auto-fix only within non-breaking changesnpm audit fix# Fail CI on high severity and above (decide by exit code)npm audit --audit-level=high
The thing to watch is not running npm audit fix on impulse. Add --force and it will apply compatibility-breaking major updates all at once, a pitfall that leaves your production build unable to compile. I target only high and above, confirming the impact of each update before taking it in.
When you have several apps, it helps to bundle this weekly sweep into one script.
#!/usr/bin/env bash# audit-all.sh — check vulnerabilities across all apps at onceset -efor app in ~/apps/*/; do echo "===== $(basename "$app") =====" ( cd "$app" && npm audit --audit-level=high || echo "vulnerabilities need attention" )done
Running this once over the weekend tells you, in one list, which apps need attention. Just moving vulnerability response from "when I remember" to "a weekly inspection" sharply cuts what slips through.
✦
Thank you for reading this far.
Continue Reading
What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.
WHAT YOU'LL LEARN
✦A workflow that separates direct from transitive dependencies with npm ls and npm why, and reverse-traces how an unfamiliar package got in
✦A script that runs a weekly npm audit across all your apps, plus a severity filter that avoids breaking production builds with --force
✦Pinning transitive versions with overrides, removing unused dependencies with depcheck, and why native SDKs need their own separate ledger
Secure payment via Stripe · Cancel anytime
✦
Unlock This Article
Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.
A common trait of AI-generated projects is loose version ranges in package.json. With ^ or ~ left in place, when you npm install on a different day, a transitive dependency quietly shifts to another version. A build that worked yesterday fails today without a single line of code changing — and that is often the cause.
The key to reproducibility is the lockfile. Always commit package-lock.json, and in CI use ci rather than install.
# Install strictly per the lockfile (reproducibility first)npm ci
On top of that, when you learn a specific version of a transitive dependency has a known problem, pin it precisely with overrides.
overrides is the mechanism for overriding the version of a library you do not depend on directly. It lets you swap out a vulnerable transitive dependency ahead of time, without waiting for the parent library to update.
Trim unused dependencies on a schedule
Another pitfall audits often miss is dependencies that remain even though you no longer use them. As you ask Rork to regenerate again and again, libraries used in past implementations can stay behind in package.json.
# Detect dependencies that are no longer referencednpx depcheck
For anything depcheck flags as "unused," I confirm with a code search that it is truly safe to delete before removing it. Unused dependencies needlessly widen your attack surface and also add noise to vulnerability alerts.
Keep native SDKs in a separate ledger
Looking only at JavaScript dependencies leaves a blind spot: the native SDKs for ads (AdMob) and purchases. These enter through a path separate from the npm dependency tree, and they also affect your App Store privacy manifest.
For native SDKs, I keep a ledger separate from JavaScript dependencies that tracks version, purpose, and the privacy declarations involved. npm audit will not look here, so you have to follow the SDK vendor's release notes by hand. Because ad-SDK updates tie directly to eCPM and review requirements, this is the one place I recommend checking the changes with your own eyes rather than leaving it to automation.
Turn the audit into a habit
Finally, here is how I keep the steps above sustainable. I run them at the following cadence:
Weekly: run npm audit --audit-level=high across all apps via the script
Right after asking Rork for a new feature: check the added dependencies with npm ls --depth=0 and npm why
Monthly: inventory unused dependencies with depcheck and regenerate the lockfile
Once you fix the cadence, dependency auditing changes from "a spring cleaning when the mood strikes" into "a quiet inspection." Precisely because this is an era where the AI chooses dependencies, I feel the role of periodically reviewing what was chosen stays with the indie developer.
Aligning dependencies across apps makes one audit cover all
Once you run several apps as a solo developer, each tends to carry a slightly different version of the same library. One app on the image library's 5.x, another on 6.x — let that drift and every single vulnerability means re-investigating all your apps separately.
To avoid this, for the foundational libraries I use often, my policy is to align versions across apps. The React Native and Expo SDKs, image processing, state management — absent a specific reason, I pin all apps to the same major line.
# Compare a specific library's version side by side across all appsfor app in ~/apps/*/; do printf "%-20s " "$(basename "$app")" ( cd "$app" && npm ls expo --depth=0 2>/dev/null | grep expo@ )done
If the versions line up in this list, investigating a vulnerability is a one-time job. If they do not, I converge them gradually at the next update. Aligning the foundation looks like overhead, but the more apps you have, the more it lowers the cost per audit. For native SDKs like AdMob, keeping versions aligned the same way lets you handle App Store review responses in one batch.
Your next step
On a Rork app you have on hand, first run npm ls --all --parseable | wc -l. That number is the breadth of the supply chain you are implicitly trusting. Knowing the number is the first step of taking inventory.
Share
Thank You for Reading
Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.