Disclaimer: This is an independent resource site. Not affiliated with the Voron project or its development team.
Klipper's `save_variables` feature allows you to persist data between restarts, firmware reloads, and even across prints. For Voron owners, this opens up powerful capabilities: per-filament profiles that survive reboots, Z offset memory that persists after bed changes, calibration data that doesn't need re-running, and much more. --- ## What Are Save Variables? `save_variables` is a Klipper system that writes key-value pairs to a JSON file on disk. Unlike regular macro variables (which reset on `RESTART` or power cycle), save variables are written to storage and reloaded automatically when Klipper starts. **Key capabilities:** - Store calibration results permanently - Remember user preferences across sessions - Implement per-filament profiles - Track usage statistics (filament consumed, print hours) - Persist Z offset adjustments --- ## Enabling Save Variables Add this to your `printer.cfg`:

[save_variables]
filename: ~/printer_data/config/saved_variables.cfg


The `.cfg` extension is intentional — the file doubles as a Klipper config file, allowing you to `[include]` it and use the stored values as regular config parameters.

**Important:** The file is created automatically when variables are first saved. You do not need to create it manually.

---

## Basic Usage — Saving and Loading Variables

### Saving a Variable

Use `SAVE_VARIABLE` in any macro or from the console:


SAVE_VARIABLE VARIABLE=my_offset VALUE=0.175


The value is written to `saved_variables.cfg` as:


#*# [my_offset]
#*# 0.175


### Loading Variables in Macros

Access saved variables through the `printer.save_variables` namespace:


[gcode_macro APPLY_Z_OFFSET]
gcode:
    SET_GCODE_OFFSET Z_ADJUST={printer.save_variables.variables.my_offset}


### Checking If a Variable Exists

Use Jinja2's default filter or conditional:


{% set z_offset = printer.save_variables.variables.my_offset | default(None) %}
{% if z_offset is not None %}
    SET_GCODE_OFFSET Z_ADJUST={z_offset}
{% endif %}


---

## Practical Applications for Voron Printers

### 1. Per-Filament Z Offset Profiles

Different filaments (PLA vs ABS vs PETG) often need different first-layer Z offsets. Store them persistently:


[gcode_macro SAVE_Z_OFFSET]
description: Save current Z offset for a filament type
gcode:
    {% set filament = params.FILAMENT|default("PLA") %}
    {% set offset = printer.gcode_move.homing_origin.z|default(0) %}
    SAVE_VARIABLE VARIABLE=z_offset_{filament} VALUE={offset}
    M117 Z offset saved for {filament}

[gcode_macro LOAD_Z_OFFSET]
description: Load saved Z offset for a filament type
gcode:
    {% set filament = params.FILAMENT|default("PLA") %}
    {% set var_name = "z_offset_" ~ filament %}
    {% set offset = printer.save_variables.variables[var_name] | default(None) %}
    {% if offset is not None %}
        SET_GCODE_OFFSET Z_ADJUST={offset}
        M117 Loaded Z offset for {filament}: {offset}mm
    {% else %}
        M117 No Z offset saved for {filament}
    {% endif %}


**Usage in `PRINT_START`:**


[gcode_macro PRINT_START]
gcode:
    # ... homing, heating ...
    {% set filament_type = params.FILAMENT_TYPE|default("PLA") %}
    {% set var_name = "z_offset_" ~ filament_type %}
    {% set saved_offset = printer.save_variables.variables[var_name] | default(None) %}
    {% if saved_offset is not None %}
        SET_GCODE_OFFSET Z_ADJUST={saved_offset}
        M117 Using {filament_type} Z offset: {saved_offset}mm
    {% endif %}


### 2. Per-Filament Pressure Advance Values

Save pressure advance values for each filament brand/type:


[gcode_macro SAVE_PA]
description: Save pressure advance for current filament
gcode:
    {% set filament = params.FILAMENT|default("default") %}
    {% set pa = printer.configfile.settings.extruder.pressure_advance %}
    SAVE_VARIABLE VARIABLE=pa_{filament} VALUE={pa}
    M117 PA saved for {filament}: {pa}

[gcode_macro APPLY_PA]
description: Apply saved pressure advance for a filament
gcode:
    {% set filament = params.FILAMENT|default("default") %}
    {% set var_name = "pa_" ~ filament %}
    {% set pa = printer.save_variables.variables[var_name] | default(None) %}
    {% if pa is not None %}
        SET_PRESSURE_ADVANCE ADVANCE={pa}
        M117 PA set to {pa} for {filament}
    {% endif %}


### 3. Persistent Z Offset Adjustment (Live Tweak)

Adjust Z offset during a print and have it persist:


[gcode_macro Z_OFFSET_UP]
description: Increase Z offset by 0.01mm
gcode:
    {% set current = printer.save_variables.variables.z_offset_live | default(0.0) %}
    {% set new = current + 0.01 %}
    SET_GCODE_OFFSET Z_ADJUST={new}
    SAVE_VARIABLE VARIABLE=z_offset_live VALUE={new}
    M117 Z offset: {new}mm

[gcode_macro Z_OFFSET_DOWN]
description: Decrease Z offset by 0.01mm
gcode:
    {% set current = printer.save_variables.variables.z_offset_live | default(0.0) %}
    {% set new = current - 0.01 %}
    SET_GCODE_OFFSET Z_ADJUST={new}
    SAVE_VARIABLE VARIABLE=z_offset_live VALUE={new}
    M117 Z offset: {new}mm


### 4. Print Start/Resume Tracking

Monitor printer usage:


[gcode_macro PRINT_START]
gcode:
    # ... standard start stuff ...
    {% set total_hours = printer.save_variables.variables.total_print_hours | default(0.0) %}
    M117 Total print time: {"%.1f"|format(total_hours)} hours

[gcode_macro PRINT_END]
gcode:
    # ... standard end stuff ...
    {% set start_time = printer.save_variables.variables.print_start_time | default(0) %}
    {% set elapsed = (session.start_time - start_time) / 3600 %}
    {% set total = printer.save_variables.variables.total_print_hours | default(0.0) %}
    SAVE_VARIABLE VARIABLE=total_print_hours VALUE={total + elapsed}
    SAVE_VARIABLE VARIABLE=last_print_duration VALUE={elapsed}
    SAVE_VARIABLE VARIABLE=total_prints VALUE={(printer.save_variables.variables.total_prints | default(0)) + 1}
    M117 Print complete! Total prints: {(printer.save_variables.variables.total_prints | default(0))}


### 5. Bed Mesh Profile Management

Save and recall multiple bed mesh profiles:


[gcode_macro SAVE_MESH_PROFILE]
description: Save current bed mesh with a name
gcode:
    {% set name = params.NAME|default("default") %}
    BED_MESH_PROFILE SAVE={name}
    SAVE_VARIABLE VARIABLE=last_mesh_profile VALUE="{name}"
    M117 Mesh saved as {name}

[gcode_macro RESTORE_LAST_MESH]
description: Load the last used bed mesh profile
gcode:
    {% set profile = printer.save_variables.variables.last_mesh_profile | default("default") %}
    BED_MESH_PROFILE LOAD="{profile}"
    M117 Loaded mesh: {profile}


---

## The saved_variables.cfg File

Your saved variables file lives at the path you specified. Example contents:


#*# [variables]
#*# z_offset_PLA = 0.125
#*# z_offset_ABS = 0.050
#*# z_offset_PETG = 0.075
#*# pa_PLA = 0.045
#*# pa_ABS = 0.035
#*# pa_PETG = 0.060
#*# total_print_hours = 287.4
#*# total_prints = 143
#*# last_print_duration = 4.2
#*# last_mesh_profile = "250c_abs"
#*# z_offset_live = 0.010


**Important notes:**

- The `#*# ` prefix marks auto-generated entries — Klipper uses this to identify managed variables
- Do NOT edit this file manually while Klipper is running, or your changes will be overwritten
- You can edit it safely when Klipper is stopped, but be careful with JSON syntax

**To include the file in your config:**


[include saved_variables.cfg]


This is optional but recommended if you reference saved variables in other config sections.

---

## Advanced Techniques

### Namespacing Variables

For complex setups, namespace your variables to avoid collisions:


SAVE_VARIABLE VARIABLE=filament:pla:z_offset VALUE=0.125
SAVE_VARIABLE VARIABLE=filament:abs:pa VALUE=0.035
SAVE_VARIABLE VARIABLE=calibration:input_shaper:x_freq VALUE=47.5


Access them as:


printer.save_variables.variables["filament:pla:z_offset"]


### Batch Saving

Save multiple related values at once (call `SAVE_VARIABLE` multiple times):


[gcode_macro SAVE_FILAMENT_PROFILE]
description: Save complete filament profile
gcode:
    SAVE_VARIABLE VARIABLE=f_{params.NAME}_z_offset VALUE={params.Z_OFFSET}
    SAVE_VARIABLE VARIABLE=f_{params.NAME}_pa VALUE={params.PA}
    SAVE_VARIABLE VARIABLE=f_{params.NAME}_temp VALUE={params.TEMP}
    SAVE_VARIABLE VARIABLE=f_{params.NAME}_bed_temp VALUE={params.BED_TEMP}
    SAVE_VARIABLE VARIABLE=f_{params.NAME}_retract VALUE={params.RETRACT}
    SAVE_VARIABLE VARIABLE=f_{params.NAME}_fan_speed VALUE={params.FAN}
    M117 Profile {params.NAME} saved


### Reading Variables Without Including the File

Even without `[include saved_variables.cfg]`, you can access variables in macros:


{printer.save_variables.variables.my_variable}


But including the file allows you to use variables as config parameters:


[heater_bed]
# This only works if the file is included
pid_kp: {printer.save_variables.variables.bed_pid_kp | default(72.426)}


### Resetting/Clearing Variables

There's no built-in `DELETE_VARIABLE`. To reset a variable, save an empty or default value:


SAVE_VARIABLE VARIABLE=my_data VALUE=None


To clear the entire file, stop Klipper and delete/truncate `saved_variables.cfg`, then restart.

---

## Integration with Macros and Slicers

### Passing Filament Info from Slicer

OrcaSlicer and others can pass custom parameters in `PRINT_START`:


# In OrcaSlicer's filament start gcode:
; filament_type = {filament_type}
; filament_vendor = {filament_vendor}

# In your PRINT_START macro:
{% set ftype = params.FILAMENT_TYPE|default("PLA") %}
{% set fvendor = params.FILAMENT_VENDOR|default("Generic") %}
{% set profile_key = fvendor ~ "_" ~ ftype %}
{% set z_off = printer.save_variables.variables["z_" ~ profile_key] | default(0.0) %}
SET_GCODE_OFFSET Z_ADJUST={z_off}


### Moonraker Integration

Moonraker's `machine.update_manager` can also benefit from save variables:


[update_manager my_repo]
type: git_repo
path: ~/printer_data/config/my_macros
origin: https://github.com/you/your-macros.git
primary_branch: main
managed_services: klipper
managed_scripts:
    - "{% if printer.save_variables.variables.auto_update | default(true) %}"
    - update
    - "{% endif %}"


---

## Troubleshooting

### Variables Not Persisting

**Symptom:** Variables reset after `FIRMWARE_RESTART`.

**Causes and solutions:**

1. **File path incorrect**: Verify the path in `[save_variables]` is writable. Check with:
   

   ls -la ~/printer_data/config/saved_variables.cfg
   


2. **File permission issue**: The Klipper service user must have write access:
   

   chown pi:pi ~/printer_data/config/saved_variables.cfg
   


3. **SD card full or read-only**: Free up space or check mount status.

### Variable Read Errors

**Symptom:** Error messages when accessing `printer.save_variables.variables.x`.

**Solution:** Always use `| default()` when accessing variables that might not exist:

{printer.save_variables.variables.my_var | default(0)}


### Corrupted Variables File

If `saved_variables.cfg` gets corrupted (e.g., power loss during save), Klipper may fail to parse it.

**Fix:** Stop Klipper, back up the corrupted file, and create a fresh empty one:

sudo systemctl stop klipper
mv ~/printer_data/config/saved_variables.cfg ~/printer_data/config/saved_variables.cfg.bak
touch ~/printer_data/config/saved_variables.cfg
sudo systemctl start klipper


You'll lose saved data but the system recovers.

---

## Performance Considerations

`save_variables` writes to disk every time `SAVE_VARIABLE` is called. Avoid calling it in tight loops:


# BAD — writes to disk 100 times
{% for i in range(100) %}
    SAVE_VARIABLE VARIABLE=temp VALUE={i}
{% endfor %}

# GOOD — only final value
{% set final = 0 %}
{% for i in range(100) %}
    {% set final = i %}
{% endfor %}
SAVE_VARIABLE VARIABLE=temp VALUE={final}


Write operations are atomic (Klipper writes to a temp file and renames), but excessive writes can wear SD cards over years of use.

---

## Complete Example: Filament Profile System

Here's a full example combining everything into a reusable macro system:


[gcode_macro FILAMENT_PROFILE_SAVE]
description: Save current settings as a filament profile
gcode:
    {% set name = params.NAME|default("default") %}
    SAVE_VARIABLE VARIABLE=fp_{name}_z_offset VALUE={printer.gcode_move.homing_origin.z|default(0)}
    SAVE_VARIABLE VARIABLE=fp_{name}_pa VALUE={printer.configfile.settings.extruder.pressure_advance}
    SAVE_VARIABLE VARIABLE=fp_{name}_temp VALUE={printer.configfile.settings.extruder.max_temp}
    SAVE_VARIABLE VARIABLE=fp_{name}_retract VALUE={printer.configfile.settings.extruder.max_extrude_only_distance}
    M117 Profile "{name}" saved

[gcode_macro FILAMENT_PROFILE_LOAD]
description: Load a saved filament profile
gcode:
    {% set name = params.NAME|default("default") %}
    {% set z_off = printer.save_variables.variables["fp_" ~ name ~ "_z_offset"] | default(None) %}
    {% set pa = printer.save_variables.variables["fp_" ~ name ~ "_pa"] | default(None) %}
    {% set temp = printer.save_variables.variables["fp_" ~ name ~ "_temp"] | default(None) %}
    
    {% if z_off is not None %}
        SET_GCODE_OFFSET Z_ADJUST={z_off}
    {% endif %}
    {% if pa is not None %}
        SET_PRESSURE_ADVANCE ADVANCE={pa}
    {% endif %}
    {% if temp is not None %}
        M104 S{temp}
    {% endif %}
    M117 Loaded profile "{name}"


---

## Summary

Klipper's `save_variables` is one of the most powerful features for Voron owners who want to move beyond basic configuration. With persistent variables you can:

- Store per-filament Z offsets and pressure advance values
- Track usage statistics and print history
- Create instant-recall filament profiles
- Persist live Z offset adjustments between prints
- Manage bed mesh profiles across different materials

The key to success is thoughtful variable naming, liberal use of `| default()`, and avoiding excessive writes to storage. Implement the examples in this guide one at a time, test thoroughly, and your Voron will reward you with a smarter, more personalized printing experience.
  

Powered by 蓝德欧科技 · Independent Voron 3D Printer Resources

Voron is an open-source 3D printer project. This site provides community-contributed build guides and resources.

Brand & domain available for acquisition — learn more
🚨

Voron LDO 商标 · 域名 打包出售

Trademark & domains sold as one package

Voron LDO 商标 (中国区 · China)
voron.cn
voronldo.com
ldovoron.com

有意者请联系 · Contact us:

📧 346290742@qq.com
📞 +86 13522926174