The proof becomes the product
The proof is the architecture
Somebody asks for a demonstration. Prove the thing can talk to the other thing. Small ask, low stakes, and framing are what make it easy to get wrong.
Whatever the proof is built out of is what the product inherits. Not in principle. In practice, later, under a deadline, when nobody has room to reconsider.
The throwaway version is the trap. Prototype code written to be discarded gets shipped instead, because it works and the date is close, and the rewrite never gets a slot. So the realistic options are not "build-fast-then-rebuild" versus "build-properly”. They are: choose the architecture on purpose now, or choose it by accident.
Which layer the bet lands on
A dependency is a bet about which environments will stay available to you.
Most of the time that bet is free. Most products only ever run where the package assumed they would, and the dependency is pure gain.
It stops being free at exactly the layer a constrained deployment would have to reproduce. Air-gapped installs, regulated environments, on-premise, anywhere the network you assumed is not there.
The way to find that layer: ask what you would have to rebuild if the network went away. Then check whether you are about to put someone else's package directly underneath it.
The objection, taken seriously
This is designing for a requirement that does not exist, and that is usually a mistake with a well-known name.
The honest version: you pay a real cost up front against a possibility, and if the possibility never arrives, it was avoidable work. Being right about the future is not the defense, because you usually will not be.
What makes it defensible is the asymmetry. The cost of building it yourself is bounded and paid now, while you have time. The cost of swapping it out later is unbounded and paid during whatever crisis made it necessary — which is to say, rebuilding the interaction layer of a shipped product on somebody else's timeline.
Bounded-now against unbounded-later is a reasonable trade. Predicting the future is not.
Build primitives, not a screen
If you do build it, the shape matters more than the decision.
A screen is a demo. Hooks, utilities, state primitives, and components are a foundation, and they cost about the same to write the first time. The difference becomes apparent when the second surface requires the same behavior.
Be honest about what the reuse proves, though. If later surfaces build on your primitives, that proves the abstraction was at the right level. It does not retroactively prove the reasoning that motivated it.
And they only become leverage once they are documented and visually covered. Undocumented internal primitives are a package with no community, no issues, and no search results.
The cost
You own behavior a maintained package would have supplied. No upstream fixes, no community patterns, more surface to document, and every edge case in the domain is now yours to discover.
Chat is the standard example of why that hurts: it looks like one component, but it’s a dozen states that all have to agree. Message rendering, input, submission, waiting, success, API errors, and the unhappy paths that only appear to a customer. A package handles those, and that is not a small thing to give up.
When not to
If the product will only ever run where you can reach the internet, take the package. If the layer in question is not one a constrained deployment would have to reproduce, take the package. And if you cannot commit to documenting what you build, take the package, because an undocumented in-house foundation is worse than a dependency.