Hero image for "The Code You Own Is the Code You Also Have to Fix Yourself"

The Code You Own Is the Code You Also Have to Fix Yourself


Here's the sentence that should give every shadcn adopter pause: a breaking change in Radix forced one team to audit 120 copied files by hand (techpotions). Not a npm update and a changelog skim. A manual audit, file by file, because the whole point of the copy-paste model is that nobody's package manager is watching those files anymore.

That's the trade everyone signs up for with shadcn/ui, often without reading the fine print. You don't npm install a component library — you run a CLI command that copies the component's source into components/ui/, and from that moment it's yours: your repo, your git blame, your bugs to fix (dev.to). I've written before about composition patterns that survive contact with a real product, and this is the same tension at the distribution layer instead of the API layer: ownership versus upkeep.

Ownership Solves the Wrong Half of the Problem

The pitch is genuine. You stop fighting an abstraction layer that wasn't built for your exact use case. No hunting for a prop that doesn't exist, no theme override that only touches color, no forking a library because the animation is hardcoded three components deep (dev.to). That's a real, specific kind of pain for teams running an installed library, and shadcn genuinely removes it.

But ownership was never the hard half of component library maintenance. Distribution was. An npm package gives you a one-line way to pull in a fix somebody else made. Copy-paste code gives you none of that by default — which is exactly why the ecosystem has spent 2026 quietly rebuilding the thing shadcn was supposed to let you skip: a registry you can run npx shadcn add against to re-sync code you already copied (untitledui.com). useLayouts, built by an independent maintainer and picked up by Vercel's Open Source Program, exists specifically as a shadcn registry rather than an npm package, for the same philosophical reason — you still copy it in, but at least there's a sanctioned channel for getting it (dev.to).

Look at the react-jsonschema-form maintainers wrestling with this exact fork in a GitHub issue: should their shadcn theme ship as an npm package, or as a shadcn registry entry? An npm package can't import the app's own components/ui/ — it has to ship duplicate copies of the same primitives, so the app ends up with two buttons living side by side. The registry route gets the files into the app in the app's own style, but it means every fix the maintainers make has to be re-pulled manually, file by file, forever (GitHub). That issue is basically shadcn's whole ownership model playing out in miniature, argued by people who have to ship a real library against it.

The Upstream Floor Still Moves Under You

The clearest evidence that "you own it" doesn't mean "it's insulated" landed in July, when shadcn switched its default primitive layer from Radix to Base UI. Existing projects were untouched, and Radix stayed fully supported — but asChild became render, anchored popups gained a Positioner layer, and Overlay became Backdrop, all silent-breaking or build-breaking depending on which part of the component you touched (dev.to). If you'd copied in fifteen dialogs before July and wanted the new Combobox or Number Field that only Base UI ships, you weren't getting an upgrade — you were doing a migration, component by component, on code with no record of what it was derived from.

This is the part the "you own it" framing glosses over: ownership doesn't mean isolation from the ecosystem you copied from. It means the ecosystem keeps moving, and you've lost the tooling that would otherwise tell you it moved.

Pick the Model Based on Who's Going to Do the Auditing

None of this makes the npm model categorically safer. MUI's ThemeProvider turns every route into a client component under the App Router, trading one kind of debt (bundle weight, forced hydration) for the kind shadcn avoids entirely (techpotions). Mantine sits in between, with a lighter provider but similar client-component pressure on interactive pieces (techpotions). Every model has a bill. The only real question is which currency you're paying in — JavaScript you ship to users, or engineering hours you spend re-syncing code six months from now.

If your team ships one component a week and nobody owns a "check upstream for breaking changes" calendar reminder, the copy-paste model will quietly accrue the same kind of debt a badly governed wrapper layer does — just distributed across more files, with less of a paper trail. If you've got the discipline to track a registry's changelog the way you'd track a dependency's, shadcn's model is a genuinely better trade. The honest answer isn't "own your code" or "rent your code." It's knowing, before you choose, who on your team is going to read the Base UI changelog the next time the default moves.