Why Sphinx and RST are the best

Part 2 of my Hack Week recap

For comparison to the two newer tools (Antora and Docusaurus), I also ported my docs to Sphinx.

Full disclosure: I spent more than three years using Sphinx full-time at my last job. So while I am aware of some of the idiosyncrasies and difficulties of the tool, I'm used to them and know how to solve them.

Still, I ran through the whole installation process and used the quickstart generator to create a new project, and I was able to get a working site up within a few hours. This included the time it took to convert my Markdown docs to RST via Pandoc and then fix all the links.

Since I wasn’t exactly evaluating Sphinx as a brand-new user other than during the setup process, my experience was mostly a beautiful reunion between me and my favorite features of the Sphinx/RST tool set. This post will discuss several of these and other reasons why Sphinx remains the best tool for technical documentation.

RST features

Sphinx uses reStructuredText (RST) as its markup language. While it is different from Markdown, it is not as excessive as AsciiDoc.

The issue I've run into with RST is that people (*ahem* developers) are mystifyingly resistant to it. I've heard lots of complaints along the lines of "It's so much harder than Markdown." Again, I may not be the most representative user, but I do not find it much harder than Markdown. Furthermore, the documentation-specific features it adds are well worth it.

List tables

For this feature alone I would choose RST over Markdown any day.

Compare these two options for creating a table.

Markdown:

| Treat         | Quantity | Description                                                     |
|---------------|----------|-----------------------------------------------------------------|
| Albatross     | 2.99     | On a stick!                                                     |
| Crunchy Frog  | 1.49     | If we took the bones out, it wouldn’t be crunchy, now would it? |
| Gannet Ripple | 1.99     | On a stick!                                                     |

RST:

.. list-table::
   :header-rows: 1
   * - Treat
     - Quantity
     - Description
   * - Albatross
     - 2.99
     - On a stick!
   * - Crunchy Frog
     - 1.49
     - If we took the bones out, it wouldn't be
     crunchy, now would it?
   * - Gannet Ripple
     - 1.99
     - On a stick!

Imagine having to edit the first table? What if you added a cell that was longer than one of the existing ones, and had to realign all that ASCII art?

(Confession: I used an online Markdown tables generator to make the Markdown version. That's how much I didn't want to write it out myself.)

Toctrees

I've mentioned toctrees before, but they're honestly worth the price of admission for using RST and Sphinx.

Include a toctree in any file, list the filenames you want included, and just like that, Sphinx will build you a page hierarchy.

index.rst:

.. toctree::
   
   install
   getting-started
   release-notes/index

release-notes/index.rst:

.. toctree::

   v2.0
   v1.1
   v1.0

This creates the following hierarchy:

index
├── install
├── getting-started
├── release notes
         ├── v2.0
         ├── v1.1
         ├── v1.0

Dynamic linking with :ref: anchors (aka cross-references)

Specify an arbitrary text tag (ref), and then link directly to that tag. This works within files, across files, even across Sphinx projects with the intersphinx extension. You can rename or move files, and your link won't break. If you use a ref before a header, you don't even need to supply link text — it'll pull the header text automatically. (You may know this feature as "cross-references" if you're familiar with XML-based tools like Madcap Flare. But with Sphinx you don’t have to pay $1000 per seat for the privilege!)

Include external files

As mentioned under Antora, RST lets you specify the path to a file and pulls in content from that file. You can even specify line numbers to include only part of the external file, or specify tags if you've marked up the external file with the area to include. I've seen this used to great effect with code samples.

Variables

You can use the rst_epilog feature combined with substitution definition to define variables that should be available in every RST file. For example, you might use a variable for your support team's email address (if the email changes, you can update it in one place rather than all over your docs), the product name (I've been on many projects that rename their product once or twice during the development process), the end date for your copyright range, etc.

Additional code block features

In additional to language-specific syntax highlighting, Sphinx also gives you the option to highlight certain lines in a code block with the emphasize-lines parameter. In a tutorial, this lets you show code in context but still draw attention to the lines that the reader needs to add or modify. You can also provide a caption for the code block (for example, to display the name of the file the code should go in).

Theming

Swapping themes in and out of my Sphinx project was painless, and there are tons of options out there. You simply install a theme locally, then import it and invoke it in your conf.py file.

I also discovered that many of the features I admired in other documentation generators are possible in Sphinx with a different theme. For example, I like that Docusaurus's "next/previous" navigation buttons list the title of the next and previous page. Lo and behold, the Guzzle Sphinx theme does this as well.

Extensibility and wide use

As a more established tool, Sphinx has many, many extensions, themes, and cheatsheets available. The creators of Antora and Docusaurus seem active in supporting users on Github and Gitter/Discord, but for getting help, Sphinx still wins due to the vast amount of information (and StackOverflow answers) out there.

Conclusion

The combination of Sphinx+RST remains, for me, the most powerful documentation tool. If it were just up to personal preference, I’d choose it for our docs in a heartbeat. However, developer adoption is a major factor, and we may need to stick with Markdown to ensure that everyone is willing to contribute to the docs. (Then again, they might surprise me!)

An additional consideration is what language the tool is written in — the tech writing team can do some maintenance ourselves, but we largely rely on developers to set up the infrastructure for whatever documentation system we choose. So if our colleagues are more comfortable with Python or React, Sphinx or Docusaurus is going to be an easier sell.

There are still other tools we want to evaluate, so our search for the ideal docs solution isn’t over. But this experiment gave us more information on the kinds of issues we might experience when converting all our docs, and a better sense for how we value features versus complexity.