Design System Infrastructure

Building an Enterprise Design System, Part 2

Matt Felten
Sep 5, 2019 · 10 min read

This is part of a series on the journey ServiceTitan took establishing their design system Anvil.
Part 1:
Why a design system?
Part 2:
Design System Infrastructure

You spent weeks preparing a presentation convincing your boss that a design system will have a huge ROI and increase product development efficiency. You had a big meeting with the Head of Design, the CTO, and CEO and explained how every hour spent saves 5 hours of isolated teams rebuilding the same components over and over again. There were cheers and applause, maybe some high fives, and an all-important, “This sounds great. Let’s do it.”

Then the next question you get is, “So how do we do this?” The hard answer to that question is that every company is unique. Your design system will look completely different than Polaris or Carbon or Canvas because they have different problems, tools, and needs. Regardless of what your system ends up looking like, they all come from a similar starting point. First, an audit of what your company is currently doing, and second, a plan for how the design system will exist. That’s exactly where we kicked off this new project. Here’s an in-depth look at all our considerations and thought processes.

Design Tool Audit

The 10 person product design team at ServiceTitan had already been using Sketch for design work and Zeplin for doing handoffs. That seems pretty standard for a product design team. We additionally looked at some other design tools like Figma, Framer, Adobe XD, & Axure.

They also just transitioned projects over to Abstract to keep everything in a shared space. Abstract is such a cool tool. It allows us to have a tight syncing with Sketch’s native Libraries feature. Among other things, it supports version controlled Sketch Symbol Libraries which will let designers opt-in to new versions on a per-project basis.

We decided that the best workflow is the one the team is already using. All of the tools we evaluated are doing really interesting things in the space but more or less didn’t have enough features to offset the cost of making designers learn new tools. Adopting the Sketch + Abstract workflow let us have a much easier jumpstart into the teams existing workflow. All it took was introducing a new library and showing the team how to add it to their projects.

Code Audit

There was also already a rough plan to use semantic-ui-react as a base for the new design system. The codebase was using a combination of Bootstrap, Semantic, and Material Design in different sections of our giant enterprise app. After interviewing the engineering team, we discovered the team was having trouble solving conflicts between those libraries.

On one hand, using a framework will save time up front. That’s good. On the other hand, you’re locked into that system. After doing a component audit, you can easily evaluate if a framework will be able to support all your needs. In all the frameworks we looked at, they all simultaneously have more than we need in some ways, and less in others. There was no perfect solution here. After a lot of discussions, we changed our plan away from using semanitc-ui-react (thank the stars).

Leverage existing frameworks when it makes sense

We decided that no single framework will solve our problems but that didn’t mean we couldn’t leverage some of the work already done to help us start. If we import and reskin components smartly, we can mix and match the parts of each framework we need with our own custom components where it makes sense. That means we could use form components from Semantic UI and icons from Material Design for instance.

Source of Truth

  • Where do edits happen to components?
  • Should design files be referencing code or should code be referencing design files?
  • Where do usage guidelines live?

There are several ways we could go about this so we evaluated all these questions to put into our plan.

Design as the Source of Truth

That opens up the possibility that if component change isn’t communicated, the interface might not actually represent what is in our design files. A component change might be interpreted as a new component and be made differently, making the UI more fragmented. It also makes usage documentation only available to coworkers who have access to design tools.

Code as the Source of Truth

The same questions get raised by this method as with design files being the source of truth. If design files are just representation of code, if a component changes visuals or behavior because of a bug fix or accessibility improvement, how does that change get communicated back to the design team? Also having documentation in code is in a lot of ways out of reach for most of the company.

Two Sources of Truth

We really spent a lot of time thinking about the tradeoffs of each of these. There are different scaling and maintenance issues involved in each. We went back to the drawing board and thought about what the ideal solution would be for a hypothetically perfect system.

Holy Grail

We explored tools like react-sketchapp and html-sketchapp and found that we were able to make a pretty functional prototype of a code-to-sketch workflow. This would allow us to have our code be the source of truth, since that’s what our users will see after all, and also our design team would get perfect 1-to-1 representations of all of our components in their tool of choice. Yes, we would still need to check what is being generated to make sure it looks good, but would be a lot less work than trying to double check how every single change affects the visuals of our components.

We decided to pursue this idea. We decided that for the long-term growth of the project, it makes sense to invest time up front to make sure we can solve any out-of-sync issues that could arise. This does mean that designers have a little more friction getting design changes into the system, but it ensures when a change is made, it is represented in our design files and to our users.

This was such a major hurdle to solve but isn’t everything. We still need to figure out where our usage guidelines live. Since we’re using both code and design tools for our system where is the best place for those to live?

Usage Guidelines

We found a tool called Catalog that is a static site generator for documenting design systems. It supports a lot of really useful features (called specimens) to allow for live code examples, responsive viewports, simple color and type displays, and a bunch of other cool features. Each page is written as Markdown so it’s easy to add new sections and examples with the most minimal amount of code knowledge.

In about a day we had a pretty good first-pass at an in-sync component documentation tool that could be published to our internal network. This would allow not only designers, but also engineers and product managers the ability to see how components should be used to provide the best experience for our customers.


  • A React component library that is a combination of custom components, and components pulled from third-party frameworks
  • Our html-sketchapp tool to convert those React components to symbols in Sketch. That tool generates a file that can be imported into Sketch using a custom plugin. We can then check that file into Abstract which distributes it to our design team as a shared library.
  • Our Catalog documentation site which is also using those React components in live examples to show best-practices.
Design System Infrastructure
├── catalog/
│ ├──
│ ├──
│ ├──
│ └──
├── design-system/
│ ├── component-1.tsx
│ └── component-1.tsx
├── symbols/
│ └── sketch-library.js
├── third-party-library-2/
│ └── component-4.js
└── third-party-library-2/
└── component-4.js

We made a new repository in GitHub and used a code tool called Lerna to keep each of these separate projects working in sync with each other.

Another perk of organizing our system this way is that if we end up replacing a third-party, we can pull that out easily because it’s completely separate. If our design team wants to move away from Sketch, we can pull that part out and figure out what to replace it with. If we want to jump to a different documentation tool, we can. Everything is modular and always in sync.

I’ll go into it in more detail in another blog post, but with this infrastructure we have set up, releasing a new version of the design system is as simple as publishing it to NPM, checking in the symbols to Abstract, and publishing the documentation site. The only manual task we have to do is checking into Abstract. Otherwise it’s all pretty automated.

Design Systems Are Hard

Also keep in mind that tools change frequently, the needs of your company changes and grows, the team working on it has a breakthrough (or breakdown…) and changes the workflow. The best way forward is to stay nimble — make it as modular as you can. You can’t be too protective of what you’ve done because 6 months from now, you might need to tear it all down for some new hotness anyway. Every step forward is a success and helps you plot your course to your next success.

Iterations Since Launch

Iteration on Infrastructure

We also added a new project to generate tokens. Tokens are small variables or design decisions that can be used across multiple components to keep them consistent. As an example, you can have a token for border radius that then is used by your Buttons, Form Fields, and Cards. If you update that border radius token, all of those components will automatically update with your new setting. This also allows our engineering team to use the same tokens in custom non-system components so that they still align with the system principles.

We’re currently hiring Design Technologists to work on Anvil, our design system, as well as Product Designers to create world-class enterprise experiences for the home services industry. Check our careers page or reach out on Twitter.

ServiceTitan Design

Insights and opinions from ServiceTitan’s design and…