Documentation style guide

The nRF Connect SDK documentation is written in two formats:

  • doxygen for API documentation

  • RST for conceptual documentation

RST style guide

See Zephyr’s Documentation Guidelines for a short introduction to RST and, most importantly, to the conventions used in Zephyr. More information about RST is available in the reStructuredText Primer.

The nRF Connect SDK documentation follows the Zephyr style guide, and adds a few more restrictive rules that are described below.

Titles and headings

Keep titles and headings as short and to the point as possible.


Mention the module name in the title and within the RST tag of the page, which is defined in the first line of the RST file. For example:

1 .. _lib_aws_fota:
4 ########

Do not repeat the section name in the titles of the subpages. For example, when adding a sample or library, do not mention sample or library in the title of the page.

Correct title

Incorrect title

nRF9160: Secure Services

nRF9160: Secure Services Sample

DK Button and LED

DK Button and LED library


Headings use sentence case, which means that the first word is capitalized, and the following words use normal capitalization. The only exception are proper names, for example Bluetooth specification terminology (see last entry in the following table).

Correct heading

Incorrect heading

CC file format

CC File Format

Sending shell commands

Sending Shell Commands

GATT Human Interface Device (HID) Service Client

GATT Human Interface Device (HID) service client

Do not use consecutive headings without intervening text.

RST file formatting

For readability reasons, start every sentence on a new line in the source files and do not add line breaks within the sentence. In the output, consecutive lines without blank lines in between are combined into one paragraph.


For the conceptual documentation written in RST, you can have more than 80 characters per line. The requirement for 80 characters per line applies only to the code documentation written in doxygen.

The sentences must not end with a space. Trim trailing spaces before committing your changes.

Each RST file must end with one blank line.

Content highlighting

Use the following highlighing rules in the RST conceptual documentation:



Usage criteria



Emphasis or new terms.


west update

Code within text.



PCB names.



Clickable graphical user interface elements.


Filenames, file paths, directory names, and file extensions.


Do not use the following markup for italics: `..`.

For readability reasons, do not use any code highlighting for titles of other pages or headings when they are mentioned in the text. For example, do not write “The bl_crypto library”. Use the complete name of the library: “The bootloader crypto library”, and always link to the page you mention. If the page you are linking to is mentioned several times in the text, place the link on the first occurrence and on every occurrence where linking to the page is useful.


You can include Message Sequence Chart (MSC) diagrams in RST by using the .. msc:: directive and including the MSC content, for example:

.. msc::
    hscale = "1.3";
    Module<<Application      [label="nrf_cloud_connect() returns successfully"];
    Module>>Application      [label="NRF_CLOUD_EVT_TRANSPORT_CONNECTED"];
    Module>>Application      [label="NRF_CLOUD_EVT_USER_ASSOCIATION_REQUEST"];
    Module<<Application      [label="nrf_cloud_user_associate()"];
    Module>>Application      [label="NRF_CLOUD_EVT_USER_ASSOCIATED"];
    Module>>Application      [label="NRF_CLOUD_EVT_READY"];
    Module>>Application      [label="NRF_CLOUD_EVT_TRANSPORT_DISCONNECTED"];

This will generate the following output:

msc {
hscale = "1.3";
Module<<Application      [label="nrf_cloud_connect() returns successfully"];
Module>>Application      [label="NRF_CLOUD_EVT_TRANSPORT_CONNECTED"];
Module>>Application      [label="NRF_CLOUD_EVT_USER_ASSOCIATION_REQUEST"];
Module<<Application      [label="nrf_cloud_user_associate()"];
Module>>Application      [label="NRF_CLOUD_EVT_USER_ASSOCIATED"];
Module>>Application      [label="NRF_CLOUD_EVT_READY"];
Module>>Application      [label="NRF_CLOUD_EVT_TRANSPORT_DISCONNECTED"];


You can use different linking and inclusion methods, depending on the content you want to link to.


The Breathe Sphinx plugin provides a bridge between RST and doxygen.

The doxygen documentation is not automatically included in RST. Therefore, every group must be explicitly added to an RST file.

.. doxygengroup:: bluetooth_gatt_throughput
   :project: nrf


Including a group on a page does not include all its subgroups automatically. To include subgroups, list them on the page of the group they belong to.

The Breathe documentation contains information about what you can link to.

To link directly to a doxygen reference from RST, use the following Breathe domains:

  • Function: :cpp:func:

  • Structure: :c:type:

  • Enum (the list): :cpp:enum:

  • Enumerator (an item): :cpp:enumerator:

  • Macro or define: :c:macro:

  • Structure member: :cpp:member:


The :cpp:enum: and :cpp:enumerator: domains do not generate a link due to Breathe issue #437. As a workaround, use the following command:



Kconfig options can be linked to from RST by using the :option: domain:



If you need to repeat some information, do not duplicate the text. Use the .. |tag| replace:: command to reuse the text. Whenever you use the tag in an RST document, it will be replaced with the text specified after the colons.

You can reuse the content with the same tag either on one page or on multiple pages:

  • To reuse the text on one page, define the |tag| and the replacement text between the page tag and the page title.

  • To reuse the text on multiple pages, define the |tag| and the replacement text in nrf/doc/nrf/shortcuts.txt.

For example, see the following code sample taken the source of this page:

1 .. _doc_styleguide:
3 .. |sg| replace:: style guide
5 Documentation |sg|
6 ##################
8 The |NCS| documentation is written in two formats:

In this case, the |sg| tag is defined for local usage. This tag is not available on other pages. Additionally, the example is also using the |NCS| tag that is defined in shortcuts.txt and can be used on all documentation pages in the nRF Connect SDK project.

PCB names

When referring to specific Printed Circuit Board elements, use capitalization. For example, Button 1, Switch 3, LED 1.

If you are referring to a generic PCB element, do not use capitalization: button, switch, LEDs.

If you want to provide the short name of a specific PCB element as printed on the board, write it in bold and follow the spelling and capitalization from the board: Button 1, SW3, LED1.


Use bold for button elements only when you are using the short names for other PCB elements in your document.


Follow Zephyr’s Documentation Guidelines for tables. Do not add table titles to describe the table. Instead, make sure to introduce the table with a short sentence that describes the table contents. For example:

The following table lists something.

.. list-table::
    :widths: 15 20 40
    :header-rows: 1

    * - Heading 1
      - Heading 2
      - Heading 3
    * - body row 1, column 1
      - body row 1, column 2
      - body row 1, column 3

Doxygen style guide

This style guide covers guidelines for the doxygen-based API documentation.

General documentation guidelines

  1. Always use full sentences, except for descriptions for variables, structs, and enums, where sentence fragments with no verb are accepted, and always end everything with period.

  2. Everything that is documented must belong to a group (see below).

  3. Use capitalization sparingly. When in doubt, use lowercase.

  4. Line breaks: In doxygen, break after 80 characters (following the dev guidelines). In RST, break after each sentence.

  5. @note and @warning should only be used in the details section, and only when really needed for emphasis. Use notes for emphasis and warnings if things will really really go wrong if you ignore the warning.

File headers and groups

  1. @file element is always required at the start of a file.

  2. There is no need to use @brief for @file.

  3. @defgroup or @addgroup usually follows @file. You can divide a file into several groups as well.

  4. @{ must open the group, @} must close it.

  5. @brief must be added for every defgroup.

  6. @details is optional to be used within the defgroup.

 * @file
 * @defgroup bt_gatt_pool BLE GATT attribute pool API
 * @{
 * @brief BLE GATT attribute pools.

#ifdef __cplusplus
extern "C" {

#include <bluetooth/gatt.h>
#include <bluetooth/uuid.h>

 *  @brief Register a primary service descriptor.
 *  @param _svc GATT service descriptor.
 *  @param _svc_uuid_init Service UUID.
#define BT_GATT_POOL_SVC_GET(_svc, _svc_uuid_init)      \
{                                                       \
        struct bt_uuid *_svc_uuid = _svc_uuid_init;     \
        bt_gatt_pool_svc_get(_svc, _svc_uuid);          \

/** @brief Return a CCC descriptor to the pool.
 *  @param attr Attribute describing the CCC descriptor to be returned.
void bt_gatt_pool_ccc_put(struct bt_gatt_attr const *attr);

/** @brief Print basic module statistics (containing pool size usage).
void bt_gatt_pool_stats_print(void);

#ifdef __cplusplus

 * @}


  1. Do not use @fn. Instead, document each function where it is defined.

  2. @brief is mandatory.

    • Start the brief with the “do sth” form.

    /** @brief Request a read operation to be executed from Secure Firmware.
    /** @brief Send Boot Keyboard Input Report.
  3. @details is optional. It can be introduced either by using @details or by leaving a blank line after @brief.

  4. @param should be used for every parameter.

    • Always add parameter description. Use a sentence fragment (no verb) with period at the end.

    • Make sure the parameter documentation within the function is consistently using the parameter type: [in], [out], or [in,out].

    * @param[out] destination Pointer to destination array where the content is
    *                         to be copied.
    * @param[in]  addr        Address to be copied from.
    * @param[in]  len         Number of bytes to copy.
  5. If you include more than one @sa (“see also”, optional), add them this way:

    @sa first_function
    @sa second_function
  6. @return should be used to describe a generic return value without a specific value (for example, “@return The length of …”, “@return The handle”). There is usually only one return value.

    *  @return  Initializer that sets up the pipe, length, and byte array for
    *           content of the TX data.
  7. @retval should be used for specific return values (for example, “@retval true”, “@retval CONN_ERROR”). Describe the condition for each of the return values (for example, “If the function completes successfully”, “If the connection cannot be established”).

    *  @retval 0 If the operation was successful.
    *            Otherwise, a (negative) error code is returned.
    *  @retval (-ENOTSUP) Special error code used when the UUID
    *            of the service does not match the expected UUID.
  8. Do not use @returns. Use @return instead.

/** @brief Request a random number from the Secure Firmware.
 * This function provides a True Random Number from the on-board random number generator.
 * @note Currently, the RNG hardware is run each time this function is called. This
 *       consumes significant time and power.
 * @param[out] output  The random number. Must be at least @p len long.
 * @param[in]  len     The length of the output array. Currently, @p len must be
 *                     144.
 * @param[out] olen    The length of the random number provided.
 * @retval 0        If the operation was successful.
 * @retval -EINVAL  If @p len is invalid. Currently, @p len must be 144.
 int spm_request_random_number(uint8_t *output, size_t len, size_t *olen);


The documentation block should precede the documented element. This is in accordance with the Zephyr coding style.

/** HID Service Protocol Mode events. */
enum hids_pm_evt {

        /** Boot mode entered. */

        /** Report mode entered. */


The documentation block should precede the documented element. This is in accordance with the Zephyr coding style. Make sure to add :members: when you include the API documentation in RST; otherwise, the member documentation will not show up.

/** @brief Event header structure.
 * @warning When event structure is defined event header must be placed
 *          as the first field.
struct event_header {

        /** Linked list node used to chain events. */
        sys_dlist_t node;

        /** Pointer to the event type object. */
        const struct event_type *type_id;


Always add a name for the struct. Avoid using unnamed structs due to Sphinx parser issue.


To link to functions, enums, or structs from within doxygen itself, use the @ref keyword.

/** @brief Event header structure.
 *  Use this structure with the function @ref function_name and
 *  this structure is related to another structure, @ref structure_name.


Linking to functions does not currently work due to Breathe issue #438.


The documentation block should precede the documented element. This is in accordance with the Zephyr coding style.

 * @brief Download client asynchronous event handler.
 * Through this callback, the application receives events, such as
 * download of a fragment, download completion, or errors.
 * If the callback returns a non-zero value, the download stops.
 * To resume the download, use @ref download_client_start().
 * @param[in] event  The event.
 * @retval 0 The download continues.
 * @retval non-zero The download stops.
 typedef int (*download_client_callback_t)(const struct download_client_evt *event);