There's a moment in every growing engineering org where you realize the biggest bottleneck isn't the backlog — it's the fact that five different teams are solving the same problem five different ways. Different form validation logic. Different multi-step flow patterns. Different ways of watching viewport changes to trigger responsive behavior. None of it is bad code. But none of it talks to each other, and none of it compounds.
That's where I was when I started building FormGenerator, WizardBuilder, and viewportWatcher — a set of internal libraries that eventually became the default way product teams at our org built merchant-facing workflows.
I want to make the case that internal libraries aren't just a nice-to-have. For platform-minded engineers, they're one of the highest-leverage things you can ship.
The problem nobody files a ticket for
Product teams don't usually complain about repeated UI patterns. They're too busy shipping features. But the cost shows up everywhere: inconsistent merchant experiences, duplicated bugs, onboarding friction when engineers rotate between teams, and a general slowdown that's hard to attribute to any single cause.
The real problem is that without shared abstractions, every new feature starts from scratch. Not from zero — engineers aren't rewriting React from the ground up — but from a place where they have to make dozens of micro-decisions that someone on another team already made last quarter.
FormGenerator came out of exactly this. We had merchant-facing forms across multiple product surfaces, each with their own validation patterns, their own error handling, their own way of managing conditional fields. The logic wasn't complex in isolation. But multiplied across teams, it was a tax on every feature that touched a form — which, in a SaaS product, is most of them.
Building for adoption, not just functionality
Here's the thing most engineers get wrong about internal tooling: they optimize for the technical solution and underinvest in adoption. You can build the most elegant abstraction in the world, but if it requires a 40-minute onboarding session and a Confluence page that nobody reads, it's dead on arrival.
When I designed FormGenerator, I obsessed over the API surface. The goal was that a product engineer should be able to look at a usage example for 30 seconds and immediately know how to wire up a new form. Declarative config in, validated form out. No wrestling with internal state. No guessing about where to put error messages.
WizardBuilder followed the same philosophy. Multi-step flows are inherently stateful and messy — there's forward and backward navigation, conditional steps, progress persistence, validation gates between steps. Product engineers shouldn't have to think about any of that. They should declare their steps, define their validation rules, and move on.
viewportWatcher was a smaller tool but solved a surprisingly persistent problem: responsive behavior that goes beyond CSS media queries. When your UI needs to programmatically respond to viewport changes — collapsing navigation, swapping component variants, adjusting data density — you need a shared, performant observer. Not five different resize event listeners scattered across the codebase.
The compounding effect
The real payoff of internal libraries isn't the first team that adopts them. It's the third, fourth, and fifth team. Each adoption reduces the surface area for bugs, makes cross-team code reviews faster, and creates a shared vocabulary that makes architectural conversations more productive.
After FormGenerator and WizardBuilder became the defaults for our org, something shifted. Feature delivery got faster — not because the libraries were magical, but because engineers stopped spending cycles on solved problems. Code reviews got tighter because reviewers already understood the patterns. And when we needed to make a platform-wide change (say, updating validation behavior across all merchant forms), we had one place to make that change instead of hunting through a dozen repos.
This is what I mean by internal libraries being high-leverage. The value isn't linear. It compounds.
What I'd tell an engineer thinking about building internal tooling
First: start with the pain, not the abstraction. If you're building a library because you think it would be elegant, stop. Build it because you've watched three teams independently solve the same problem and you can feel the drag it creates.
Second: the API is the product. Spend more time on the developer experience than on the internals. Your consumers are other engineers, and they will judge your library in the first five minutes of trying to use it.
Third: don't ask for permission to build platform tools. Just build a small, useful thing and let one team try it. Adoption is the best business case. If it's good, people will pull it into their workflow. If it's not, you'll find out fast.
Fourth: own it after launch. Internal libraries without maintenance become internal liabilities. Budget time for documentation, bug fixes, and the occasional API evolution as the product grows.
The best platform work often looks invisible. Nobody throws a launch party for a form library. But when your entire org is shipping faster, more consistently, and with fewer bugs — that's the infrastructure doing its job.
Building internal tools that other teams depend on is one of the most rewarding things I've done as an engineer. If you're working on something similar, I'd love to hear about it — reach out on LinkedIn.