How to contribute to LXD

The LXD team welcomes contributions through pull requests, issue reports, and discussions.

  • Contribute to the code or documentation, report bugs, or request features in the GitHub repository

  • Ask questions or join discussions in the LXD forum.

Review the following guidelines before contributing to the project.

Code of Conduct

All contributors must adhere to the Ubuntu Code of Conduct.

Pull requests

Submit pull requests on GitHub at: https://github.com/canonical/lxd.

All pull requests undergo review and must be approved before being merged into the main branch.

Commit structure

Use separate commits for different types of changes:

Type

Affects files

Commit message format

API extensions

doc/api-extensions.md, shared/version/api.go

api: Add XYZ extension

Documentation

Files in doc/

doc: Update XYZ

API structure

Files in shared/api/

shared/api: Add XYZ

Go client package

Files in client/

client: Add XYZ

CLI changes

Files in lxc/

lxc/<command>: Change XYZ

LXD daemon

Files in lxd/

lxd/<package>: Add support for XYZ

Tests

Files in tests/

tests: Add test for XYZ

Depending on complexity, large changes might be further split into smaller, logical commits. This commit structure facilitates the review process and simplifies backporting fixes to stable branches.

Developer Certificate of Origin sign-off

To ensure transparency and accountability in contributions to this project, all contributors must include a Signed-off-by line in their commits in accordance with DCO 1.1:

Developer Certificate of Origin
Version 1.1

Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
660 York Street, Suite 102,
San Francisco, CA 94110 USA

Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.

Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as indicated
    in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and that a record of the contribution (including all
    personal information I submit with it, including my sign-off) is
    maintained indefinitely and may be redistributed consistent with
    this project or the open source license(s) involved.

Including a Signed-off-by line in your commits

Every commit must include a Signed-off-by line, even when part of a larger set of contributions. To do this, use the -s flag when committing:

git commit -s -m "Your commit message"

This automatically adds the following to your commit message:

Signed-off-by: Your Name <your.email@example.com>

By including this line, you acknowledge your agreement to the DCO 1.1 for that specific contribution.

  • Use a valid name and email address—anonymous contributions are not accepted.

  • Ensure your email matches the one associated with your GitHub account.

Commit signature verification

In addition to the sign-off requirement, contributors must also cryptographically sign their commits to verify authenticity. See: GitHub’s documentation on commit signature verification.

Make-generated files

Some changes require regenerating certain files using Makefile commands.

After you run any of the commands below, you’ll be prompted whether to commit the changes. If you respond Y, only the re-generated files are committed—any other staged files are ignored.

CLI tool string updates

If you modify CLI strings in lxc/, regenerate and commit translation files:

make i18n

API updates

If you modify the LXD API (shared/api), regenerate and commit the Swagger YAML file (doc/rest-api.yaml) used for API reference documentation:

make update-api

Configuration options updates

If you add or update configuration options, regenerate and commit the documentation metadata files (lxd/metadata/configuration.json and doc/metadata.txt):

make update-metadata

Contribute to the code

Follow the steps below to set up your development environment and start working on new LXD features.

Install LXD from source

To build the dependencies, follow the instructions in Install LXD from source.

Add your fork as a remote

After setting up your build environment, add your GitHub fork as a remote and fetch the latest updates:

git remote add myfork [email protected]:<your_username>/lxd.git
git remote update

Then switch to the main branch of your fork:

git switch myfork/main

Build LXD

Now you can build your fork of the project by running:

make

Before making changes, create a new branch on your fork:

git switch -c <name_of_your_new_branch>

Set up tracking for the new branch to make future pushes easier:

git push -u myfork <name_of_your_new_branch>

Important notes for new LXD contributors

  • Persistent data is stored in the LXD_DIR directory, which is created by running lxd init.

    • By default, LXD_DIR is located at /var/lib/lxd (for non-snap installations) or /var/snap/lxd/common/lxd (f or snap users).

    • To prevent version conflicts, consider setting a separate LXD_DIR for your development fork.

  • Binaries compiled from your source are placed in $(go env GOPATH)/bin by default.

    • When testing, explicitly invoke these binaries instead of the global lxd you might have installed.

    • For convenience, you can create an alias in your ~/.bashrc to call these binaries with the appropriate flags.

  • If you have a systemd service running LXD from a previous installation, consider disabling it to prevent version conflicts with your development build.

Contribute to the documentation

We strive to make LXD as easy and straightforward to use as possible. To achieve this, our documentation aims to provide the information users need, cover all common use cases, and answer typical questions.

You can contribute to the documentation in several ways. We appreciate your help!

Ways to contribute

Document new features or improvements you contribute to the code.
  • Submit documentation updates in pull requests alongside your code changes. We will review and merge them together with the code.

Clarify concepts or common questions based on your own experience.
  • Submit a pull request with your documentation improvements.

Report documentation issues by opening an issue on GitHub.
  • We will evaluate and update the documentation as needed.

Ask questions or suggest improvements in the LXD forum.
  • We monitor discussions and update the documentation when necessary.

Join discussions in the #lxd channel on IRC via Libera Chat.
  • While we cannot guarantee responses to IRC posts, we monitor the channel and use feedback to improve the documentation.

If you contribute images to doc/images:

  • Use SVG or PNG formats.

  • Optimize PNG images for smaller file size using a tool like TinyPNG (web-based), OptiPNG (CLI-based), or similar.

Documentation framework

LXD’s documentation is built with Sphinx and hosted on Read the Docs.

It is written in Markdown with MyST extensions. For syntax help and guidelines, see the MyST style guide and the documentation cheat sheet (source).

For structuring, the documentation uses the Diátaxis approach.

Build the documentation

To build the documentation, run make doc from the root directory of the repository. This command installs the required tools and renders the output to the doc/_build/ directory. To update the documentation for changed files only (without re-installing the tools), run make doc-incremental.

Before opening a pull request, make sure that the documentation builds without any warnings (warnings are treated as errors). To preview the documentation locally, run make doc-serve and go to http://localhost:8000 to view the rendered documentation.

When you open a pull request, a preview of the documentation hosted by Read the Docs is built automatically. To see this, view the details for the docs/readthedocs.com:canonical-lxd check on the pull request. Others can also use this preview to validate your changes.

Automatic documentation checks

GitHub runs automatic checks on the documentation to verify the spelling, the validity of links, correct formatting of the Markdown files, and the use of inclusive language.

You can (and should!) run these tests locally before pushing your changes:

  • Check the spelling: make doc-spellcheck (or make doc-spelling to first build the documentation and then check it)

  • Check the validity of links: make doc-linkcheck

  • Check the Markdown formatting: make doc-lint

  • Check for inclusive language: make doc-woke

Document instructions (how-to guides)

LXD can be used with different clients, primarily the command-line interface (CLI), API, and UI. The documentation contains instructions for all of these, so when adding or updating how-to guides, remember to update the documentation for all clients.

Using tabs for client-specific information

When instructions differ between clients, use tabs to organize them:

````{tabs}
```{group-tab} CLI
[...]
```
```{group-tab} API
[...]
```
```{group-tab} UI
[...]
```
````

Tip

You might need to increase the number of backticks (`) if there are code blocks or other directives in the tab content.

Guidelines for writing instructions

CLI instructions
  • Link to the relevant lxc command reference. Example: [`lxc init`](lxc_init.md)

  • You don’t need to document all available command flags, but mention any that are especially relevant.

  • Examples are very helpful, so add a few if it makes sense.

API instructions
  • When possible, use lxc query to demonstrate API calls. For complex calls, use curl or other widely available tools.

  • In the request data, include all required fields but keep it minimal—there’s no need to list every possible field.

  • Link to the API call reference. Example: [`POST /1.0/instances`](swagger:/instances/instances_post)

UI instructions
  • Use screenshots sparingly—they are difficult to keep up to date.

  • When referring to labels in the UI, use the {guilabel} role. Example: To create an instance, go to the {guilabel}`Instances` section and click {guilabel}`Create instance`.

Document configuration options

Configuration options are documented by comments in the Go code. These comments are extracted automatically.

Adding or modifying configuration options

  • Look for comments that start with lxdmeta:generate in the code.

  • When adding or modifying a configuration option, include the corresponding documentation comment.

  • Refer to the lxd-metadata README file for formatting guidelines.

  • When you add or modify configuration options, you must re-generate doc/metadata.txt and lxd/metadata/configuration.json. See the Configuration options updates section for instructions.

Including configuration options in documentation

The documentation pulls sections from doc/metadata.txt to display a group of configuration options. For example, to include the core server options, use:

% Include content from [metadata.txt](metadata.txt)
```{include} metadata.txt
    :start-after: <!-- config group server-core start -->
    :end-before: <!-- config group server-core end -->
```

When to update documentation files

  • If you add a new option to an existing group, no changes to the documentation files are needed, aside from re-generating metadata.txt. The option will be included automatically.

  • If you define a new group, to add it to the documentation, you must add an {include} directive to the appropriate Markdown file in doc/.