Migrating your pcbnew scripts to the IPC API before KiCad 11
pcbnew is being removed in KiCad 11: a pcbnew → kipy mapping table, the key differences, and a method to port your KiCad Python scripts.
The pcbnew Python bindings (SWIG) have been deprecated since KiCad 9, and the official KiCad documentation states that their removal is planned for KiCad 11. Every script starting with import pcbnew will then have to go through the IPC API and its Python client, kipy. This guide collects the mappings verified across this site’s tutorials, so you can port a script without guesswork.
What really changes
pcbnew |
IPC API (kipy) |
|
|---|---|---|
| Where the script runs | Inside KiCad’s process, or with the Python bundled with KiCad | In any Python, talking to KiCad over a socket |
| Installation | Ships with KiCad | pip install kicad-python |
| KiCad must be open | No (headless, LoadBoard is enough) |
Yes, or started headless by kipy (KiCad 11) |
| Editing an object | Immediate effect | Edit the local copy, then board.update_items(...) |
| Creating an object | board.Add(item) |
board.create_items(item) |
| Units | FromMM() / ToMM() |
from_mm() / to_mm() (nanometres) |
The most confusing point: with kipy, the objects you read are copies. Changing fp.position does nothing until you call board.update_items(fp).
Mapping table
| Task | pcbnew |
kipy |
|---|---|---|
| Open board | board = pcbnew.GetBoard() |
board = KiCad().get_board() |
| Save | pcbnew.SaveBoard(path, board) |
board.save() |
| Find a footprint | board.FindFootprintByReference("U1") |
next(f for f in board.get_footprints() if f.reference_field.text.value == "U1") |
| Position | fp.SetPosition(VECTOR2I(FromMM(30), FromMM(20))) |
fp.position = Vector2.from_xy_mm(30, 20) |
| Orientation | fp.SetOrientationDegrees(90) |
fp.orientation = Angle.from_degrees(90) |
| Apply changes | (immediate) | board.update_items(fp) |
| Flip to the back | fp.Flip(fp.GetPosition(), True) |
board.flip_items(fp) |
| Track | PCB_TRACK(board) + board.Add(track) |
Track() + board.create_items(track) |
| Via | PCB_VIA(board), SetWidth(via.TopLayer(), w), SetDrill(d) |
Via(), via.diameter = w, via.drill_diameter = d |
| Layer | pcbnew.F_Cu |
board.get_layer_by_name("F.Cu") |
| Net | board.FindNet("GND") |
Net(name="GND") |
| Zone | ZONE(board) + SHAPE_POLY_SET outline |
Zone() + zone.outline = PolygonWithHoles |
| Lists | board.GetFootprints(), board.Zones(), board.GetTracks() |
get_footprints(), get_zones(), get_tracks(), get_vias() |
| Gerber export | PLOT_CONTROLLER(board) |
board.export_gerbers(...) (KiCad 11 + kicad-python 0.9) |
| Redraw | pcbnew.Refresh() |
(automatic) |
Each row is covered in detail, with both versions side by side, in the matching tutorial: positioning a footprint, creating a track, creating a via, creating a zone, exporting Gerbers.
Example: the same script in both APIs
Moving and rotating U1 with pcbnew:
import pcbnew
from pcbnew import VECTOR2I, FromMM
board = pcbnew.GetBoard()
fp = board.FindFootprintByReference("U1")
fp.SetPosition(VECTOR2I(FromMM(30), FromMM(20)))
fp.SetOrientationDegrees(90)
pcbnew.Refresh()
The same thing with kipy:
from kipy import KiCad
from kipy.geometry import Angle, Vector2
board = KiCad().get_board()
fp = next(f for f in board.get_footprints() if f.reference_field.text.value == "U1")
fp.position = Vector2.from_xy_mm(30, 20)
fp.orientation = Angle.from_degrees(90)
board.update_items(fp)
Recommended migration method
- Inventory: search your scripts for every
pcbnew.andboard.call to know what needs porting. - Isolate board access in a single module (reading footprints, creating tracks…): it’s the only place to rewrite.
- Port line by line with the table above, without forgetting
update_items()andcreate_items(). - Compare: run the old and new versions on a copy of the same board, then diff the files or run the DRC with kicad-cli.
First of all, enable the IPC API in KiCad’s preferences: it’s off by default.
Going further
Both APIs coexist in KiCad 9 and 10: you can migrate gradually, script by script, without waiting for KiCad 11. Every tutorial on the site has a switcher at the top to compare both versions.