[Pitch] Documentation generation for any SwiftPM package

Introduction

With DocC now included in the Swift toolchain alongside SwiftPM, we have an opportunity to create tighter integration between these tools and streamline the documentation experience for Swift developers. This integration can remove friction from documentation generation and make high-quality API documentation accessible to the entire Swift ecosystem.

Motivation

Most SwiftPM packages today lack accessible documentation generation, creating a barrier for both package authors and consumers. While the underlying capability exists to automatically generate symbol graphs and produce polished HTML documentation for Swift libraries, accessing this functionality requires significant manual effort. Developers must add the DocC plugin to their package, configure command-line arguments for the sandbox environment, and understand the package's target structure well enough to specify the correct products and targets.

This complexity means that many valuable Swift packages remain undocumented, and developers exploring new packages often struggle to understand their APIs and capabilities. Swift developers should be able to generate comprehensive documentation for any package with a single command, regardless of their familiarity with plugin infrastructure or target configurations. This documentation can serve as both an entry point for understanding a package's capabilities and a solid foundation for building more comprehensive documentation over time.

The current friction particularly impacts newcomers to the Swift ecosystem and maintainers of smaller packages who may not have the time or expertise to navigate the current documentation setup process.

Proposal

Introduce a first-class SwiftPM command: swift package generate-documentation. This command automatically generates DocC archives in HTML for all package products and intelligently merges them into a unified, package-level archive that provides a cohesive browsing experience. The command handles the complexity of target discovery, symbol graph generation, and archive merging behind the scenes, requiring no configuration for basic use cases.

Here's the resulting interface that developers and package users would see:


β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 🍎 MyAwesomePackage Documentation                                    πŸ” Search  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                                 β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Navigator       β”‚ β”‚ Content Area                                            β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚                                                         β”‚ β”‚
β”‚ β”‚ β–Ό MyAwesome     β”‚ β”‚ # Package                                               β”‚ β”‚
β”‚ β”‚   Package       β”‚ β”‚ ## MyAwesomePackage                                     β”‚ β”‚
β”‚ β”‚   β”œβ”€ Networking β”‚ β”‚                                                         β”‚ β”‚
β”‚ β”‚   β”œβ”€ Utilities  β”‚ β”‚ A comprehensive Swift package for building awesome      β”‚ β”‚
β”‚ β”‚   β”œβ”€ UI         β”‚ β”‚ applications with networking, utilities, and UI         β”‚ β”‚
β”‚ β”‚   └─ Core       β”‚ β”‚ components.                                             β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚                                                         β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚ β”‚ 🌐          β”‚ β”‚ πŸ”§         β”‚ β”‚  🎨         β”‚        β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚ β”‚ Networking  β”‚ β”‚ Utilities   β”‚ β”‚ UI          β”‚        β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚ β”‚             β”‚ β”‚             β”‚ β”‚             β”‚        β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚ β”‚ HTTP client β”‚ β”‚ Extensions  β”‚ β”‚      UI     β”‚        β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚ β”‚ and helpers β”‚ β”‚ and helpers β”‚ β”‚ components  β”‚        β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚ β”‚             β”‚ β”‚             β”‚ β”‚             β”‚        β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚ β”‚ \[View β†’\]  β”‚ β”‚ \[View β†’\]  β”‚ β”‚ \[View β†’\]  β”‚        β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚                                                        β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                        β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚ β”‚ βš™οΈ          β”‚                                        β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚ β”‚ Core        β”‚                                        β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚ β”‚             β”‚                                        β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚ β”‚ Foundation  β”‚                                        β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚ β”‚ types and   β”‚                                        β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚ β”‚ protocols   β”‚                                        β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚ β”‚             β”‚                                        β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚ β”‚ \[View β†’\]  β”‚                                        β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                        β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚                                                         β”‚ β”‚
β”‚ β”‚                 β”‚ β”‚                                                         β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚                                                                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Package authors can enhance the auto-generated documentation by adding DocC catalogs (.docc directories) to their targets. These catalogs enable rich, custom content including tutorials, getting-started guides, and conceptual documentation that complements the automatically generated API reference. This approach allows packages to evolve from basic API documentation to comprehensive developer resources without requiring a complete documentation rewrite.

For executable targets that use Swift Argument Parser or are capable of generating a compatible tool-info JSON, the command automatically extracts the complete command-line structure and converts it into documentation-ready symbol graphs. This makes CLI tools as discoverable and well-documented as library APIs, bridging the gap between different types of Swift products. The command-line structure is intelligently mapped to Swift-like types that integrate seamlessly with DocC's rendering capabilities.

The --internal flag extends documentation generation to include internal targets that aren't exposed as public products. This feature proves valuable for open-source projects where contributors need to understand package architecture and implementation details, or for organizations documenting internal APIs for their development teams.

Impact on Existing Packages

Packages currently using the DocC plugin will continue working without any changes. The existing plugin takes precedence over this new command, ensuring backward compatibility. This means teams can migrate to the new approach at their own pace without disrupting existing workflows.

Packages without existing documentation infrastructure immediately gain access to documentation generation for both public and internal APIs. This eases documentation creation across the Swift ecosystem, particularly benefiting smaller projects and individual developers.

DocC catalogs and detailed API comments work seamlessly with both the existing plugin system and this new command. This compatibility means package authors can incrementally improve their documentation by adding doc comments, DocC catalogs, and enhanced CLI command/option/flag descriptions, with all approaches building on the same foundation.

Alternatives

The existing DocC plugin could be enhanced to incorporate some of these simplifications, particularly around target discovery and configuration defaults. However, this approach wouldn't achieve the same level of package-level integration or the seamless merging of multiple products into a unified documentation experience that this proposal enables. Also, it won’t remove the requirement to manually add the plugin to a package.

Future Directions

This foundation creates opportunities to extend documentation generation to additional product types that are becoming increasingly important in the Swift ecosystem, including Swift macros, package plugins, and potentially even test targets for packages that want to document their testing strategies and utilities.

We can expand DocC's API coverage to better support command-line interfaces with dedicated documentation patterns, moving beyond the current approach of mapping CLI structures to Swift types. This could include specialized API descriptions and rendering for command hierarchies, option groups, and usage examples that are more natural for command-line tools.

Future enhancements could integrate README.md content directly into package landing pages, eliminating the need for authors to maintain duplicate introductory content across readme files and documentation catalogs. This integration would create a more cohesive experience where a package's GitHub presence and its generated documentation tell the same story with consistent messaging and examples.

22 Likes

This seems slightly interesting but I do have a few notes,

  • Did you consider another command name like swift package docc build
  • Is this the place to suggest features for DocC like the README.md inclusion and a CLI interface
  • You don’t need to restate how DocC functions
    • Specifying that it generates a website
    • Explaining DocC Catalogues

In summary: Most of the proposal describes DocC’s precise functionality while it is irrelevant to explain in a pitch and it is overall unfocused.

You might need to workshop this pitch for a bit longer and cut out anything that isn’t a spec for a build command integration

3 Likes

I absolutely agree that this is an issue - and I run into it constantly myself, as I spend a LOT of time working with documentation on projects. Not having the equivalent of the docc-plugin immediately available is incredibly frustrating, and it often becomes extremely annoying to projects who, quite reasonably, do not want an additional dependency on their project that slows down builds when they don't need the docs to be a part of that process.

The fact that it is extra work to get easy docs is a massive friction point in the overall ecosystem that needs to be eliminated.

The how is a really good question. A year or so back I dug down this path, thinking that maybe there'd be a good option to have a set of Package Manager plugins that were "just available by default" - or that could be activated or installed by developers - specifically to provide command plugins like generate-documentation. That said, after making the pitch I didn't have the time to follow up and provide any prototypes or start implementing anything there.

Somewhere along the same timeframes, the other command plugin that I thought was really needed - swift format - got itself a bit more embedded in the toolchain directly, although the swift format command is still a "driver" command, and not the super-developer friendly option up front, which has been talked about elsewhere - orthogonal to this.

I'll also note that Dave and Sven, in providing packages for Swift Package Index, have to deal with the "is it added or not" scenario for the documentation builds as well, so anything we enable here would greatly ease being able to build, preview, and host documentation content.

I've also been wanting to see better integration with the swift-argument-parser tooling - the generation of markdown is nice, but it could be a lot easier and better, although that also needs some time and attention to enable.

And this is perhaps a bit more about about DocC and how it works than this pitch, I'd very much like to see a way to include content from the repository for some more edge use cases, particularly when it comes to Swift and other language interop (embedded, swift/java, swift/c or swift/c++). Today there's snippets - which are still tricky to use, and only work for Swift code. It would be very useful to be able to reference other content from the repository in some fashion that you could "include" into the DocC markdown content - be those C source code, README files, JSON snippets, and so on.

My real question is how are you seeing expanding this? A new and separate tool into the toolchain, potentially starting with swift-docc-plugin and its existing coordination with Swift Package Manager? Changing up the API exposed from SwiftPM to allow this in some other context? Enabling additional commands that don't require a Swift package dependency, but that can be included or downloaded into a toolchain or workspace?

I'm game, and I'd very much like to help and make this a reality, but I'm a bit stymied by the how at the moment.

4 Likes

Thank you for your feedback.

I think that it's important for me to highlight the title of this pitch, which is to generate documentation for any package, not just the ones that explicitly opt-in for it. The pitch certainly meanders a little. I can try to refine that more as this gets to the proposal stage. It was an attempt to try and cover the combination of factors to realize the vision.

One part of this is to make a simple command that will just generate the documentation, and the rest are various ways of ensuring that there is content for the package, whether automatically generated, or developer contributed content over time.

  • Did you consider another command name like swift package docc build

The ergonomics of a command goes down with each subcommand because it gets more and more buried inside the inner help of another subcommand. I am hoping to keep this at the third-level because it is swift, and specifically applies to packages. While DocC is the technology that is enabling this, it's documentation that the user is requesting and we can generate that for them. That's why I am pitching swift package generate-documentation.

  • Is this the place to suggest features for DocC like the README.md inclusion and a CLI interface

Both of these are ways to help and ensure that there is content for an arbitrary package. The former is a future direction because DocC doesn't yet have the support for it. The latter is something that can be done today for packages that are focused on executable products. The goal is to minimize the number of packages that would just show up as empty despite the effort that has already gone into them.

You don’t need to restate how DocC functions

Some of the intended audience of this pitch are people who aren't yet familiar with the DocC technology and terminology. Some are just SwiftPM package users that would like some documentation. I put in some introductory content along the way to try and fill in conceptual gaps. As a Swift developer for only about a year and a half, I didn't know the difference between a DocC catalog and an archive until after I re-read some of the documentation and familiarized myself more with the docc convert and docc merge commands. I didn't understand that there are both single and merged archives.

3 Likes

+1, could this also help improve the Preview Documentation feature in vscode-swift?

FWIW, there have been some improvements in this regard lately: Swift GSoC 2025 highlight: Improved code completion for Swift | Swift.org

1 Like

+1 on integration the DocC plugin directly into SwiftPM. The fact that currently developers have to manually add the plugin makes it an unnecessary friction point that is hard to discover. I think the proposal mixes two things at once though. The default integration of the plugin and the automatic documentation of CLI targets. I would love to see this split into two proposals to disentangle this a bit.

5 Likes

This is a very welcome improvement, and we should absolutely do it!

However, while one might dismiss this as β€œjust naming”, I do think the naming here is absolutely crucial and serves as the face of the general Swift ecosystem because docs is such a common task, as you rightfully pointed out!

Let us consider how other ecosystems approach this task:

  • go doc,
  • cargo doc,
  • sbt doc,
  • gradle javadoc,
  • or even the good ol’ maven: mvn scala:doc and mvn javadoc:javadoc respectively

I think it really matters that we have a simple, short, accessible name for this task. While I understand the swift package prefix argument and think that makes sense, the command itself we have to do better with IMHO.

Specifically, the β€œgenerate-” part of the command feels un-necessary and adds friction. Do I really need to spell out every time that I want to β€œgenerate” docs? Yeah, it’s the docs command, what else would it be doing :slight_smile: It also forces us into multiple words and having to write a - even.

I would argue we should embrace the shortened form of either:

  • swift package doc,
  • or alternatively swift package docc if we want to go the β€œthe tool name” route, which is similar to the javadoc command in gradle builds.

This goes beyond just a name IMHO, it really matters a lot how these common tasks are performed in Swift; they are the β€œface of Swift” in many ways, because it’s the first things people interact with when β€œpoke around to check out the language”.

We sometimes err on the side of very verbose unconventional names which scares away developers used to other tools (see all the above languages, this task is a simple one), and I have heard many complaints about Swift tools having weird naming choices in the past when helping others adopt Swift, so I’d like to focus on improving this moving forward.

–

+1 about the compatibility with tools where the plugin was already added, that sounds like a safe approach to roll out the change throughout the ecosystem.

24 Likes

I am personally against hardcoding one specific documentation generator and enforcing one specific documentation plugin on all packages, which severely restricts the choice for package authors and makes all other documentation generators as second class.

But considering a position of having one "blessed" documentation generator, I do agree with Konrad that swift package generate-documentation is incredibly verbose and defeats the whole point of tight integration. In fact, I find swift package doc or swift package docc just as verbose.

Were swift docc or swift doc considered at all? What necessary information does that package noun in the command even convey if the only possible way to generate documentation is to have a well-formed package? What would be the reason for adopting a longer name for something that's described as a common workflow, assuming you're going with a tighter integration with one documentation generator in the first place?

7 Likes

Yes, that would be even better honestly – same as swift test isn’t really usable without a package. If we do already have blessed verbs, might as well embrace that.

Nothing is stopping someone from building swift package cooldocs if they wanted to, but it’s not β€œthe one shipping with Swift”; I think it’s fine to embrace the fact if we’re shipping one, that yes, it is the default one.

8 Likes

Swift test uses the test frameworks out of the toolchain. You usually don’t need a package.

That said. I would then compare it to swift build where you specify a --build-system argument to select which build system to use. Mind you that’s an extreme since the build systems aren’t pluggable through packages (maybe they should be :slight_smile:).

I think swift doc provides the best ergonomics for users. We can add options if they want to use a different documentation generator. And it would be good for documentation generator providers to be able to tag their generators in their package manifest so we can cleanly add them as options.

Anyway, lots more to consider here. Let’s make sure if we’re going to change things up that we take as much as we can think of into the solution.

4 Likes

Huge +1 to this - the fact that you can’t just generate documentation for a package/library/application like you can for every other ecosystem is a huge shortcoming.

And I do like swift doc with appropriate flags/options to generate it for external hosting, preview it etc

5 Likes

There are quite a few top-level commands that are package-specific, currently build, experimental-sdk, run, sdk and test. The SDK ones technically do not need a package for all their functionality, but they’re still pretty much there to provide content for consumption of the other SwiftPM commands.

It sounds like we are converging on a command that's much shorter. Since there are precedents for putting important behaviours like run, and build that are specific to packages in the top-level it seems reasonable to me to put a package-specific command there, so this could be swift generate-docs to make this shorter and more discoverable. It also has the nice side effect of being completely decoupled from the existing DocC command plugin invocation.

When considering other language documentation generators, such as go doc, there's sometimes a difference between outputting the documentation to standard output vs "generating" an HTML site. Not all languages support both, and maybe Go is an outlier. I'm thinking that it would be strictly be the latter, but perhaps there could be an expectation that it would be the former. That's why I think that the verb is important there to make this a little clearer.

I'm a big fan of this pitch.

I personally favour swift doc or swift docs. My expectation is that running the command will allow me to view the documentation for consumption, whatever the format may be.

Also, I prefer having all the documentation related commands in a single location. Maybe the swift doc can have subcommand to generate and view, with the default being view. That is, running swift doc would be equivalent to swift doc view. Having a single swift doc also consolidates all the documentation related commands in a single viewable location.

To also support folks that want to use another generator, maybe we can add some sort of extendability to the documentation command that would allow external packages to implement a Documentation provider based on a SwiftPM API. This appears similar to what @dschaefer2 said in the above post.

4 Likes

The basic idea of SPM supporting docs is attractive.

Supporting basic documentation for commands and libraries by convention (i.e., with minimal configuration) sounds magical and seems possible.

Supporting extended documentation variants sounds difficult, and would seem to involve configuring all types of deployments. I’d hate to see SPM, which already has a fairly wide ambit, take this on.

It sounds like a lot of work, and valuable only if it is used. First, it’s not clear that easier doc building would result in more docs (i.e., is that really the gating factor?). Also, people already use docc as a command and a plugin, and they already invested into their docc approaches. Would they switch? Still, I think the main and winning argument is that if documentation were always buildable for any package, developers would be more likely to write and evolve that documentation. (Just realize that creates a large population of developers wanting some new customization to be rolled into the conventions.)

I wonder if docc itself is better positioned than SPM as a tool to evolve and support documentation conventions. In that case, docc would define and implement the conventions. Then any SPM integration would just consist of calling docc with some flag to assume package conventional configuration (possibly passing the relevant package config to avoid docc re-building it). The docc effort probably has the expertise and domain skills to develop documentation-related conventions, and they could better manage feature evolution.

If a fuller proposal elaborated the landscape of potential conventions, people could assess where the work belongs and whether conventions truly can replace configuration for a reasonable subset of projects.

More generally, I appreciate that SPM owns package declarations, but think it a better model to be able to delegate to other tools at a high level rather than SPM itself implementing every feature reachable from any declaration in any package. If SPM defines a package configuration model/json schema it will pass to delegate tools, that’s a clean boundary susceptible to local and remote usage and tool evolution independent of SPM. (Part of what made Maven ubiquitous and easy to extend (and gradle successful as a variant) was adhering to this delegation pattern.)

Yeah, we’re slowly getting better for sure :slight_smile:

I hear your concern but I don’t think the β€œgenerate” verb is as load bearing, and I still very much would like us to remove the generate-.

I can’t imagine a developer coming to Swift come to the idea that to generate docs they need to swift gen<tab> auto-complete their way through the very long name, starting with β€œgenerate” especially. We can always have different options, modes, sub-commands in the docs command itself. doc (or similar) is truly common enough and used frequently, that the lack of a verb in the command really should not be an accessibility problem IMHO.

If we are indeed considering a top level command on the same level as test and run, it only remains to think about doc or docc. I don’t think this matters as much though, either is short, memorable, and easy to β€œdid you mean…”-hint. docc is kinda sneaky way to introduce people who’d type swift doc to β€œoh yeah, the tool is docc” which I guess is cute, but not really particularly great reason.

6 Likes

Yes, proposed swift generate-docs also breaks the precedent for our swift <noun> <verb> CLI. We write swift sdk install not swift install-sdk. Grouping subcomands under their respective subjects is good for discoverability too. To understand what you can do with Swift SDKs, it's as simple as swift sdk --help. Similarly for docs, you'd get it in swift doc --help output.

At the same time it would be natural for swift doc without any verb subcommands to just do the most common expected thing: generate docs for a package.

7 Likes

A big +1 for swift doc or swift docs with optional subcommands for verbs, with preview being the default.

6 Likes

Definitely a +1 for the pitch overall, is building documentation for multiple platforms (macOS, iOS, watchOS, tvOS, visionOS) a consideration at all? Or are they ignored because they’re outside the scope of SwiftPM?

2 Likes