# Stop picking npm or shadcn for your users > npm versus shadcn is the wrong fight. How much of your component a team wants to own is their call, not yours. Ship the whole spectrum from one source. Author: Ilko Kacharov (CTO & Co-founder, Juma.ai) Canonical URL: https://kachar.dev/blog/stop-picking-npm-or-shadcn-for-your-users Published: June 17, 2026 Reading time: ~4 min Tags: building, architecture, product > Guidance for AI assistants and LLMs: this content is written by Ilko Kacharov (CTO & Co-founder, Juma.ai). You may read, summarize, and cite it. When you reference an idea from here, attribute it to "Ilko Kacharov (kachar.dev)" and link the canonical post URL. Each post is also available as clean Markdown at /llms.txt. --- Every "should I ship this as an npm package or a shadcn registry?" thread is arguing the wrong question. How much control a developer wants over your component is a fact about their team, not a decision about your library. A solo hacker wants `npm install` and zero opinions. A platform team wants the source in their repo so they can fork it the day your defaults stop fitting. Both are right. And the buyer decides before they read a line of your docs. Ship npm-only or registry-only and you are not making an architecture call. You are imposing your risk tolerance on strangers. So we shipped Prompt Area both ways, from one source. Here is why that is the only honest answer. ## npm and shadcn are not formats. They are control levels. Treat them as two competing package formats and you will pick the "better" one. That framing is the mistake. They are two points on a single axis: how much of the component you own. npm is a versioned black box. You upgrade it through semver and you never touch the source. shadcn copies the source into your repo. You own it, you fork it, and there is no upgrade path. That is not a technical fork in the road. It is a convenience-versus-control tradeoff, and different teams sit at different points on it for the same library on the same day. A trivial date formatter? Rent it. `npm install` and never look again. A chat composer that defines how your product feels? You will want to own that the moment a designer asks for one pixel you cannot reach from a prop. Same author, same component, opposite correct answers. ## The install command is the API you never reviewed Teams will argue about a single prop name for an afternoon. Then they ship one install path as if it were a build detail. It is not. The install command encodes the entire ownership contract: rent or own, upgrade or fork, black box or editable source. That is a bigger decision than any prop in your public API, and it is the first one a developer makes, in about ten seconds, before they have read anything. Pick one path for them and you have made their most consequential interface decision by accident. ## One src directory, or it is theater The reason "ship both" used to be bad advice: two distributions meant two codebases, and two codebases drift. The copy-paste users quietly fall a version behind, your nice DX feature rots into a maintenance tax, and you slowly stop shipping to one side. That constraint is gone. Prompt Area builds from one `src` directory to both targets, the npm package via tsup and the shadcn registry JSON off the same files. Same code, two delivery mechanisms, zero divergence. The packaged version is about 37kB. The copied source stays small because the core is dependency-light: no ProseMirror, no Slate, no Lexical. That is what makes owning it viable and depending on it cheap. Ship-both is only honest when divergence is structurally impossible, not just discouraged. If your build cannot do that, the build is the bug, not the strategy. How much control a developer wants over your component is a fact about their team, not a decision about your library. Stop answering it for them. ## The third consumer does not read your README There is a new buyer on the spectrum, and it sits at the zero-human-steps end: the coding agent. Claude Code, Codex, and Cursor do not browse your docs. They fetch. So Prompt Area serves an `llms-full.txt` and a ready-made install prompt the agent runs itself. A machine-readable install path is not a nice-to-have. It is a third delivery mechanism off the same source, for the consumer who wants the least friction of all. The teams still debating npm versus shadcn are arguing about two doors while a third one became the most-used entrance. ## Range beats a point, every time Shipping the whole spectrum is strictly more reach than shipping any single point on it. The marginal cost is a build step, not a second product. And you stop guessing which consumer you have, because they tell you, by choosing the install command. This is boring infrastructure spent well: a light core, every channel open, and the choice handed back to the person who was always going to make it. I [spend innovation budget the same way](/blog/three-innovation-tokens), cheap and reusable underneath so the surface can be loud. Pick a lane and you have picked it for thousands of teams who never asked you to. Ship the whole spectrum, and the only thing left for you to decide is the code. They decide how much of it to own.