What Klipper macros can do

Klipper macro parameters: passing values and defaults

A Klipper macro takes its arguments as NAME=VALUE pairs on the command line and reads them from the params variable. Below: the call syntax, defaults, number conversion, booleans, required parameters and how Mainsail and Fluidd show them.

Published · Last verified

Front view of an orange Voron toolhead on its gantry, with the cable chain behind it
Photo: disinterpreter, CC BY-SA 2.0

Call the macro with NAME=VALUE pairs, as in HEAT_UP BED=100 HOTEND=250, and read each one inside the macro as params.NAME. Every value arrives as a string, so convert it with |int or |float. Put |default() in front to cover calls that leave the parameter out.

[gcode_macro HEAT_UP]
description: Heat bed and hotend, then wait
gcode:
    {% set bed = params.BED|default(60)|float %}
    {% set hotend = params.HOTEND|default(210)|float %}
    M140 S{bed}
    M104 S{hotend}
    M190 S{bed}
    M109 S{hotend}

HEAT_UP BED=100 HOTEND=250 heats to 100 and 250. HEAT_UP alone uses 60 and 210. HEAT_UP HOTEND=240 takes the bed default and the hotend value you passed.

How do you pass parameters to a Klipper macro?

Type the macro name followed by NAME=VALUE pairs separated by spaces, for example PRINT_START BED=110 EXTRUDER=250. Inside the macro, Klipper’s params pseudo-variable holds them: params.BED and params.EXTRUDER. Names arrive in upper case and values arrive as strings, so convert numbers before doing math. Order does not matter.

Klipper’s parser in klippy/gcode.py sets four rules for the call line:

  • No spaces around =. TEMP = 200 fails with a “Malformed command” error. So does a bare value with no name, such as HEAT_UP 200.
  • Case does not matter in the call. heat_up bed=100 works, because Klipper upper-cases the names. Inside the macro, always write params.BED. params.bed is never set.
  • Quote values that contain spaces. Klipper splits arguments shell-style, so NOTIFY MSG="Bed is hot" arrives as one value, Bed is hot.
  • Extra parameters are ignored. Passing a name the macro never reads raises no error, so a typo like TEMPP=240 quietly leaves the default in place.

A slicer passes values the same way, using its own placeholders in the start G-code. Klipper’s Slicers page has the lines for Cura and PrusaSlicer. A full start macro is on the PRINT_START page.

Macros named like G-codes

A macro named like a standard G-code (M141) takes G-code-style parameters: M141 S60, read as params.S. Klipper parses these lines in upper case, values included. The chamber heater page uses this for M141 and M191, and rename_existing covers overriding a G-code Klipper already has.

How do you set a default value for a Klipper macro parameter?

Add Jinja’s default filter before the conversion: {% set temp = params.TEMP|default(200)|float %}. When the call leaves TEMP out, temp becomes 200.0. When it passes TEMP=240, the passed value wins. Keep default before int or float, and assign the result once with set at the top of the macro.

Klipper’s own sample-macros.cfg writes its start macro this way, with params.BED_TEMP|default(60)|float.

The default only fires when the parameter is missing. A parameter passed with nothing after the = (TEMP=) arrives as an empty string, and float turns that into 0.0. Jinja’s documentation says that to cover values “that evaluate to false you have to set the second parameter to true”:

{% set temp = params.TEMP|default(200, true)|float %}

Defaults kept in a variable

To change a default without editing the macro body, store it in a variable_ option. Klipper makes macro variables available by name during expansion, so the filter can point at one:

[gcode_macro LOAD_FILAMENT]
variable_load_length: 90      # mm; your extruder-to-nozzle distance
gcode:
    {% set length = params.LENGTH|default(load_length)|float %}
    M83
    G1 E{length} F300

SET_GCODE_VARIABLE MACRO=LOAD_FILAMENT VARIABLE=load_length VALUE=120 changes it until the next restart. The macro variables page covers that command and saving values across restarts.

A default can also come from printer state, for example params.BED|default(printer.heater_bed.target)|float to keep whatever the bed is already set to.

Klipper macro params are strings: converting to numbers

Use |int for counts and |float for temperatures, distances and speeds. Without a conversion, params.TEMP + 10 fails because the value is text.

Both filters fail quietly. Jinja’s documentation says float returns 0.0 and int returns 0 when “the conversion doesn’t work”. A typo like TEMP=24O, with the letter O, therefore becomes 0 and turns the heater off instead of raising an error. Check the range of anything that heats or moves.

How to make a macro parameter required

  1. Test for the name. Use 'TEMP' not in params, the form Klipper’s sample macros use, or params.TEMP is not defined.
  2. Stop with an error. Call action_raise_error() with a message that shows the correct call.
  3. Check the range. After converting the value, raise the same error if it falls outside what your hardware accepts.
[gcode_macro SET_HOTEND]
gcode:
    {% if 'TEMP' not in params %}
      { action_raise_error("SET_HOTEND needs TEMP, e.g. SET_HOTEND TEMP=240") }
    {% endif %}
    {% set temp = params.TEMP|float %}
    {% if temp < 170 or temp > 290 %}   # your hotend's working range
      { action_raise_error("SET_HOTEND: TEMP %.0f is out of range" % temp) }
    {% endif %}
    M104 S{temp}

Klipper evaluates the whole macro “in entirety and only then” runs the resulting commands. action_raise_error aborts “the current macro (and any calling macros)” during that evaluation, so none of the macro’s commands run.

Boolean parameters: use 0 and 1

Pass 0 or 1, the convention Klipper’s own commands follow (ENABLE=[0|1] in its G-code reference, ADAPTIVE=1 for bed meshing). Convert with int and compare:

[gcode_macro PRINT_START]
gcode:
    {% set mesh = params.MESH|default(1)|int %}
    G28
    {% if mesh == 1 %}
      BED_MESH_CALIBRATE
    {% endif %}

PRINT_START MESH=0 skips the mesh. Never test the raw value with {% if params.MESH %}. Jinja’s if works like Python’s, where any non-empty string is true, so MESH=0 would still run the mesh.

To accept words as well as digits, lower-case the value and check it against a list:

{% set mesh = params.MESH|default(1)|string|lower in ['1', 'true', 'yes', 'on'] %}

mesh is then a real true or false, so {% if mesh %} works. More on conditions is on the if/else page.

Passing parameters on to another macro

Write the value into the inner call with braces: HEAT_UP BED={bed} HOTEND={hotend}. A called macro sees only the parameters on its own call line, never its caller’s params.

To forward everything unchanged, use rawparams, which Klipper describes as “the full unparsed parameters for the running macro”:

[gcode_macro START]
gcode:
    PRINT_START {rawparams}

Klipper notes that rawparams “will include any comments that were part of the original command.” That is harmless when forwarding, because the inner call drops the comment again; it only shows up if you print rawparams as text.

To see what a macro received, put { action_respond_info("params: " ~ params) } on its first line. The console shows every name and value.

Klipper macro parameters in Mainsail and Fluidd

Both interfaces scan the macro text for params.NAME and give the macro button one input field per parameter. Mainsail shows the default() value as a placeholder and sends nothing for an empty field, so the macro’s own default applies. Fluidd prefills the field, but only with a quoted or numeric default; a default taken from a variable leaves it blank.

Both skip parameter names that start with an underscore, so params._RETRY stays out of the form while the macro still reads it. The same prefix on a macro name, such as _HELPER, hides the whole macro, per the Mainsail and Fluidd documentation.

Sources

  1. Klipper documentation, Command templates (accessed October 10, 2026)
  2. Klipper documentation, Configuration reference (accessed October 10, 2026)
  3. Klipper documentation, G-Codes (accessed October 10, 2026)
  4. Klipper documentation, Slicers (accessed October 10, 2026)
  5. Klipper source, config/sample-macros.cfg (accessed October 10, 2026)
  6. Klipper source, klippy/gcode.py (command and parameter parsing) (accessed October 10, 2026)
  7. Klipper source, klippy/extras/gcode_macro.py (accessed October 10, 2026)
  8. Jinja documentation, Template designer documentation (accessed October 10, 2026)
  9. Mainsail source, src/plugins/helpers.ts (macro parameter detection) (accessed October 10, 2026)
  10. Mainsail source, src/components/inputs/MacroButton.vue (accessed October 10, 2026)
  11. Fluidd source, src/util/gcode-macro-params.ts (accessed October 10, 2026)
  12. Fluidd source, src/components/widgets/macros/MacroBtn.vue (accessed October 10, 2026)
  13. Mainsail documentation, Hide macros, outputs or fans (accessed October 10, 2026)
  14. Fluidd documentation, Macros (accessed October 10, 2026)