A start macro moves your printer's warm-up routine out of the slicer and into printer.cfg, where you can change it without re-slicing. Below is a complete macro, what each line does, and what to check when Klipper says the command is unknown.
Write a [gcode_macro PRINT_START] section in printer.cfg that reads the bed and nozzle temperatures as parameters, then heats the bed, homes, meshes, heats the nozzle and purges. Replace your slicer’s start G-code with one line that calls it, such as PRINT_START BED_TEMP=60 EXTRUDER_TEMP=210, and restart Klipper.
What should a Klipper PRINT_START macro do?
A PRINT_START macro should take the bed and nozzle temperatures from the slicer, heat the bed, home all axes, probe or load a bed mesh, heat the nozzle, and lay a purge line. Each wait must finish before the next step, so the first layer starts at temperature on a measured surface.
The order matters most for the bed. Home and probe after the bed reaches temperature, so the Z reference and the mesh match the hot bed you print on.
How to write a Klipper PRINT_START macro
- Add the section. Open
printer.cfg (or a file it includes) and add [gcode_macro PRINT_START] with a gcode: option.
- Read the temperatures. Set
BED_TEMP and EXTRUDER_TEMP from params, with a default for each and a conversion to a number.
- Heat the bed and wait. Use
M190 S{BED_TEMP}.
- Home. Run
G28 once the bed is hot.
- Mesh. Run
BED_MESH_CALIBRATE ADAPTIVE=1 if you have a probe, or BED_MESH_PROFILE LOAD=default if you saved a mesh.
- Heat the nozzle and wait. Use
M109 S{EXTRUDER_TEMP}.
- Purge. Draw a short line off the print area to prime the nozzle.
- Call it from the slicer. Replace the slicer’s start G-code with
PRINT_START BED_TEMP=… EXTRUDER_TEMP=…, using the slicer’s own temperature placeholders.
- Reload and test. Send
RESTART, then run HELP in the console and check that PRINT_START is listed.
Klipper start print macro example
This macro does every step above. Copy it, then change the purge coordinates to a clear strip at the front of your bed.
[gcode_macro PRINT_START]
description: Heat, home, mesh and purge before a print
gcode:
{% set BED_TEMP = params.BED_TEMP|default(60)|float %}
{% set EXTRUDER_TEMP = params.EXTRUDER_TEMP|default(200)|float %}
G90 ; absolute coordinates
M190 S{BED_TEMP} ; heat the bed and wait
G28 ; home all axes on the hot bed
BED_MESH_CALIBRATE ADAPTIVE=1 ; probe only where the objects sit
G1 Z5 F3000 ; lift clear of the bed
M109 S{EXTRUDER_TEMP} ; heat the nozzle and wait
SAVE_GCODE_STATE NAME=purge
M83 ; relative extrusion for the purge
G1 X10 Y10 F6000 ; purge start: placeholder, set for your bed
G1 Z0.3 F600
G1 X110 E15 F1200 ; 100 mm line, 15 mm of filament
G1 Z2 F600 ; lift off the line
RESTORE_GCODE_STATE NAME=purge
No probe? Delete the BED_MESH_CALIBRATE line. Without a probe, Klipper’s bed mesh falls back to manual probing (the paper test), which has no place in an unattended start macro. If you saved a mesh, load it with BED_MESH_PROFILE LOAD=default instead.
For a printer that soaks a heated chamber before homing, the chamber heater guide adds an M191 wait to the same structure. For a more careful purge than a straight line, see the purge line macro.
Klipper PRINT_START macro explained, line by line
{% set BED_TEMP = params.BED_TEMP|default(60)|float %} reads the BED_TEMP= value the slicer passes. Klipper’s command templates page says parameter names “are always in upper-case when evaluated in the macro and are always passed as strings”, so float turns the value into a number. default(60) covers a missing parameter, as when you run the macro by hand. See macro parameters for more.
G90 sets absolute coordinates. Klipper’s docs recommend that a macro “always explicitly set the G-Code parsing state prior to issuing a G1 command.”
M190 and M109 heat and wait. Klipper’s G-code list says each one “always waits for temperature to settle at requested value.”
G28 homes every axis. It has to come before BED_MESH_CALIBRATE and before any G1 move.
SAVE_GCODE_STATE and RESTORE_GCODE_STATE wrap the purge. The purge switches to relative extrusion with M83, and the restore puts back whatever extrusion mode was active before. Without MOVE=1, the restore does not move the toolhead.
Klipper evaluates a macro “in entirety and only then” runs the commands it produced. A template that reads printer.extruder.temperature sees the value from before the macro started, even if it sits below the M109 line. To act on a temperature reached mid-macro, call a second macro, which is evaluated when it runs.
Passing temperatures to the start print macro
The macro gets its temperatures from the line that calls it. PRINT_START BED_TEMP=60 EXTRUDER_TEMP=210 hands the macro params.BED_TEMP and params.EXTRUDER_TEMP, as the strings "60" and "210". In the slicer, swap the numbers for its first-layer temperature placeholders. Klipper’s slicer guide gives the exact line for Cura and for PrusaSlicer. The names after the macro must match the params. names in it, letter for letter.
If the printer heats twice, the slicer added its own M190 and M109 above your start G-code because it saw no temperature commands. The same guide shows how to stop that in each slicer.
Adding a bed mesh to PRINT_START
Put BED_MESH_CALIBRATE after G28 and after the bed is at temperature. The mesh is active as soon as the command finishes. Do not also load a saved profile in the same routine. Klipper’s bed mesh guide warns that doing both “may produce unexpected results, especially with adaptive meshing.”
ADAPTIVE=1 probes only the area that the objects in the current file cover, plus adaptive_margin from [bed_mesh] (default 0 mm), with proportionally fewer points. Klipper names the result adaptive-… and says it “should not be saved for reuse.”
An adaptive mesh needs two things:
- An
[exclude_object] section. Add it to printer.cfg; it takes no options.
- Object definitions in the G-code. Turn on object labelling in your slicer, or set
enable_object_processing: True under [file_manager] in moonraker.conf so Moonraker converts object labels on upload. The EXCLUDE_OBJECT_DEFINE lines must sit above the PRINT_START line, because the mesh reads only the objects defined before it runs.
If either is missing, Klipper meshes the whole bed. Without [exclude_object] the console says Exclude objects not enabled. Using full mesh..., and with no object definitions it falls back silently. Setup details are on the adaptive bed mesh page.
Is it PRINT_START or START_PRINT in Klipper?
Either name works, because neither is built into Klipper. The command exists only because a [gcode_macro] section defines it, so the slicer must call exactly the name you defined. Klipper’s own documentation and sample macros use START_PRINT. Voron’s stock configs use PRINT_START. Upper or lower case makes no difference.
Klipper’s command templates page says “case is not important for the G-Code macro name”, so print_start in the slicer calls [gcode_macro PRINT_START]. Underscores and word order do matter. One naming rule catches people out: any numbers in a macro name “must all be at the end of the name”, so PRINT_START2 is valid and PRINT2_START is not.
Fixing “Unknown command” for PRINT_START
The console line Unknown command:"PRINT_START" means Klipper has no command by that name loaded. Check these in order:
- Name mismatch. The slicer sends
PRINT_START but the config defines START_PRINT, or the reverse. Make the two match.
- Macro not loaded. The macro sits in a separate file, such as
macros.cfg, that printer.cfg never pulls in. Add [include macros.cfg] to printer.cfg.
- Config not reloaded. Klipper reads its config only when it starts. After editing, send
RESTART, which makes Klipper reload its config.
Then run HELP in the console. It lists every extended command Klipper has loaded, macros included, so PRINT_START should appear.
Do not ignore this message during a print. Klipper reports an unknown command and keeps reading the file, so the print carries on unheated and unhomed. It usually stops a few lines later, with Must home axis first on the first move, or Extrude below minimum temp once the extruder moves while still below min_extrude_temp (170 °C by default).