Copy-Paste vs a Shared Dependency: When Each Wins
Not every repeated piece of code belongs in a shared dependency. Here is how to decide between copy-paste and a shared library so your foundation compounds.
Copy-paste beats a shared dependency more often than engineers want to admit. A shared library is the right call when the logic is stable, correctness matters across every consumer, and a bug in one place is a bug everywhere. Copy-paste is the right call when the code is young, the two uses are only coincidentally similar, or the coupling a shared dependency creates would cost more than the duplication it removes. The skill is telling those apart before you commit.
I run a portfolio on a shared foundation, so people assume I share everything. I do not. Sharing has a price: every consumer now depends on your release cadence, your abstraction, your bugs. Some code is worth that price. Plenty is not.
When a shared dependency actually wins
Put something in the shared foundation when all three of these are true.
- It is stable. The interface has stopped changing. You are not still discovering what it should do. Sharing an unstable abstraction means you drag every consumer through every redesign.
- Correctness is shared. Auth checks, money math, date handling, input sanitization. A bug here is a bug in every product at once, which is bad, but it also means a fix is a fix everywhere at once, which is exactly the leverage you want. This is the category where standardizing auth, billing, and deploy once pays for itself.
- It repeats for real. Not "these look similar." Actually the same responsibility, in three or more places, with the same reason to change. That is the rule of three for shared code, and it exists precisely to stop you from sharing after two coincidences.
If it clears all three, share it, version it, and treat it like the product it now is.
When copy-paste wins
Copy-paste wins when coupling would cost more than duplication. The clearest case is early code that still wants to diverge. Two products render a settings page. They look alike today. If you extract a shared settings component now, the first time one product needs a different layout you will either fork it, poison the shared version with flags, or block the change behind a foundation release. All three are worse than having let each product own its own file.
Duplication is cheap to fix later. You can always extract a shared dependency once the pattern proves itself. Premature sharing is expensive to undo, because now you have to untangle consumers that assumed the abstraction. Wrong sharing is worse than no sharing. When in doubt, copy, and watch. If the same edit lands in three copies, that is your signal to extract, not before. This is the same instinct behind reuse vs rewrite on every project.
The coupling cost nobody prices in
A shared dependency creates a release relationship. Change it and you now own a rollout. You have to version it, communicate it, and make sure no consumer breaks. I described the discipline for that in versioning your shared foundation without breaking apps, and it is real work. That work is worth it for auth. It is not worth it for a card component that two apps happen to share and will inevitably want to style differently.
So price the coupling before you share. Ask: how often will this change, how many consumers, and what breaks when it does. If the answer is "rarely, everyone, and everything," share it and guard it. If the answer is "constantly, two apps, and I am not sure they even want the same thing," copy it.
The middle path: copy the code, share the tokens
You do not have to choose one for everything. Often the right move is to copy the component but share the design tokens underneath it. Each product owns its own markup and can diverge freely, but colors, spacing, and type come from one place, so the copies stay visually coherent without being structurally coupled. You get consistency where consistency compounds and freedom where coupling would hurt.
The test I use
Before anything enters the shared foundation, I ask one question: if this breaks, do I want it to break everywhere at once? For auth, yes, because I want to fix it everywhere at once too. For a marketing hero section, no, because the products should be free to differ and a shared bug there buys me nothing. Answer that honestly and most "should I share this" arguments settle themselves.
Getting this line right is most of what makes a foundation compound instead of calcify. Share the stable, correctness-critical core, and let the surface stay copyable and free. I keep that line clean across the portfolio using the build platform at Bootspring, where the shared core and the per-product surface live in the same workflow but with very different rules. Draw the line well and duplication stops being a sin. It becomes a tool.