Creating a copper zone (ground plane) with pcbnew's Python API
Generate a copper zone connected to a net and trigger its fill by script, with pcbnew or KiCad's IPC API.

A ground plane drawn and filled by hand has to be redone after every routing change. By scripting the zone’s creation and fill, you get a reproducible ground plane that can be regenerated with a single command after each change.
Seven copper zones of different shapes (circle, star, ring with a hole, hatched ground plane…) drawn by script, filmed live in KiCad, then checked with the DRC (1:26):
Creating the zone
Instantiate a ZONE object, pick its layer, then add it to the board:
import pcbnew
board = pcbnew.GetBoard()
from pcbnew import ZONE, F_Cu
zone = ZONE(board)
zone.SetLayer(F_Cu)
board.Add(zone)With the IPC API, you instantiate a blank Zone object, then set its type (copper):
from kipy import KiCad
from kipy.board_types import Zone, ZoneType
kicad = KiCad()
board = kicad.get_board()
zone = Zone()
zone.type = ZoneType.ZT_COPPERDefining the outline
The outline is a SHAPE_POLY_SET you append the polygon’s vertices to, in internal units:
from pcbnew import SHAPE_POLY_SET, FromMM
outline = SHAPE_POLY_SET()
outline.NewOutline()
for x, y in [(0, 0), (50, 0), (50, 30), (0, 30)]:
outline.Append(FromMM(x), FromMM(y))
zone.SetOutline(outline)On the IPC API side, the outline is built from a PolyLine of nodes (in nanometers, converted with from_mm), wrapped in a PolygonWithHoles:
from kipy.geometry import PolyLine, PolyLineNode
from kipy.common_types import PolygonWithHoles
from kipy.util.units import from_mm
outline = PolyLine()
for x, y in [(0, 0), (50, 0), (50, 30), (0, 30), (0, 0)]: # last point closes the loop
outline.append(PolyLineNode.from_xy(from_mm(x), from_mm(y)))
polygon = PolygonWithHoles()
polygon.outline = outline
zone.outline = polygon
zone.layers = [board.get_layer_by_name("F.Cu")]Try it below: adjust width and height to see the zone’s outline change on the board.
Connecting the net and filling
Attach the zone to a net, then trigger the fill through ZONE_FILLER:
from pcbnew import ZONE_FILLER
zone.SetNet(board.FindNet("GND"))
filler = ZONE_FILLER(board)
filler.Fill(board.Zones())Same idea for attaching the net. This is also the point, once every property is set, where the zone is actually created on the board — there’s no confirmed method for triggering a fill programmatically via the IPC API yet:
from kipy.board_types import Net
zone.net = Net(name="GND")
board.create_items(zone)Going further
This skeleton is easy to reuse to generate a full per-layer ground plane, carve out keep-out zones around sensitive components, or automatically re-trigger the fill after every routing change instead of clicking “Fill All Zones” by hand.