Creating a via with pcbnew's Python API

Published on September 8, 2026 by leZ

Add, position, and size a through-hole via on a PCB by scripting it, with pcbnew or KiCad's IPC API.

0.6 mm via with a 0.3 mm drill on the GND net, created at (40, 25) mm by a Python script in KiCad
The via created by the script, on the GND net.

A stitching-via grid around a ground plane, or a row of thermal vias under a footprint: as soon as you need more than a handful of identical vias, placing them by hand gets slow and imprecise. Both pcbnew and the IPC API let you create these vias by script, with exact control over position, pad diameter, and drill size.

A via (and the track leading to it) created by script, filmed live in KiCad (1:16):

Creating the via

Instantiate a PCB_VIA object attached to the board, then add it:

import pcbnew

board = pcbnew.GetBoard()
from pcbnew import PCB_VIA

via = PCB_VIA(board)
board.Add(via)

With the IPC API, you instantiate a blank Via object; it doesn’t exist on the board until it’s explicitly created:

from kipy import KiCad
from kipy.board_types import Via

kicad = KiCad()
board = kicad.get_board()
via = Via()

Positioning and sizing the via

Position, pad diameter, and drill size are set separately, in internal units (nanometers), converted from millimeters with FromMM:

from pcbnew import VECTOR2I, FromMM

via.SetPosition(VECTOR2I(FromMM(40), FromMM(25)))
via.SetWidth(via.TopLayer(), FromMM(0.6))
via.SetDrill(FromMM(0.3))

Position is set in millimeters via Vector2.from_xy_mm, but diameter and drill size are raw nanometer integers: they need an explicit from_mm conversion:

from kipy.geometry import Vector2
from kipy.util.units import from_mm

via.position = Vector2.from_xy_mm(40, 25)
via.diameter = from_mm(0.6)
via.drill_diameter = from_mm(0.3)

Try it below: drag the sliders to see how position, pad diameter, and drill size affect the via on the board.

via.SetPosition(VECTOR2I(FromMM(40), FromMM(25)))
via.SetWidth(FromMM(0.6))
via.SetDrill(FromMM(0.3))
40
25
0.6
0.3

Connecting the via to a net

The via needs to be attached to an existing net (typically GND for a stitching via):

via.SetNet(board.FindNet("GND"))

On the IPC API side, the net is referenced directly by name. This is also the point, once every property is set, where the via is actually created on the board:

from kipy.board_types import Net

via.net = Net(name="GND")
board.create_items(via)

Going further

Placing a single via is rarely the actual goal. The real value of scripting is generating an entire stitching-via grid around a ground plane, or a row of thermal vias under a power footprint, in a few lines of loop rather than by hand.