People don’t write manpages anymore. This is partially because of Google being a more common first line for help, but it’s also because people are scared to write them.

Most of the tools for generating manpages are complex, or generate weird output. They’re actually easy to write by hand. This is a crash course in (badly) writing simple manpages by hand.


Manpages have a “section” number. Command-line tools are section 1, file formats are section 5. You’ll probably only write section 1 and 5 manpages.

Basic Syntax

Manpages are written in a language called roff, troff, groff or something similar.

It’s a little like Markdown, in that text can be wrapped however you want, but a blank line makes a new paragraph. Unlike Markdown:

You can write comments using \", like:

\" comment

roff has “macros”. These are lines that start with a . and then a couple of letters. The only ones you need to worry about are .TH, .SH, and .BR.

Manpage Format

The basic structure is:

  1. .TH line
  2. NAME section
  3. SYNOPSIS section
  4. DESCRIPTION section
  5. More sections, more details

(For section 5 manpages, only 1 and 2 apply. These are more free-form.)


The first line is just .TH, your tool name in all-caps, and the manpage section. For example:

\" or


One line: .SH NAME, then another line: your tool name and a very brief description. It should fit on one line:

secret\-sender \- send passwords over slack


Look at other manpages for reference on how the general use of bold and underline goes, and use \fB\fR and \fI\fR. If you have multiple different invocation forms, you can separate them with a line containing .BR. Example:

\fBfind\fR \fIpath\fR [\fIexpression\fR]
\fBfind\fR [\fB\-H\fR] \fIpath\fR

This renders looking like:

find path [expression]

find [-H] path


Just write text here. You often use this space to document all the different command line flags you support, which you can do a lot like in SYNOPSIS.


None of what’s described here is a very good way to write manpages, but it gets the job done. If you want to do something fancier, there’s a lot of reference material at /usr/share/man/man1.

Full Example

secret\-sender \- send passwords and tokens manually over insecure channels
\fBsecret\-sender\fR send
\fBsecret\-sender\fR receive
\fBsecret\-sender\fR requires two users to run the program at the same time in
cooperation, and paste messages at each other as a communication medium. These
messages are not secret, so can be pasted on (e.g.) Slack.

Under the hood, \fBsecret\-sender\fR uses NaCl Box cryptograpy, or
curve25519xsalsa20poly1305. The receiver generates an ephemeral keypair and
sends the public portion to the sender, who encrypts the secret to that key,
before sending the ciphertext to the receiver.  The receiver then recovers the
plaintext and terminates, discarding the private key.

Neither subcommand takes any arguments, but both ask for user input. Scripting
this is discouraged: Use \fBejson\fR directly.
Invoked when a user wants to send a secret to another user, \fBsecret\-sender
send\fR first asks for the public key generated by the user running
\fBreceive\fR, then prints the encrypted secret to send to the receiver.
Invoked when a user wants to receive a secret from a sender, \fBsecret\-sender
receive\fR prints a public key to send to the sender, then waits for the
returned ciphertext from the sender, which it decrypts immediately before