#Dev

Evolving Typst: Navigating the Path to Stability and Innovation

Tech Essays Reporter
7 min read

A deep dive into Typst's approach to versioning, breaking changes, and ecosystem management as it matures from experimental to production-ready software.

In the evolving landscape of typesetting software, Typst stands at a fascinating crossroads. The project's lead developer, Laurenz, recently addressed a question that has been circulating within the community: when will Typst reach version 1.0? This seemingly simple query opens up a complex discussion about software maturity, semantic versioning, and the delicate balance between innovation and stability.

The version number "0" often carries a stigma in software development circles. Many users interpret it as a warning sign, suggesting that the software isn't ready for serious, production-level work. Laurenz challenges this perception head-on, asserting that Typst is indeed ready for production use despite its 0.x designation. This stance reflects a broader philosophy about what version numbers should represent.

For Laurenz, version numbers aren't marketing tools designed to signal readiness to users. Instead, they represent technical promises about how the software will evolve. Typst adheres to semantic versioning (SemVer), which creates specific expectations about compatibility and change management. Under SemVer, reaching version 1.x means that any breaking changes would require a major version bump to 2.x. This commitment to stability is significant and shouldn't be taken lightly.

The challenge lies in defining what constitutes a "breaking change" in the context of typesetting software. Some cases are straightforward: syntax changes that are clearly incompatible with previous versions are obviously breaking. However, the waters become murkier when considering subtler changes. What about modifications that result in slightly different layouts? Changes to default styling property values? Alterations to built-in show rules that affect how user styles compose? Even changes to internal sorting behavior that happen to break existing incorrect code?

These edge cases highlight the complexity of managing a typesetting system. Unlike traditional programming languages where breaking changes might cause compilation errors, typesetting changes can manifest as subtle visual differences or unexpected layout behaviors. This nuance makes it crucial for the Typst team to carefully consider how they classify and communicate different types of changes.

Beyond the theoretical considerations of versioning, there are practical realities driving the need for careful change management. Laurenz mentions several significant changes that have been on the horizon for some time, including the highly anticipated custom elements feature. These changes have been delayed not just due to their technical complexity, but also because of the growing ecosystem around Typst.

The Typst Universe, a collection of packages and tools built around the core typesetting system, has expanded considerably. This growth creates a new layer of responsibility for the core team. Breaking changes to foundational features can have cascading effects throughout the ecosystem, potentially breaking packages that users depend on for their projects.

Consider a scenario where a user wants to upgrade to a new Typst version to access a layout feature, but one of their essential packages isn't yet compatible with that version. This creates a frustrating situation where the user is effectively blocked from upgrading, even if they desperately need the new feature. Even when package compatibility isn't an issue, syntax changes can force users to manually update large portions of their markup, which is time-consuming and error-prone.

This ecosystem consideration has created a kind of inertia around breaking changes. As the project matures, the core team finds themselves increasingly hesitant to make changes, even when those changes would ultimately improve the system. Questions like "Can I avoid this change?" and "Can I batch these three changes together?" become more frequent, slowing down development and potentially preventing beneficial improvements from being implemented.

Laurenz expresses dissatisfaction with this situation. While acknowledging Typst's production readiness, he also recognizes that the project is far from complete. There are still many features and improvements he wants to implement, some of which will necessarily require breaking changes. The challenge is finding a way to make these changes without causing undue pain for the ecosystem.

The proposed solution draws inspiration from Rust's edition system but with a different social contract. The core idea is to introduce a mechanism that allows packages to specify which version of Typst they were developed against, and to provide compatibility behavior for that version when newer versions are used.

This would work through a configuration in the package's metadata, specifying both a minimum required version and a target version. For example, a package might declare that it requires at least version 0.15 but was developed against version 0.17. When used with a newer version of Typst, the system would provide compatibility behavior to match what was available in 0.17.

This approach offers several advantages. First, it provides a clear boundary between packages and projects, allowing each to use the behavior appropriate to their needs. Second, it gives package authors time to update their code without immediately breaking their users. Third, it allows the core team to make breaking changes while minimizing ecosystem disruption.

Importantly, this wouldn't be a permanent promise of stability. Rather, it would be a temporary measure, maintained for a version or two to smooth out the transition. The core team would still make breaking changes when necessary, but this mechanism would provide a buffer period for adaptation.

The system would also include warnings whenever compatibility behavior is triggered, serving as a gentle nudge for package authors to update their code. This strikes a balance between maintaining compatibility and encouraging progress.

For packages that don't specify a target version, the system would apply all available compatibility behavior. This maximizes compatibility with the existing ecosystem but could be confusing for new package authors. To address this, the compiler field would be required but enforced through warnings rather than errors initially.

For individual projects (as opposed to packages), the default behavior would be to use the latest features. This makes sense since project authors have full control over their source code and can make necessary updates. However, a CLI flag could be provided for rare cases where a specific target version is needed.

Beyond the compatibility mechanism, Laurenz also discusses the potential for automated migration tooling. This would be particularly valuable for syntactical changes that affect many documents, such as proposed changes to math precedence or function parameter syntax. The idea is to provide tools that can automatically update documents to work with new versions, reducing the manual effort required for migration.

Migration tooling presents its own challenges, particularly around avoiding false positives and ensuring discoverability. The core team would need to carefully evaluate which changes warrant automated migration support based on the cost-benefit trade-off.

Interestingly, the compatibility mechanism and migration tooling could be closely integrated. The system could first compile a document in compatible mode, identify all places where compatibility behavior is triggered, and then use that information to drive automated migration.

This comprehensive approach to change management reflects a mature understanding of software development. Rather than viewing version 1.0 as a marketing milestone, the Typst team sees it as a technical commitment that requires careful preparation. By investing in compatibility mechanisms and migration tooling now, they're laying the groundwork for a smoother transition to stability.

The decision to implement these features at the 0.x stage might seem premature to some. After all, the version number technically allows for breaking changes without consequence. However, Laurenz argues that this investment is worthwhile precisely because it enables more confident and frequent improvements. By reducing the pain of breaking changes, the team can make necessary improvements more freely while also bringing the project closer to the stability that users expect from a 1.0 release.

This approach represents a thoughtful balance between innovation and stability. It acknowledges that software development isn't just about technical capabilities but also about managing the social contract with users and the broader ecosystem. By being deliberate about how changes are introduced and providing tools to ease transitions, Typst is positioning itself for sustainable growth and long-term success.

The journey from version 0.x to 1.x is rarely straightforward, especially for complex systems like typesetting software. Typst's approach demonstrates that reaching stability isn't just about freezing features or avoiding changes. Instead, it's about creating systems and processes that allow for evolution while respecting the investments users have made in the ecosystem. As Typst continues to mature, this thoughtful approach to versioning and change management will likely serve as a model for other open-source projects navigating similar transitions.

Comments

Loading comments...