Building the Future of Our Desktop Apps

April 7, 2021 Published by Spotify Engineering

For the past couple of years, we’ve been on a mission to modernize our Spotify clients by creating one single desktop UI for both the Desktop application and the Web Player.

We couldn’t build everything we wanted to for our users with our old setup, so we decided to do something about it.

In the beginning, there were two clients

Towards the end of 2018, our team was the owner of a recently built Web Player, as well as Spotify’s Desktop client. The Desktop was our rich, full-featured experience and the Web Player was a much lighter, simpler experience.

Because the Web Player was implemented with a modern React app architecture, we had success onboarding new engineers to the Web Player code. But those same engineers were having difficulties with the Desktop client, which used a very diverse range of web technologies (thanks to Conway’s law). Due to having to implement many of the features twice at different levels of complexity while dealing with context switching, we were not shipping new features at the pace we would have liked to.

In addition, there were accessibility issues in our clients that we needed to solve. We discovered that making our Web Player accessible was going to be a difficult, yet achievable, challenge. Making the Desktop application accessible, in contrast, would be nearly impossible.

We had many discussions on how to solve these problems. The team figured out that converging the clients into a single codebase and user experience would be the best way forward. We considered several approaches and did tech spikes to test many of the ideas — component sharing, feature sharing — always trying to find the right balance between fixing our technical debt problem while continuing to improve the experience for our users.

We knew we were embarking on a long-term project, so our biggest priority was to de-risk delivery and avoid trapping ourselves into a big bang rewrite. We settled on a bold solution: focus on iterating on top of the existing Web Player codebase until it reached a Desktop-grade feature set. Since our Web Player is continuously deployed, we could ship and test with real users every change made towards our final goal.

There were risks, of course. Desktop had (and has) many more users than Web Player, and Spotify’s Desktop client is the place most of Spotify’s “power users” call home. We knew we would have a lot of work to do to bring our Web Player up to those power users’ exacting standards.

Now, at the beginning of 2021, we have created one maintainable codebase for both of our clients with the high standard of accessibility and speed of development we hoped for.

Let’s talk more in detail about how we turned the idea into reality.

One UI, multiple containers

The Spotify Desktop client is a Windows and Mac native application that uses CEF (Chromium Embedded Framework) to display a web-based user interface. That’s still true today, but for the previous version of Desktop, every “page” in the client was built as a standalone “app” to run inside its own iframe. This architecture was designed to foster autonomy, allowing multiple teams — and potentially partners — to own the development and maintenance of the features. Eventually, however, one team became responsible for the user interface of the entire application.

Previous architecture (simplified) of the Desktop client. Each page in the application would be sandboxed in an iframe and built in different ways. The UI would access the backend through the native container.

The previous version of the Desktop client had many strengths, including Spotify’s original “killer feature” from its very first client, which would allow playback to begin as soon as a listener clicked. It also boasted a comprehensive set of features we know Spotify listeners value. But, at the same time, this architecture was causing severe friction for developers.

The Web Player’s codebase, however, was considered a much more solid foundation to build upon. It allowed us to develop new features quickly. It was developed with the web in mind, meaning it was small in size, more performant, and worked with various browsers. The client was delivered continuously, allowing changes to get to users almost immediately. We decided, then, to use the Web Player as the starting point for a single user experience shared between the Web Player and Desktop. One of the main challenges we encountered was that this approach would require us to ship and run the Web Player UI with the Desktop container.

The Web Player was also tightly coupled to our web servers, relying on them for all data and authentication. The playback system used by Web Player was not compatible with Desktop. Authentication worked differently — we needed to support our web OAuth login on Web Player and our native login on Desktop. Desktop would also need features its users expect, such as downloading and offline playback, that are not supported by the Web Player.

This concept of running the same user interface on two similar but different infrastructures is what informed the architecture we developed. In order to keep the UI platform agnostic, we built TypeScript Platform APIs that would abstract the different sources of data and different playback stacks, as well as provide helpful information to the user interface about what functionality was available to it. We also rewrote the whole client in TypeScript along the way, as we were rebuilding the experience bit by bit.

While work was done outside of our team to make certain kinds of data available via the web, we focused on decoupling the Web Player not just from the web servers but also from any hard-coded dependencies from being run in a normal browser.

The final architecture looks like a layer of Platform APIs that expose the underlying Spotify ecosystem to clients, with a React-based user interface and the Platform APIs exposed via React Hooks. Thus, the new UI can run on the web, and it can run in our Desktop container, and never know, or care, if the data is coming from our C++ stack or our web infrastructure.

The new architecture of Web Player (left) and Desktop (right) clients. The UI is built as a React application that reaches the backend through our GraphQL and Web API services, and in some cases achieves this through the native Desktop APIs due to their increased performance and capabilities.

With this architecture in place, the team’s velocity began increasing rapidly. We added downloading, offline mode, local files, lyrics, a “Now Playing” queue, as well as advanced features such as sorting and filtering of playlists and albums. In just over a year, the new shared UI included all the features of the original Desktop client and was, in some areas, actually more advanced, including features previously seen only on the mobile client.

Old vs New: the Web Player UI has come a long way since the project started.

Solving the organizational challenge

From the moment we decided on the product strategy for the new Desktop client, we began work on solving the engineering challenge — but there was also the organizational challenge: how could we actually make this happen in a reasonable amount of time without dropping the everyday “business as usual” work that needed to continue?

There was also a large information gap we had to solve. What features in the existing Desktop application had to be implemented in the new one? What should the new client look like? Almost immediately the design and product insight teams began to investigate how our users use our software, so that we could draw up a road map towards being able to ship.

At the same time we created a small “virtual team” made up of engineers from several teams to begin the very first engineering experiments and answer some fundamental questions: Was the desired solution even possible? How much work would it actually require? This virtual team’s priority was simply to get the Web Player, as it was, running inside the Desktop container. They would solve the problem of playback and authentication, explore how the UI was bundled with the container, and set the engineering blueprint for the rest of the project. The team was aided by other teams within Spotify to create a single UI that could run on multiple platforms having different capabilities — for example, televisions. The fact that both codebases were co-located in the same monorepo as a result of previous efforts to converge the clients was key to facilitating this task.

After three months, the team’s work concluded successfully. We established our roadmap and priorities, and we knew exactly what we would be doing for the upcoming year. It would require a full commitment from everyone on our wider team, with constant testing and analysis to ensure we were on the correct path. 

In reality, this project only happened because of the commitment of our engineering, design, and product management teams to envision a product that engineers could iterate on quickly, and that would fully support the Spotify vision. We had to iterate longer than we’d hoped before shipping to users, but the speed at which the team was able to implement these features in the new shared UI is what gave everyone the confidence that we were heading in the right direction.

Evaluating success

We had four primary goals at the start of this project: make our code reusable, unify our user experience and visual design, improve speed to deliver more quickly, and do all of this while meeting Desktop and Web Player users’ needs. With the results of the project now shipped, how have we performed against these metrics?

1. Reusability

Reusing the same code in multiple clients (i.e., the Web Player and Desktop) allows us to write the code once and reap the benefits in multiple places. When we need to implement a design change, it’s much more efficient to make it in one location and have it propagate to all receiving endpoints. We would like to expand our reusability in the future, sharing more of our Platform APIs with even more clients.

2. Unification

User experience and visual design are important yet time-consuming areas to improve within an application. Thus, having one set of components that service multiple clients ensures that we can implement designs more thoroughly, thereby improving our users’ experiences.

Critically, we have been able to achieve a degree of unification with the rest of the Spotify ecosystem, moving our clients to Spotify’s shared design language. The result is a more consistent experience when users switch between mobile and desktop, as well as a more modern, contemporary, accessible, and user-oriented experience for everyone. 

3. Speed

An important justification for this project was the argument that a modernized codebase with a single, easy-to-understand architecture would increase our velocity as engineers. While we need more time to conclusively prove success in the long term, the large number of features the team has already completed since the project began is a positive indicator. Speed, however, is merely an outcome — the result of engineers with clear goals working with a healthy codebase. We measure code health in terms of test coverage, maintainability, readability, and how easy code is to remove. The architecture we chose had unexpected benefits in terms of making UI coding simpler and easier to understand as developers, and so we are hopeful this platform is going to be a solid foundation for us to build on in the years to come.

4. Satisfaction: Meeting Desktop and Web Player user needs

The new experience has been developed with Spotify users in mind — both existing Desktop power users, and new users coming from the mobile app or completely new to the Spotify ecosystem. From the very beginning, we’ve been evaluating and testing our progress at each step to make sure we deliver an experience that fulfills our users’ needs. We’ve conducted extensive user research and run continuous tests over the past year that have informed us of the direction we should take. We’ve made the experience more accessible than ever, so everyone can enjoy using the application.

We are looking closely at the feedback received and are continuously shaping the application to satisfy users’ needs. The new architecture lets us move faster, and users can expect the client to evolve more quickly than ever before.

What does all this mean for you as a user?

As a music listener using the Spotify Desktop client or Web Player, we hope it feels like a fresh new experience, but with all the features you use and love still there. You’ll notice a few new features that you might have seen on Spotify on mobile appearing for the first time too.

As time goes on, you’ll begin to notice brand-new features appearing more often, making your experience of music and podcasts even better. The launch of the new Desktop, for us, is not the end. It’s just a new beginning for the app that started everything here at Spotify.

Is this your jam? Join us!

Want to join the band and build the future of Spotify? Head over to our job board and see if anything catches your eye. We’ve just announced our Working From Anywhere policy, which allows employees to choose whether they want to work from home full time, at the office full time, or a combination of the two.

A shout out to everyone who contributed to this project, especially Felix Bruns, Peter Johansson, Alberto Núñez Acosta, Guido Kessels, Tryggvi Gylfason, Craig Spence, Lucas Lencinas and Emma Bostian.