A little more than a year ago we realized that HubSpot’s application performance was impeding our users’ ability to complete basic tasks. A s a SaaS product that thousands of business across the globe rely on every day , this was un acceptable. For our CRM product , our core product offering which sees more than 50 million page views a week, a single page load could take upward of 6 seconds for our average user — in aggregate , our users were waiting more than 9 years for that single app to load every week. Since then, our efforts to improve performance have grown from just a few of us playing with code splitting and webpack settings in our free time to two dedicated frontend performance teams and organization-wide standards for creating performant applications.

More than a year ago a few colleagues and I began this push for performance and I’m now a member of our CRM Frontend Performance team. Here I’ll cover some of the decisions we’ve made and tools we use on a daily basis to help accomplish the mission of making the HubSpot product as fast as possible. This is not a technical post on how to improve performance, but rather a guide to the decisions made and tools utilized to empower the technical work.

Conscious Investment

Like many engineering challenges, performance is a goal that is all but impossible to meet without dedicated resources. This is a lesson we unfortunately learned from experience. While a few of us spent several months attempting to improve the speed of the applications we owned and evangelize the importance of performance work to the rest of the organization, we were making slow, if any, progress over the first few months. After more investigation , we discovered this was a resourcing problem. Engineers were interested in performance - they were showing up in droves to technical presentations, asking good questions about performance, and engaging in team-wide discussions daily — but simply didn’t have the hours to devote to extensive application profiling. There were more urgent tasks at hand.

Our solution was two-fold. First, we established a platform performance team. This team is responsible for building performance as a top-level citizen into our frontend stack, including everything from more robust synthetic testing solutions to empowering long-lived cross-application static asset caches. Once our platform team had their legs under them, we established a mirroring team on the application side in our CRM — the largest application in HubSpot. By giving full-time dedicated resources to one of the highest-visibility projects at HubSpot, we were able to create a sense of urgency across the organization. With these resources in place and a growing contingent of performance-focused engineers , it was time to get to work.

Tracking the Right Thing

Before we could start to think about our performance goals we needed to track our performance consistently. Out of the box solutions for monitoring proved to be unhelpful for modern applications, as they don’t understand the intricacies of single-page app frameworks like React. Instead of using browser events like DOMContentLoaded , which don’t know anything about the content in your application or your user's intent, HubSpot has created our own internal metric tracking system that marks pages as successful or failed based on the actual components on the page.

The exact implementation has evolved over the years, from our original solution based on CSS selectors to our latest solution which tracks the rendering of “markers” based on React Context , but the core philosophy that page loads are based on the actual content of your app is unchanged. An application team chooses what “success” means based on their own business concerns, but each team places these markers with the same guideline that a page is only successful once a user has all of the information they need to do their job.

Monitoring

We’ve stood by a core principle in our journey to make HubSpot fast for all of our users: you can’t make fast what you don’t know is slow. While it’s easy to anecdotally say “this app feels slow” or “this interaction has some lag to it,” you have no way to know you’re making progress if you don’t have numbers to attribute to your changes. Similarly, you might not even know what to change without tracking some metrics and profiling your application. Your teams may find value in all or only a subset of the methods below, but it’s important to try all of them to understand what works for you. Each of these types of tracking will answer different questions about your application, and will be applicable at different stages in your journey to make an application performant.

Synthetic Monitoring

While we’ve found limited value in synthetic monitoring of our application for tracking day-over-day performance regressions, it’s been incredibly helpful for telling us how our performance is trending over time. By running performance tests on the same hardware, network connection, and user account every single test run, we’re able to isolate environment changes that might cause shifts in real user data. These tests run with a cold cache on a regular interval to give us an easy way to track our page load performance over time.

A screenshot from SpeedCurve, HubSpot’s current synthetic monitoring solution

--