Nordic nRF Connect SDK (NCS) Environment
Key Concepts
SDK version and Toolchain version are separate:
- •SDK (nRF Connect SDK): The source code (e.g., v3.2.1, main branch, custom branch)
- •Toolchain: Build tools like west, cmake, compilers (tied to bundle IDs)
These can differ! Example: NCS main branch + v3.2.1 toolchain.
Critical Rule
ALWAYS check if the NCS environment is set up before running any west command.
Workflow for West Commands
When the user requests any west command (west build, west flash, west update, etc.):
Step 1: Check Terminal Status
Check if there's an active terminal with NCS configured. Look for version in prompt (e.g., (v3.2.1)).
Step 2: Determine SDK and Toolchain Versions
If NO active terminal OR terminal doesn't show NCS version:
Ask the user TWO things:
- •Which toolchain version? (e.g., "v3.2.1" → determines bundle ID for build tools)
- •Which SDK path/version? (e.g.,
/opt/nordic/ncs/v3.2.1or/opt/nordic/ncs/main)
Example question: "Which toolchain version would you like to use? (e.g., v3.2.1) And which SDK path? (e.g., /opt/nordic/ncs/v3.2.1 or a custom path)"
Common scenarios:
- •Same version: Toolchain v3.2.1 + SDK at
/opt/nordic/ncs/v3.2.1 - •Different: Toolchain v3.2.1 + SDK at
/opt/nordic/ncs/main
If terminal already shows NCS version in prompt:
- •Proceed directly with the west command
Step 3: Set Up Environment (if needed)
- •
Look up the toolchain bundle ID using the toolchain version:
shjq -r '.toolchains[] | select(.ncs_versions[]=="<TOOLCHAIN_VERSION>").identifier.bundle_id' /opt/nordic/ncs/toolchains/toolchains.json
- •
Export PATH, GIT_EXEC_PATH, and source Zephyr environment from the SDK path:
shBUNDLE_ID="$(jq -r '.toolchains[] | select(.ncs_versions[]=="<TOOLCHAIN_VERSION>").identifier.bundle_id' /opt/nordic/ncs/toolchains/toolchains.json)" export PATH="/opt/nordic/ncs/toolchains/${BUNDLE_ID}/bin:$PATH" export GIT_EXEC_PATH=$(ls -d /opt/nordic/ncs/toolchains/${BUNDLE_ID}/Cellar/git/*/libexec/git-core) source <SDK_PATH>/zephyr/zephyr-env.sh
Step 3.5: Update NCS Main Branch (if using main)
When using the NCS main branch, always update to the latest before building:
- •
Pull latest nrf repository changes:
shcd /opt/nordic/ncs/main/nrf && git pull
- •
Update all west modules (fetches dependencies like OpenThread, Matter, Memfault SDK, etc.):
shcd /opt/nordic/ncs/main && west update --narrow -o=--depth=1
The --narrow -o=--depth=1 flags speed up the update by doing shallow clones.
Why this is needed:
- •The main branch manifest changes frequently, adding/removing module dependencies
- •Build errors like "Unmet or cyclic dependencies" indicate missing modules
- •Running
west updateensures all required modules (OpenThread, Matter, etc.) are present
Step 4: Execute West Command
Combine setup and command in a single invocation:
export PATH="/opt/nordic/ncs/toolchains/<BUNDLE_ID>/bin:$PATH" && \ export GIT_EXEC_PATH=$(ls -d /opt/nordic/ncs/toolchains/<BUNDLE_ID>/Cellar/git/*/libexec/git-core) && \ source <SDK_PATH>/zephyr/zephyr-env.sh && \ cd /path/to/project && \ west <command>
Replace:
- •
<BUNDLE_ID>: From toolchain version lookup - •
<SDK_PATH>: User-specified SDK location (e.g.,/opt/nordic/ncs/v3.2.1or/opt/nordic/ncs/main)
Common Toolchain Bundle IDs
| Toolchain Version | Bundle ID |
|---|---|
| v2.6.0 | 580e4ef81c |
| v2.8.0 | 15b490767d |
| v3.1.1 | 561dce9adf |
| v3.2.0, v3.2.1 | 322ac893fe |
For unlisted versions, always look up in /opt/nordic/ncs/toolchains/toolchains.json.
Example Dialogs
Same SDK and Toolchain Version
User: "Build my project at /opt/nordic/ncs/myApps/my_app"
Assistant: "Which toolchain version would you like to use? (e.g., v3.2.1, v3.1.1)"
User: "v3.2.1"
Assistant: Uses toolchain v3.2.1 + SDK at /opt/nordic/ncs/v3.2.1, then builds
Different SDK and Toolchain Versions
User: "Build my project using NCS main branch"
Assistant: "Which toolchain version would you like to use with the main branch? (e.g., v3.2.1)"
User: "v3.2.1 toolchain with SDK at /opt/nordic/ncs/main"
Assistant: Sets up toolchain v3.2.1, pulls latest nrf repo, runs west update, then builds
User Specifies Both Upfront
User: "Build with v3.2.1 toolchain and NCS main branch at /opt/nordic/ncs/main"
Assistant: Sets up environment, pulls latest, runs west update, then builds
Full Main Branch Build Sequence
# 1. Set up toolchain export PATH="/opt/nordic/ncs/toolchains/<BUNDLE_ID>/bin:$PATH" export GIT_EXEC_PATH=$(ls -d /opt/nordic/ncs/toolchains/<BUNDLE_ID>/Cellar/git/*/libexec/git-core) # 2. Pull latest NCS main cd /opt/nordic/ncs/main/nrf && git pull # 3. Update west modules cd /opt/nordic/ncs/main && west update --narrow -o=--depth=1 # 4. Source environment and build source /opt/nordic/ncs/main/zephyr/zephyr-env.sh cd /path/to/project && west build -b <board> -p
Troubleshooting
Git remote helper issues
After exporting PATH, verify git-remote-https resolves:
command -v git-remote-https || echo "Missing git-remote-https. Current GIT_EXEC_PATH: $GIT_EXEC_PATH"
Avoid nrfutil sdk-manager --shell
Don't use nrfutil sdk-manager … --shell in automated terminals—it keeps the VS Code task busy after builds complete.
Development Environment Setup
Code Formatting with clang-format
Configure VS Code to automatically format code using Zephyr's clang-format rules.
Add to VS Code settings (~/Library/Application Support/Code/User/settings.json on macOS):
{
"editor.rulers": [75,100],
"editor.formatOnSave": true,
"editor.defaultFormatter": "ms-vscode.cpptools",
"C_Cpp.clang_format_path": "/opt/nordic/ncs/toolchains/<BUNDLE_ID>/bin/clang-format",
"C_Cpp.clang_format_style": "file:<SDK_PATH>/zephyr/.clang-format",
}
Replace placeholders:
- •
<BUNDLE_ID>: Your toolchain bundle ID (e.g.,322ac893fefor v3.2.x) - •
<SDK_PATH>: Your SDK path (e.g.,/opt/nordic/ncs/v3.2.1or/opt/nordic/ncs/main)
Example for v3.2.1:
{
"C_Cpp.clang_format_path": "/opt/nordic/ncs/toolchains/322ac893fe/bin/clang-format",
"C_Cpp.clang_format_style": "file:/opt/nordic/ncs/v3.2.1/zephyr/.clang-format",
}
Important: Verify ColumnLimit in .clang-format
After copying Zephyr's .clang-format to your project root, verify that ColumnLimit is set to 80 (not 100). Checkpatch enforces an 80-column limit, and mismatches will cause CI failures.
# In .clang-format, ensure this line reads: ColumnLimit: 80
If you find ColumnLimit: 100, change it to 80 and commit the corrected .clang-format to your repository.
When clang-format and checkpatch disagree:
Zephyr’s checkpatch.pl is the authority. Some macros (for example HTTP_RESOURCE_DEFINE, ZBUS_CHAN_DEFINE) require braces on the same line, while the shared .clang-format prefers Linux-style line breaks. Wrap those regions so VS Code doesn’t reflow them:
/* clang-format off */ HTTP_RESOURCE_DEFINE(button_api_resource, webserver_service, "/api/buttons", &button_api_detail); /* clang-format on */
Inside the off/on block you can keep the checkpatch-approved layout (same-line braces, wrapped strings, etc.) without fighting the formatter.
Speed Up Flashing: Disable Verification
Problem: Verification during flashing adds significant time, especially for large binaries.
Solution: Disable verification in the nrfutil runner.
Steps:
- •
Navigate to the runner script in your SDK:
code<SDK_PATH>/zephyr/scripts/west_commands/runners/nrf_common.py
- •
Find the
_op_programmethod (around line 460) - •
Change the verification option:
python# Before: 'options': {'chip_erase_mode': erase, 'verify': 'VERIFY_READ'} # After: 'options': {'chip_erase_mode': erase, 'verify': 'VERIFY_NONE'}
Example path for v3.2.1:
/opt/nordic/ncs/v3.2.1/zephyr/scripts/west_commands/runners/nrf_common.py
Note: This change persists across flashing operations until you update/reinstall the SDK.
Git Pre-Push Hook for Code Quality
Automatically validate code style and commit messages before pushing to prevent CI failures.
Setup:
- •
Create the pre-push hook in your project:
bashnano .git/hooks/pre-push
- •
Add this content (from Zephyr docs):
bash#!/bin/sh remote="$1" url="$2" z40=0000000000000000000000000000000000000000 echo "Run push hook" while read local_ref local_sha remote_ref remote_sha do args="$remote $url $local_ref $local_sha $remote_ref $remote_sha" exec ${ZEPHYR_BASE}/scripts/series-push-hook.sh $args done exit 0 - •
Make it executable:
bashchmod +x .git/hooks/pre-push
What it checks:
- •Code style validation using
checkpatch.pl - •Commit message format
- •Signed-off-by verification
Environment requirement:
Ensure ZEPHYR_BASE is set (automatically set when you source zephyr-env.sh):
export ZEPHYR_BASE=<SDK_PATH>/zephyr
Testing the hook:
# Make a test commit with sign-off git commit --signoff -m "test: Validate pre-push hook" # Push (hook will run automatically) git push
The hook will display "Run push hook" and any validation errors before allowing the push.
Notes
- •Toolchain provides build tools (west, cmake, compilers) via bundle ID
- •SDK path provides source code and zephyr-env.sh
- •Multiple terminals can have different PATH exports simultaneously
- •Prompt may not change after PATH export; rely on the explicit bundle/version you set
- •To switch versions, repeat setup with new bundle ID and/or SDK path (no terminal restart needed)
- •When user says "NCS v3.2.1", clarify if they mean toolchain, SDK, or both