---
title: Building and Flashing
sidebar_label: Building and Flashing
---

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";

From here on, building and flashing ZMK should all be done from the `app/`
subdirectory of the ZMK checkout:

```sh
cd app
```

:::warning
If this is not done, you will encounter errors such as: `ERROR: source directory
"." does not contain a CMakeLists.txt; is this really what you want to build?`
:::

## Building

Building a particular keyboard is done using the
[`west build`](https://docs.zephyrproject.org/4.1.0/develop/west/build-flash-debug.html#building-west-build)
command. Its usage slightly changes depending on if your build is for a keyboard
with an onboard MCU or one that uses an MCU board add-on.

<Tabs queryString="build-opts" defaultValue="onboardMcu"
      values={[
        {label: 'Onboard MCU', value: 'onboardMcu'},
        {label: 'Addon MCU', value: 'addonMcu'}
      ]}>
  <TabItem value="onboardMcu">
    Keyboards with onboard MCU chips are simply treated as the
    [board](https://docs.zephyrproject.org/4.1.0/hardware/porting/board_porting.html)
    as far as Zephyr™ is concerned.

    Given the following:

    - Keyboard: Planck (rev6)
    - Keymap: default

    you can build ZMK with the following:

    ```sh
    west build -b planck_rev6
    ```

  </TabItem>
  <TabItem value="addonMcu">
    ZMK treats keyboards that take an MCU addon board as
    [shields](https://docs.zephyrproject.org/4.1.0/hardware/porting/shields.html),
    and treats the smaller MCU board as the true
    [board](https://docs.zephyrproject.org/4.1.0/hardware/porting/board_porting.html).

    Given the following:

    - MCU Board: Proton-C
    - Keyboard PCB: kyria_left
    - Keymap: default

    You can build ZMK with the following:

    ```sh
    west build -b proton_c -- -DSHIELD=kyria_left
    ```

  </TabItem>
</Tabs>

### CMake Arguments

For creating a build system, the `west build` command uses
[CMake](https://cmake.org/). This allows for additional arguments to be added to
its invocations.

This is done by adding `--` after the `west build` command and listing the CMake
arguments afterward. The previous section shows one example of this with
`-DSHIELD=kyria_left`. Another example use case is passing Kconfig flags:

```sh
west build -b planck_rev6 -- -DCONFIG_ZMK_SLEEP=y
```

:::tip
Once the first generation of the build directory using one-time CMake arguments
is done, you can omit the CMake arguments and board selection, instead building
with the command:

```sh
west build -d <build_dir>
```

:::

You can also add permanent CMake arguments to `west build` by using the
[`west config`](https://docs.zephyrproject.org/4.1.0/develop/west/config.html#west-config-cmd)
command. These are invoked whenever a new build system is generated. To add
permanent arguments, set the `build.cmake-args` configuration option.

```sh
west config build.cmake-args -- -DSHIELD=kyria_left
```

Multiple arguments are added by assigning a string to the configuration option:

```sh
west config build.cmake-args \
  -- "-DSHIELD=kyria_left -DZMK_CONFIG=/absolute/path/to/zmk-config"
```

### Pristine Building

When building for a new board and/or shield after having built one previously, you may need to enable the pristine build option. This option removes all existing files in the build directory before regenerating them, and can be enabled by adding either --pristine or -p to the command:

```sh
west build -p -b nice_nano -- -DSHIELD=kyria_left
```

### Building For Split Keyboards

:::note
For split keyboards, you will have to build and flash each side separately the first time you install ZMK.
:::

By default, the `build` command outputs a single .uf2 file named `zmk.uf2` so building left and then right immediately after will overwrite your left firmware. In addition, you will need to pristine build each side to ensure the correct files are used. To avoid having to pristine build every time and separate the left and right build files, we recommend setting up separate build directories for each half. You can do this by using the `-d` parameter and first building left into `build/left`:

```sh
west build -d build/left -b nice_nano -- -DSHIELD=kyria_left
```

and then building right into `build/right`:

```sh
west build -d build/right -b nice_nano -- -DSHIELD=kyria_right
```

This produces `left` and `right` subfolders under the `build` directory and two separate .uf2 files. For future work on a specific half, use the `-d` parameter again to ensure you are building into the correct location.

:::tip
Build times can be significantly reduced after the initial build by omitting all build arguments except the build directory, e.g. `west build -d build/left`. The additional options and intermediate build outputs from your initial build are cached and reused for unchanged files.
:::

### Building With External Modules

ZMK supports loading additional boards, shields, code, etc. from [external ZMK modules](../../features/modules.mdx), facilitating out-of-tree management and versioning independent of the ZMK repository. To build with any additional modules, use the `ZMK_EXTRA_MODULES` define added to your `west build` command.

For instance, building with the `my-vendor-keebs-module` checked out to your documents directory, you would build like:

```
west build -b nice_nano -- -DSHIELD=vendor_shield -DZMK_EXTRA_MODULES="C:/Users/myUser/Documents/my-vendor-keebs-module"
```

When adding multiple modules, make sure they are separated by a semicolon, e.g.:

```
west build -b nice_nano -- -DSHIELD=vendor_shield -DZMK_EXTRA_MODULES="C:/Users/myUser/Documents/my-vendor-keebs-module;C:/Users/myUser/Documents/my-other-keebs-module"
```

### Building from `zmk-config` Folder

Instead of building .uf2 files using the default keymap and config files, you
can build using files from your [`zmk-config` folder](../../user-setup.mdx#github-repo)
by adding `-DZMK_CONFIG="C:/the/absolute/path/config"` to your `west build`
command. **Notice that this path should point to the folder labeled `config`
within your `zmk-config` folder.**

For instance, building kyria firmware from a user `myUser`'s `zmk-config` folder
on Windows may look something like this:

```sh
west build -b nice_nano -- -DSHIELD=kyria_left \
  -DZMK_CONFIG="C:/Users/myUser/Documents/Github/zmk-config/config"
```

:::warning
If your config is also a [module](../../features/modules.mdx), then you should
also add the root (the folder in which the `zephyr` folder is found) of your
`zmk-config` as an [external module to build with](#building-with-external-modules).
:::

## Flashing

The above build commands generate a UF2 file in `build/zephyr` (or
`build/left|right/zephyr` if you followed the instructions for splits) and is by
default named `zmk.uf2`. If your board supports USB Flashing Format (UF2), copy
that file onto the root of the USB mass storage device for your board. The
controller should flash your built firmware, unmount the USB storage device and
automatically restart once flashing is complete.

Alternatively, if your board supports flashing and you're not developing from
within a Dockerized environment, enable Device Firmware Upgrade (DFU) mode on
your board and run the following command to flash:

```sh
west flash
```

## Multi-CPU and Dual-Chip Bluetooth Boards

Zephyr supports running the Bluetooth host and controller on separate processors. In such a configuration, ZMK always runs on the host processor, but you may need to build and flash separate firmware for the controller. Zephyr provides sample code which can be used as the controller firmware for Bluetooth HCI over [RPMsg](https://docs.zephyrproject.org/4.1.0/samples/bluetooth/hci_rpmsg/README.html), [SPI](https://docs.zephyrproject.org/4.1.0/samples/bluetooth/hci_spi/README.html), [UART](https://docs.zephyrproject.org/4.1.0/samples/bluetooth/hci_uart/README.html), and [USB](https://docs.zephyrproject.org/4.1.0/samples/bluetooth/hci_usb/README.html). See [Zephyr's Bluetooth Stack Architecture documentation](https://docs.zephyrproject.org/4.1.0/connectivity/bluetooth/bluetooth-arch.html) for more details.

The following documentation shows how to build and flash ZMK for boards that use a dual-chip configuration.

### nRF5340

To build and flash the firmware for the nRF5340 development kit's network core, run the following command from the root of the ZMK repo:

```sh
cd zephyr/samples/bluetooth/hci_rpmsg
west build -b nrf5340dk_nrf5340_cpunet
west flash
```

You can then build and flash ZMK firmware using the normal steps described above. The network core's firmware only needs to be updated whenever ZMK upgrades to a new version of Zephyr.

For a custom nRF5340-based board, you will need to define two Zephyr boards: one for the application core and one for the network core. The [nRF5340 DK's board definition](https://github.com/zephyrproject-rtos/zephyr/tree/main/boards/arm/nrf5340dk_nrf5340) can be used as reference. Replace `nrf5340dk_nrf5340_cpunet` with the name of your network core board.
