Skip to main content

Module Creation

ZMK modules are the recommended method of adding content to ZMK, whenever it is possible. This page will guide you through creating a module for ZMK. Distinction is made between modules used for different purposes:

  • Modules containing one or more keyboard-related definitions (boards, shields, interconnects, etc.)
  • Modules containing behaviors & features
  • Modules containing drivers
  • Modules containing other features, such as visual effects

See also Zephyr's page on modules.

tip

For open source hardware designs, it can be convenient to use Git submodules to have the ZMK module also be a Git submodule of the repository hosting the hardware design.

Module Setup

ZMK has a template to make creating a module easier. Navigate to the ZMK module template repository and select "Use this template" followed by "Create a new repository" in the top right.

The rest of this page will go through the contents of the template step by step, guiding you through the configuration of the module.

tip

The Unified ZMK Config Template is also a module, albeit one focused on keyboards. If you are making a module for a keyboard, you may find it useful to base the module off of the template and use GHA to help troubleshoot any errors. Later, you can extract the keyboard to a dedicated module or remove superfluous parts from your module with the help of the information on this page.

Zephyr Module File

This is the file that defines your module. Only when this file is configured correctly will your module function as expected.

Name

First, you will need to name your module. ZMK has a naming convention that you should follow:

zmk-<type>-<description>

Valid options for type are:

TypeDescription
keyboardThe module contains definitions for one or multiple keyboards, be they boards or shields.
componentThe module contains definitions for one or multiple components, such as boards for shields to use.
behaviorThe module contains a single behavior.
driverThe module contains a single driver.
featureThe module contains a single feature which doesn't fall under the other categories.
vfxThe module contains definitions for one or multiple visual effects, such as display customisations or RGB animations.

For each of these, you can use the singular or plural, i.e. keyboard and keyboards are both acceptable. Use your judgement to decide between the two.

<description> is your choice of name to describe the module.

Note that your module name does not have to be the same as your repository name. For example, if you have named your module zmk-keyboards-corne, you may for your own organisational purposes want to name the repository e.g. zmk-corne-module.

Your module name goes in the zephyr/module.yml file:

zephyr/module.yaml
name: <your module name>

Build options

Next, you need to define the options to build your module. These also go into zephyr/module.yml, as children of the build property. Commonly used options are:

  • The depends child property is used to specify a list of modules which the module depends on. The dependencies are referred to by their module name.
  • The cmake child property is used to identify a folder containing a CMakeLists.txt file that lists the CMake commands used to build source files.
  • The kconfig child property is used to identify the Kconfig file that defines configuration settings used by the module.
  • settings is a child property containing additional child properties, two of which are particularly relevant:
    • board_root points to the parent directory of a boards directory, which contains additional board/shield definitions.
    • dts_root points to the parent directory of a dts directory, which contains additional devicetree bindings.
    • snippet_root points to the parent directory of a snippets directory, which contains snippets.

See the zephyr/module.yml found in the template for a usage example.

Dependencies

If zephyr/module.yml has anything listed under depends, then you should also define a west manifest file. While the zephyr/module.yml file defines which modules your module depends on, the west manifest file defines where said modules are found. This then allows automatic tooling to fetch the modules when building firmware. If depends is not present in zephyr/module.yml, then this file (named west.yml in the template) should be removed.

It is recommended that you place the manifest file at the root of your module, though you can place it elsewhere. Be sure to note in your README.md that your module uses dependencies, so that users import these correctly. Below is an example west.yml file for a user that would be using your module, with the necessary import field if the module has dependencies:

west.yml
manifest:
remotes:
- name: remote-name
url-base: https://github.com/remote-name
projects:
# Together with the above defined remote, this refers to a module located at
# https://github.com/remote-name/repository-name
- name: repository-name
remote: remote-name
# This points to a west manifest file in the remote module for further imports
import: west.yml

See the modules feature page for additional information on using west manifest files.

Informational Files

Make sure to include a README.md file and a LICENSE file in your repository.

Predefined Files and Folders

The repository comes with a number of files and folders already positioned for you to edit. The below table describes which files are most likely kept and which are most likely deleted, based on your module's type. Note that these aren't hard rules, merely the most common use case.

keyboardcomponentbehaviordriverfeaturevfx
board/
dts/
CMakeLists.txt
Kconfig
include/
src/
snippets/

The below table reminds of the purpose of each of these files and folders, if you are not already familiar with them:

File or FolderDescription
board/Folder containing definitions for boards, shields and interconnects
dts/Folder containing devicetree bindings and includes with devicetree nodes (.dtsi)
CMakeLists.txtCMake configuration to specify source files to build
KconfigKconfig file for the module
include/Folder for C header files
src/Folder for C source files
snippets/Folder for snippets

Note that the include and src folders are not mandated by the module system, and all of these can be positioned anywhere in your module's filetree if you adjust the zephyr/module.yml accordingly. The west.yml file is not commonly present in any of the types.

Modules should expose all provided header files with an include path name beginning with the module-name, for example at include/zmk_<type>_<description>/<header>.h.

info

If your module requires adding drivers to existing subsystems in modules, you will need to use the zephyr_library_amend() CMake command, which requires you to have a specific directory structure. See here for the definition and some documentation in the comments, with an example here.

Examples

Below are some examples of modules for different types. Unless under the zmkfirmware project, these are not endorsed officially and may not follow our conventions perfectly. For such reason, the modules chosen to be presented here may change with time.