makeIRLEngineering notes

KiCad

Headless KiCad with kicad-cli: automate your PCB checks

Build a headless KiCad 9 pipeline that runs ERC, DRC with schematic parity, BOM export, Gerber plotting, and drill generation with reliable CI failures.

Published Updated

What headless KiCad is good at

kicad-cli runs deterministic checks and exports without opening the graphical editors. It is well suited to release tasks where the same source revision should produce the same reports and fabrication files every time: ERC, PCB DRC, schematic parity, BOM export, Gerbers, drills, position files, PDFs, and 3D exports.

It does not route a board, decide whether a footprint matches a datasheet, or review an online fab preview. Automation removes forgotten clicks; it does not remove engineering judgement.

Use the same KiCad major and patch version locally and in CI. Start every run by printing it:

kicad-cli version

A project created in KiCad 9 should be checked and exported with a pinned KiCad 9 toolchain. Major-version drift can change file serialization, rules, libraries, and CLI options.

Make the repository self-contained

Headless runs expose workstation assumptions quickly. Commit the .kicad_pro, root .kicad_sch, .kicad_pcb, custom .kicad_dru, project symbol and footprint libraries, and project library tables. Use ${KIPRJMOD} for paths relative to the project where practical.

Run commands from the project directory. KiCad can then resolve project variables, tables, design rules, and the schematic associated with the board. A CI image also needs the correct KiCad standard libraries if the project references them; installing only the kicad-cli binary is not necessarily enough.

Keep generated output outside the source tree, for example:

build/reports/
build/bom/
build/fab/

Ignore those directories in version control. Release archives should be reproducible artifacts associated with a source commit, not hand-maintained source files.

Gate the schematic first

Run ERC before spending time on board and fabrication exports:

mkdir -p build/reports

kicad-cli sch erc \
  --format json \
  --output build/reports/erc.json \
  --severity-all \
  --exit-code-violations \
  hardware/controller.kicad_sch

--exit-code-violations is essential for a gate. In KiCad 9, selected violations produce exit status 5; a clean check returns 0. Other nonzero statuses should be treated as execution failures. The detailed guide to command-line ERC covers severity policies and excluded markers.

Run DRC with schematic parity

Next verify physical rules and the board’s relationship to its schematic:

kicad-cli pcb drc \
  --format json \
  --output build/reports/drc.json \
  --severity-all \
  --schematic-parity \
  --exit-code-violations \
  hardware/controller.kicad_pcb

The board must already contain current filled-zone data. Refill and save zones in PCB Editor before committing a release candidate. Headless DRC is a check, not a substitute for reviewing proposed Update PCB from Schematic changes. The schematic parity guide explains the UUID-based link that this flag verifies.

Start strict on new designs. On a legacy project, you may temporarily gate --severity-error while publishing an all-severity report, but set a deadline to clear the warning baseline. Include exclusions periodically with --severity-exclusions so waivers are reviewed rather than forgotten.

Export a BOM from reviewed fields

KiCad 9’s native BOM exporter can use fields and grouping rules from the command line:

mkdir -p build/bom

kicad-cli sch export bom \
  --output build/bom/controller-bom.csv \
  --fields 'Reference,${QUANTITY},Value,Footprint,Manufacturer,MPN,${DNP}' \
  --labels 'Refs,Qty,Value,Footprint,Manufacturer,MPN,DNP' \
  --group-by 'Value,Footprint,Manufacturer,MPN,${DNP}' \
  hardware/controller.kicad_sch

Single quotes keep the shell from expanding KiCad’s ${QUANTITY} and ${DNP} tokens. A named BOM preset stored in the schematic is another good option. The pipeline should additionally validate that fitted lines have an MPN; KiCad can export an empty custom field without considering it an error.

Plot Gerbers and drills from saved settings

Configure and review Gerber layers once in PCB Editor, save the board, and export with those board plot parameters:

mkdir -p build/fab

kicad-cli pcb export gerbers \
  --output build/fab \
  --board-plot-params \
  hardware/controller.kicad_pcb

kicad-cli pcb export drill \
  --output build/fab \
  --format excellon \
  --drill-origin absolute \
  --excellon-units mm \
  --excellon-zeros-format decimal \
  --excellon-separate-th \
  hardware/controller.kicad_pcb

Use pcb export gerbers—plural—for one file per fabrication layer. Keep drill and plot origins consistent. The JLCPCB-focused Gerber export guide lists the layers and post-export inspection points.

Never reuse an output directory containing files from an older run. Generate into a clean job workspace or a revision-specific directory, validate the expected filenames, then zip that exact set. Otherwise a removed inner layer or renamed drill file can survive as a stale artifact.

Assemble the commands into a safe script

A compact POSIX script makes ordering and failure behavior explicit:

#!/usr/bin/env sh
set -eu

SCH="hardware/controller.kicad_sch"
PCB="hardware/controller.kicad_pcb"
OUT="build"

mkdir -p "$OUT/reports" "$OUT/bom" "$OUT/fab"

kicad-cli version
kicad-cli sch erc --format json --output "$OUT/reports/erc.json" \
  --severity-all --exit-code-violations "$SCH"
kicad-cli pcb drc --format json --output "$OUT/reports/drc.json" \
  --severity-all --schematic-parity --exit-code-violations "$PCB"
kicad-cli sch export bom --output "$OUT/bom/controller-bom.csv" "$SCH"
kicad-cli pcb export gerbers --output "$OUT/fab" --board-plot-params "$PCB"
kicad-cli pcb export drill --output "$OUT/fab" --format excellon \
  --drill-origin absolute --excellon-units mm --excellon-zeros-format decimal "$PCB"

With set -e, a violation status stops the script before it emits new manufacturing files. In CI, still upload ERC and DRC reports from failed jobs when possible; those artifacts explain the failure without rerunning locally.

Add checks around KiCad, not just more exports

A useful pipeline also verifies that required source files exist, output files are nonempty, the Gerber set contains one outline and the expected copper layers, BOM MPN cells are populated, and no old artifact entered the package. Record kicad-cli version, source commit, and a hash of the final archive.

Human review remains a release step. Inspect plots in a Gerber viewer, compare the BOM to the schematic, review DRC exclusions, and inspect the fab’s upload preview. A headless pipeline is strongest when it makes those review inputs consistent and refuses to manufacture from a source revision that fails its declared checks.