Saving and Loading Layer Styles as QML
Persist and reuse QGIS symbology from Python: saveNamedStyle and loadNamedStyle and their (message, ok) contract, sidecar QML versus styles stored in a…
TL;DR: layer.saveNamedStyle(path) writes the layer’s full symbology to a QML file and layer.loadNamedStyle(path) applies it to another layer — both return a (message, ok) pair that must be checked, because neither raises on failure. This page is part of the layer styling and symbology automation guide.
Complete Runnable Code
"""Save a layer's style to QML and apply it to other layers."""
import os
from qgis.core import QgsVectorLayer
def save_style(layer: QgsVectorLayer, path: str) -> None:
"""Write `layer`'s current symbology to `path` as QML."""
message, ok = layer.saveNamedStyle(path) # note the order: message first
if not ok:
raise RuntimeError("could not save style to %s: %s" % (path, message))
def load_style(layer: QgsVectorLayer, path: str, repaint: bool = True) -> None:
"""Apply the QML at `path` to `layer`, failing loudly if it does not take."""
if not os.path.isfile(path):
raise FileNotFoundError(path)
message, ok = layer.loadNamedStyle(path)
if not ok:
raise RuntimeError("could not load style from %s: %s" % (path, message))
if repaint:
layer.triggerRepaint()
def apply_style_to_all(layers: list[QgsVectorLayer], path: str) -> int:
"""Apply one QML to every layer whose geometry type it can actually style."""
applied = 0
for layer in layers:
try:
load_style(layer, path)
applied += 1
except RuntimeError as exc:
print("skipped %s: %s" % (layer.name(), exc))
return applied
Architecture Breakdown
saveNamedStyle() — what actually gets written
The QML is an XML document describing the renderer, its symbols and every symbol layer property, plus labelling, blend modes, layer opacity and rendering scale limits. It is a complete description of how QGIS draws the layer, and it deliberately says nothing about the data: no path, no provider, no field values.
That separation is what makes a QML reusable. The one thing it does encode implicitly is the geometry type, because a fill symbol has no meaning on a point layer — which is the most common reason a style loads without visible effect.
The return signature catches people out. It is (message, ok), not (ok, message), and unpacking it the wrong way round produces code that treats every failure as success, because a non-empty message string is truthy.
loadNamedStyle() — applying it elsewhere
Loading replaces the layer’s renderer wholesale. Properties in the QML that the target layer cannot use are ignored, which is usually what you want and occasionally hides a mismatch: a QML written from a polygon layer applied to a point layer reports success and draws nothing.
Check the flag, then check the map. Those are different assertions, and only the first is automatable.
Where QGIS looks for a style automatically
A QML sitting beside the data file with the same base name — parcels.gpkg and parcels.qml — is loaded automatically whenever the layer is opened, with no code at all. That makes the sidecar the simplest way to ship cartography with a dataset, and the easiest to forget when the data is copied without it.
For GeoPackage there is a better option: saveStyleToDatabase() stores the style inside the container, so the cartography travels in the same file as the data. For anything shared across a team, that removes the whole class of “the map looks wrong on my machine” reports.
Using It in a Pipeline
A styling script and a QML are complementary rather than alternatives. The script is the source of truth; the QML is its build output, regenerated whenever the rules change:
from qgis.core import QgsVectorLayer
def build_and_export_style(layer: QgsVectorLayer, qml_path: str) -> None:
"""Regenerate the house style from code and write it out for reuse."""
categorize(layer, "zone", ZONING) # the rules live in code
save_style(layer, qml_path) # the QML is the artefact
Committing the generated QML alongside the script gives you something reviewable: a diff on the QML shows exactly what a change to the styling rules did to the output, which is otherwise invisible until someone looks at a map.
Keeping Styles Under Version Control
A QML is XML, which means it diffs — badly, but it diffs. A change to one symbol produces a localised change in the file, and a change to the classification produces an obvious one. That is enough to make a style review a normal part of a pull request rather than something that happens by screenshot.
Two habits make it work in practice. Regenerate the file from the script rather than exporting it from the interface, so that unrelated attributes do not churn between commits. And commit the script and the QML together, so a reviewer can see both the rule that changed and what it did to the output.
Production Best Practices
- Unpack
(message, ok)in that order. Reversing it silently disables every error check. - Check the flag and look at the result. A style can load successfully and still draw nothing.
- Prefer styles stored in the GeoPackage over sidecars for data you share; a sidecar is one copy away from being lost.
- Regenerate QML from a script rather than hand-editing it. The XML is machine-written and hand edits do not survive the next export.
- Record which QGIS version wrote the file. QML carries a version, and a newer file read by older QGIS silently drops what it does not understand.
- Repaint after loading, and refresh the layer tree symbology inside a plugin, or the legend and the map will disagree.
Frequently Asked Questions
Why does my QML not apply to a different layer?
The usual cause is a geometry-type mismatch — a polygon style on a line layer. The load reports success because the document parsed; the renderer it produced simply cannot draw that geometry. Check layer.geometryType() on both layers before deciding the file is at fault.
The second cause is a renderer that references fields the target layer does not have. A categorized renderer on zone applied to a layer with no zone column produces a renderer with classes that never match, so nothing is drawn.
Can I edit a QML by hand?
You can, and for a one-off tweak it works. It is a poor habit, though: the file is generated, which means the next export overwrites your edit, and the schema is not documented as a public format. Change the script that produces it instead.
What is the difference between QML and SLD?
QML is QGIS’s own format and can express everything QGIS can draw. SLD is an OGC standard understood by map servers such as GeoServer and MapServer, and covers a much smaller set of symbol types. Exporting a rich QGIS style to SLD loses whatever the standard has no vocabulary for — usually the more elaborate symbol layers and any data-defined property.
If a style must work in both places, design it against the SLD subset from the start rather than simplifying it afterwards.
Can one QML style a whole group of layers at once?
Not directly — a style is applied to one layer at a time. What you can do is load it in a loop, which is the apply_style_to_all helper above, and the important part of that helper is that it keeps going after a failure rather than stopping on the first layer with the wrong geometry type.
For a genuinely shared look across many layers, a style stored in the layer’s own GeoPackage or a sidecar per dataset is usually more robust than one file applied by a script, because it survives somebody opening the data without running your code.
Does a QML include labelling?
Yes — labelling settings, blend modes, opacity and scale visibility are all part of the document, which is why a QML is a better unit of transfer than a renderer object. If you want the renderer alone, clone layer.renderer() in memory rather than round-tripping through a file.
Related
- Layer Styling and Symbology Automation — the parent guide covering the renderer chain
- Applying a Categorized Renderer from Python — building the renderer this page serialises
- Working with QgsProject and the Layer Registry — finding the layers a style should be applied to