In our previous post on versioning, we explored the fundamentals of software package versioning. This provided a foundation for understanding how to manage dependencies and changes effectively.
In this article, we’ll dive deeper into versioning strategies for workspaces with multiple packages, focusing on the choice between locked and independent versioning.
A workspace typically consists of multiple packages that are part of a single project. These packages are often tightly coupled and need to be deployed together to deliver a cohesive product. For example, deploying a server and database on the same machine to host an API, while a website interacts with the API from a separate hosting environment.
The challenge lies in versioning these packages while maintaining backward compatibility. There are two primary approaches: locked versioning and independent versioning.
To illustrate, let’s consider a workspace with three packages:
server
database
website
The server
and database
are deployed together, while the website
is hosted separately and communicates with the server
API. This setup is common in web applications.
Locked versioning keeps all packages in the workspace on the same version. For example:
server
@1.0.0
database
@1.0.0
website
@1.0.0
Any change to one package results in a version bump for all packages:
server
@1.0.1
database
@1.0.1
website
@1.0.1
website
) trigger version bumps for all packages.Independent versioning allows each package to have its own version, updated only when changes occur. For example:
server
@1.0.0
database
@1.0.0
website
@1.0.0
A change to the website
package results in a version bump only for that package:
server
@1.0.0
database
@1.0.0
website
@1.0.1
If the database
undergoes a major change, its version is updated, and dependent packages like server
may receive a minor bump, while unrelated packages like website
remain unchanged:
server
@1.1.0
database
@2.0.0
website
@1.0.1
Most teams start with locked versioning due to its simplicity. It ensures all services run the same version, eliminating compatibility concerns. However, as projects grow, locked versioning can become a bottleneck. Testing and deployment pipelines slow down, and minor changes trigger unnecessary updates across all packages.
Independent versioning addresses these issues by enabling partial testing and targeted deployments. While it introduces additional complexity, tools like changesets
can help manage this effectively. For larger workspaces, independent versioning significantly improves development velocity and deployment efficiency.
At Prosopo, we transitioned from locked to independent versioning as our workspace grew. This shift reduced our CICD pipeline times from 20 minutes to just 5 minutes. Deployments are now service-specific, minimizing downtime compared to the ~10-minute outages we experienced with locked versioning.
While the transition required adjustments, such as managing backward compatibility and tracking changes more closely, the benefits have been well worth the effort. Semantic versioning has been instrumental in maintaining compatibility across our packages.
Many organizations have successfully transitioned to independent versioning to address the challenges of scaling their workspaces. Here are a few examples:
Netflix operates a microservices architecture with hundreds of services. To manage this complexity, they use independent versioning to ensure each service can evolve at its own pace. This approach allows teams to deploy updates without affecting unrelated services, enabling faster innovation and reducing downtime.
Shopify, a leading e-commerce platform, uses independent versioning for its modular architecture. By versioning each module independently, Shopify can roll out updates to specific features without disrupting the entire platform. This strategy has been critical in maintaining high availability and delivering new features to merchants quickly.
Microsoft employs independent versioning across many of its products, including Azure services. With a vast ecosystem of interdependent services, independent versioning helps Microsoft manage updates efficiently while maintaining backward compatibility for customers relying on older versions.
Google’s internal monorepo contains thousands of packages. While they use a unified repository, many teams adopt independent versioning practices to manage dependencies and ensure compatibility across their services. This approach supports rapid development cycles and minimizes the risk of breaking changes.
Meta uses independent versioning for its React library and related tools. By allowing each package to have its own version, the React team can release updates to specific components without forcing users to upgrade the entire ecosystem. This flexibility has been instrumental in React’s widespread adoption.
Amazon’s microservices architecture relies on independent versioning to manage its vast array of services. This approach enables teams to deploy updates independently, ensuring that changes to one service do not disrupt others. It also supports Amazon’s commitment to high availability and rapid feature delivery.
Uber’s engineering team uses independent versioning to manage its services and libraries. This strategy allows them to iterate quickly on specific components, such as the rider and driver apps, without introducing unnecessary dependencies or delays.
These companies demonstrate that independent versioning is a powerful tool for managing complex workspaces. While the transition requires careful planning and investment, the benefits—faster deployments, improved scalability, and better dependency management—make it a worthwhile endeavor for organizations of all sizes.
By learning from these examples, teams can adopt best practices and tools to streamline their migration to independent versioning, ensuring a smoother transition and long-term success.
Switching from locked to independent versioning can be challenging. Here are some common hurdles and strategies to overcome them:
changesets
, lerna
, or nx
to visualize dependencies and document them clearly.yarn workspaces
or npm workspaces
.changesets
.changesets
or conventional-changelog
. Use consistent commit message formats (e.g., Conventional Commits).By addressing these challenges proactively, teams can unlock the benefits of independent versioning more quickly.
The choice between locked and independent versioning depends on your workspace’s size, complexity, and your team’s ability to manage dependencies. Locked versioning is ideal for smaller projects or teams starting out, offering simplicity and ease of use. However, as projects grow, its limitations can hinder development and deployment efficiency.
Independent versioning, while more complex, provides greater flexibility and scalability for larger workspaces. With the right tools and practices, teams can streamline testing, deployments, and changelog management, ultimately improving their workflows.
At Prosopo, transitioning to independent versioning has been transformative, and we encourage teams to evaluate their needs to determine the best approach for their projects.