KiCad Plugin Tutorial 2026 | Stitching Vias Made Effortless — Auto-Fill Ground Planes in One Click
Stitching vias is a common PCB layout task, especially when you work with ground planes, RF shielding, and thermal management. Manually placing dozens — sometimes hundreds — of small ground vias that “stitch” your copper fills together can quickly become repetitive and error-prone, yet keeping your ground reference solid, your EMI under control, and your thermal paths cool depends on them. KiCad plugin development offers a way to automate this:
In this tutorial, we introduce KiCad Via Stitcher, a free, open-source KiCad 10 plugin that automates repetitive via placement. Select a copper zone or a footprint, and KiCad Via Stitcher fills the selection’s bounding box with a regular grid of stitching vias in one click. No more repetitive clicking, manual counting, or forgetting to place vias. Let’s dive in and build it from scratch!

Contents
What is Stitching Vias?
Via stitching is the practice of placing a regular grid of ground vias across large copper areas — especially ground fills and ground planes — to electrically “stitch” the top and bottom copper layers together. This serves three critical purposes:
- EMC & RF Shielding
A dense grid of stitching vias lowers the loop inductance between planes and helps form an effective shielding “fence” around sensitive circuitry, reducing radiated emissions and crosstalk. - Thermal Management
Vias conduct heat from hot copper regions (e.g., beneath power components) down through the board, spreading it to the opposite plane for efficient heat dissipation. - Solid Ground Reference
Stitching vias keep the ground plane at a consistent potential, reducing return-current path impedance for high-speed signals and preventing ground bounce.
For RF via fences, a common starting point is to keep the via pitch below λ/10 (or λ/20) in the relevant medium. In practice, designers often use a much tighter pitch depending on the stackup, geometry, return path, and shielding requirements — and hundreds of vias across a large ground fill are common.
Meet Via Stitcher — What It Actually Does
Via Stitcher is a native KiCad 10 ActionPlugin written in Python. Unlike a hand-rolled script, it registers itself directly into KiCad’s Tools → External Tools menu (and optionally the toolbar), so you can trigger it with one click while working in the PCB Editor.
Here is exactly what the plugin does under the hood:
- Reads the open board: Grabs the currently open PCB via
pcbnew.GetBoard(). If no board is open, it aborts with a clear warning. - Collects your selection: Gathers every selected copper zone (
board.Zones()) and every selected footprint (board.GetFootprints()). If nothing is selected, it stops with a helpful message. - Prompts for parameters: Opens a native wxPython dialog asking for four values — via spacing, via diameter, drill size, and target net name.
- Validates input: Every dimension must be positive, and the drill must be smaller than the via diameter, otherwise it rejects the values with an error.
- Locates the target net: Searches for the net (e.g.,
GND) on the board. If it doesn’t exist yet, the plugin creates it automatically. - Fills the area with vias: For each selected zone or footprint, it computes the bounding box and fills it with an evenly spaced grid of through-hole vias on the F.Cu / B.Cu layer pair.
- Reports results: Refreshes the canvas and shows a summary — total vias created, spacing, via size, and net name.
That’s it — no cloud calls, no third-party Python packages; it uses KiCad’s built-in pcbnew and wx modules. The entire plugin is one self-contained Python file that places your stitching vias in a regular grid.
The Four Parameters, Explained
| Parameter | Default | What It Controls |
|---|---|---|
| Via spacing (mm) | 2.54 | Center-to-center distance between adjacent vias in the grid. Smaller spacing = denser stitching (better shielding, more vias). |
| Via diameter (mm) | 0.60 | Outer copper diameter of each via pad. |
| Via drill (mm) | 0.30 | Hole diameter of each via. Must be smaller than the via diameter. |
| Net name | GND | The net all placed vias connect to. Great for GND, AGND, DGND, or any custom net. |
A good starting point for most 2-layer boards is 2.54 mm spacing with a 0.6 mm via (0.3 mm drill) on GND. Adjust the spacing down toward 1.27 mm for RF-critical or high-current areas.
Prerequisites & Setup
Before we write any code, let’s prepare the development environment. The good news: KiCad Via Stitcher requires no additional Python packages — just the KiCad built-in pcbnew and wx modules.
- Install the Latest KiCad 10.0
This tutorial is based on KiCad 10.0, which offers mature Python API bindings via SWIG and fullpcbnew.ActionPluginsupport. - Prepare a Code Editor
We recommend VS Code with the Python extension for syntax highlighting and auto-completion while you inspect the source. - Know Your Plugin Directory
KiCad auto-loads action plugins from platform-specific scripting directories. We’ll cover the exact paths in the Installation section below.
Plugin Source Code
Here is the complete source code (via_stitcher.py). It implements every feature described above — safe module loading, a native wxPython parameter dialog with validation, automatic net creation, grid via placement, and a final statistics report. Note that it places vias over the selection’s bounding box rather than tracing the exact copper shape, so run a DRC pass afterwards:
import sys
import os
import traceback
import math
if 'pcbnew' in sys.modules:
pcbnew = sys.modules['pcbnew']
else:
import pcbnew
try:
import wx
except ImportError:
wx = None
class ViaStitcherPlugin(pcbnew.ActionPlugin):
def defaults(self):
self.name = "Via Stitcher"
self.category = "Routing Tools"
self.description = "Auto-fill copper areas with stitching vias"
self.show_toolbar_button = True
try:
self.icon_file_name = os.path.join(os.path.dirname(__file__), 'icon.png')
except NameError:
self.icon_file_name = ""
def show_msg(self, message, is_error=False):
if not wx:
print(message)
return
try:
parent = wx.GetActiveWindow()
except Exception:
parent = None
title = "Via Stitcher - Error" if is_error else "Via Stitcher"
style = wx.OK | (wx.ICON_ERROR if is_error else wx.ICON_INFORMATION)
try:
wx.MessageBox(message, title, style, parent)
except Exception:
print(f"[{title}] {message}")
def get_params(self):
if not wx:
return None
parent = wx.GetActiveWindow()
dlg = wx.Dialog(parent, title="Via Stitcher")
panel = wx.Panel(dlg)
sizer = wx.BoxSizer(wx.VERTICAL)
grid = wx.FlexGridSizer(0, 2, 10, 10)
grid.AddGrowableCol(1, 1)
grid.Add(wx.StaticText(panel, label="Via spacing (mm):"), 0, wx.ALIGN_CENTER_VERTICAL)
sp_ctrl = wx.TextCtrl(panel, value="2.54")
grid.Add(sp_ctrl, 0, wx.EXPAND)
grid.Add(wx.StaticText(panel, label="Via diameter (mm):"), 0, wx.ALIGN_CENTER_VERTICAL)
dia_ctrl = wx.TextCtrl(panel, value="0.6")
grid.Add(dia_ctrl, 0, wx.EXPAND)
grid.Add(wx.StaticText(panel, label="Via drill (mm):"), 0, wx.ALIGN_CENTER_VERTICAL)
dr_ctrl = wx.TextCtrl(panel, value="0.3")
grid.Add(dr_ctrl, 0, wx.EXPAND)
grid.Add(wx.StaticText(panel, label="Net name:"), 0, wx.ALIGN_CENTER_VERTICAL)
net_ctrl = wx.TextCtrl(panel, value="GND")
grid.Add(net_ctrl, 0, wx.EXPAND)
sizer.Add(grid, 1, wx.ALL | wx.EXPAND, 20)
btn_sizer = dlg.CreateButtonSizer(wx.OK | wx.CANCEL)
sizer.Add(btn_sizer, 0, wx.ALL | wx.EXPAND, 10)
panel.SetSizer(sizer)
dlg_main_sizer = wx.BoxSizer(wx.VERTICAL)
dlg_main_sizer.Add(panel, 1, wx.EXPAND)
dlg.SetSizerAndFit(dlg_main_sizer)
dlg.Center()
if dlg.ShowModal() == wx.ID_OK:
try:
sp = float(sp_ctrl.GetValue().strip())
dia = float(dia_ctrl.GetValue().strip())
dr = float(dr_ctrl.GetValue().strip())
net_name = net_ctrl.GetValue().strip()
if sp <= 0 or dia <= 0 or dr <= 0:
raise ValueError("All dimensions must be positive")
if dr >= dia:
raise ValueError("Drill must be smaller than diameter")
return sp, dia, dr, net_name
except ValueError as e:
self.show_msg(f"Invalid input: {e}", is_error=True)
return None
def Run(self):
try:
board = pcbnew.GetBoard()
if not board:
self.show_msg("No open PCB board.", is_error=True)
return
result = self.get_params()
if not result:
return
spacing_mm, dia_mm, drill_mm, net_name = result
spacing_nm = int(spacing_mm * 1_000_000)
dia_nm = int(dia_mm * 1_000_000)
drill_nm = int(drill_mm * 1_000_000)
zones = [z for z in board.Zones() if z.IsSelected()]
footprints = [f for f in board.GetFootprints() if f.IsSelected()]
if not zones and not footprints:
self.show_msg("Select a copper zone or footprint first.", is_error=True)
return
target_net = None
for n in board.GetNetsByName().values():
if n.GetNetname().upper() == net_name.upper():
target_net = n
break
if target_net is None:
target_net = pcbnew.NETINFO_ITEM(board, net_name)
board.Add(target_net)
via_net_code = target_net.GetNetCode()
areas = []
if zones:
for z in zones:
bbox = z.GetBoundingBox()
areas.append(bbox)
if footprints:
for fp in footprints:
bbox = fp.GetBoundingBox()
areas.append(bbox)
created = 0
for area in areas:
x0 = area.GetX()
y0 = area.GetY()
x1 = x0 + area.GetWidth()
y1 = y0 + area.GetHeight()
x = x0 + spacing_nm // 2
while x < x1:
y = y0 + spacing_nm // 2
while y < y1:
via = pcbnew.PCB_VIA(board)
via.SetPosition(pcbnew.VECTOR2I(int(x), int(y)))
via.SetWidth(dia_nm)
via.SetDrill(drill_nm)
via.SetNetCode(via_net_code)
try:
via.SetLayerPair(pcbnew.F_Cu, pcbnew.B_Cu)
except Exception:
pass
board.Add(via)
created += 1
y += spacing_nm
x += spacing_nm
try:
canvas = board.GetViewControl()
if canvas:
canvas.Refresh()
except Exception:
try:
pcbnew.Refresh()
except Exception:
pass
self.show_msg(
f"Done.\n\n"
f" - Vias created: {created}\n"
f" - Spacing: {spacing_mm:.2f} mm\n"
f" - Via size: {dia_mm:.2f} / {drill_mm:.2f} mm\n"
f" - Net: {net_name}"
)
except Exception as e:
self.show_msg(
f"Uncaught error.\n\n"
f"Type: {type(e).__name__}\n"
f"Message: {e}\n\n"
f"Traceback:\n{traceback.format_exc()}",
is_error=True,
)
if __name__ != '__main__':
ViaStitcherPlugin().register()
else:
print("[Via Stitcher] Code loaded. Run ViaStitcherPlugin().Run() in the console.")
How to Use Via Stitcher (Step by Step)
- Open your layout in the KiCad 10 PCB Editor.
- Select one or more copper zones or footprints — either works, and you can mix them. This tells KiCad Via Stitcher where to place vias.
- Launch the plugin: click Tools → External Tools → Via Stitcher (or the toolbar icon if enabled) to run KiCad Via Stitcher.
- Enter your parameters in the dialog — spacing, diameter, drill, and net name.
- Click OK. The plugin fills the selected area(s) with a grid of stitching vias and shows you the total count.
Tip: You don’t need to draw a zone first. Selecting a footprint’s bounding box works just as well — useful for quickly adding thermal vias beneath power pads. KiCad Via Stitcher handles both through the same grid routine.
Installation Guide
To make KiCad load your custom plugin automatically at startup, you must place the files in one of the officially designated directories:
- macOS ★ Recommended Path:
~/Documents/KiCad/10.0/scripting/plugins/
(A non-hidden user folder — easy to manage and clean. We highly recommend using this!) - Windows Path:
%APPDATA%\kicad\10.0\plugins\ - Linux Path:
~/.local/share/kicad/10.0/plugins/
Source Installation (Recommended): Copy the entire via_stitcher/ folder — containing __init__.py, via_stitcher.py, and icon.png — into the plugin directory above. Restart KiCad (or refresh plugins) and KiCad Via Stitcher appears under Tools → External Tools.
Compiled Binary Deployment (.so / .pyd): For distribution without exposing source code, the plugin can be compiled with Cython (a setup.py is included) into a platform-specific shared module. Keep __init__.py and icon.png in the via_stitcher/ folder and simply replace via_stitcher.py with your compiled module.
Pro Tips for Real Boards
- EMC shielding: For RF via fences, a common starting point is to keep your stitching vias spaced under λ/10 of your highest operating frequency. At 2.4 GHz in free space that means roughly 12.5 mm — but in practice designers go much denser depending on stackup and return path.
- Thermal vias: For QFN or PowerPAD packages, a 0.3 mm drill keeps solder from wicking through while maximizing heat transfer to the inner/back plane.
- DRC check: After running the plugin, run KiCad’s DRC to confirm the vias don’t collide with existing tracks or keepouts — especially at tight 1.27 mm spacing.
- Auto-net creation: If you type a net name that doesn’t exist yet (e.g., a typo), KiCad Via Stitcher creates it for you automatically — so double-check the name to avoid accidentally creating a new net.
Conclusion
Via stitching is one of those tasks that separates “it works” from “it works great” in professional PCB design. With KiCad Via Stitcher, a job that used to eat minutes of repetitive clicking now takes a single selection and one click. It’s fast, free, and fully open source.
Ready to try it? Grab the KiCad Via Stitcher plugin from the SaludPCB Store, fire up KiCad, and fill your ground planes with stitching vias in seconds. KiCad Via Stitcher turns repetitive via placement into a simple, repeatable workflow: select a zone or footprint, define the spacing and via dimensions, and let the plugin generate the grid automatically.









