Run and Save Scripts in the QGIS Python Editor

The console is where PyQGIS starts and a poor place for it to stay. As soon as a task is more than three lines, retyping it after every mistake becomes the work, and the useful version of yesterday's script is somewhere in the scrollback. The editor built into the console panel fixes that for very little effort: a file you can save, re-run with one key, and keep.

This recipe belongs to QGIS Python Console Basics. It covers the editor itself, the import-caching trap that makes edits appear to have no effect, putting your own modules on the path, running a script at QGIS startup, and the point at which an external editor becomes the better tool.

Three places to write PyQGIS, and when each stops being rightThe console suits single expressions and quick inspection but loses everything on restart. The built-in editor suits saved scripts that are run repeatedly inside QGIS, with syntax highlighting and one-key execution. An external editor suits plugins and anything under version control, with real debugging and completion, at the cost of needing the environment configured.Grow out of each one deliberatelythe consoleone expression at a timeinstant feedbackhistory lost on restartoutgrown at three linesthe built-in editorsaved files, run with one keyruns inside the live QGISno debugger, basic completionthe sweet spot for scriptsan external editorversion control, refactoringreal breakpoint debuggingneeds the environment set upplugins and real projects

Prerequisites

  • QGIS 3.34 LTR (bundled Python 3.12) or newer.
  • The Python console open — Plugins → Python Console, or Ctrl+Alt+P.
  • A folder you are happy to keep scripts in; anywhere writable will do.

Open the editor and run a script

The editor is the second button on the console toolbar — "Show Editor" — and it opens a tabbed pane beside the console output. Write a file, save it, and press Ctrl+Shift+E to run it. The script executes in the same interpreter as the console, so iface, QgsProject and anything you have already imported are available, and anything the script defines stays available in the console afterwards.

"""Summarise parcel areas by ward — run with Ctrl+Shift+E."""
from qgis.core import QgsProject

def summarise(layer_name="Parcels", field="ward"):
    layers = QgsProject.instance().mapLayersByName(layer_name)
    if not layers:
        raise RuntimeError(f"no layer called {layer_name}")

    totals = {}
    for feature in layers[0].getFeatures():
        totals[feature[field]] = totals.get(feature[field], 0) + feature.geometry().area()
    return totals


if __name__ == "__console__":
    for ward, area in sorted(summarise().items()):
        print(f"{ward}: {area / 10000:.1f} ha")

Breakdown: Wrapping the work in a function and calling it under a guard means the file is useful in two ways: run it and it prints a summary, or import it and call summarise() with different arguments. The guard value is "__console__" rather than "__main__" — that is the module name the QGIS console gives to the script it runs, which is a genuine QGIS-specific detail that catches people out. Keeping the parameters as arguments with defaults rather than constants at the top means the console can experiment without editing the file.

Beware the import cache

The trap that costs everybody an hour once: a script imported as a module is cached, so editing the file and re-running the importer changes nothing.

import importlib
import my_tools

importlib.reload(my_tools)
my_tools.run()

Breakdown: Python caches modules in sys.modules on first import, and a second import my_tools is a no-op. importlib.reload() re-executes the file, which picks up your edits — but only for that module, not for modules it imports, so a package of several files may need reloading in dependency order. This is the same problem plugins have, and the same reason the Plugin Reloader tool exists, as described in Reload a QGIS Plugin Without Restarting. Scripts run from the editor with Ctrl+Shift+E are executed fresh every time and are not affected; only imports are.

Put your own modules on the path

Once a few scripts share helper functions, put them in a folder QGIS can import from.

import sys

folder = "/home/ana/pyqgis_tools"
if folder not in sys.path:
    sys.path.append(folder)

from geometry_helpers import densify        # your own module

Breakdown: Appending to sys.path at the top of a script works immediately and lasts for the session. For something permanent, the same two lines belong in the startup script described below, or the folder can be added to the PYTHONPATH environment variable before QGIS launches. Guard the append with the membership test or the path accumulates duplicates every time the script runs, which is harmless but makes sys.path unreadable when you are debugging an import problem.

Where an import actually looksAn import statement first checks the modules already loaded in memory, which is why editing a file changes nothing until it is reloaded. Only if the module is not already loaded does the search continue through the paths, in order: the current script folder, any folders added to the path, the QGIS Python libraries, and finally the system site packages.The first stop explains the edits that seem to do nothingalready imported?sys.modules cachethe script folderand your path additionsQGIS and system librariesqgis, PyQt, site packagesfound here — no rereadimportlib.reload() forces onefile read and executedthen cached for next timenot found anywhereImportError names the module

Run code at QGIS startup

QGIS runs a Python file called startup.py in the active profile folder every time it launches — the right place for path additions, small conveniences and anything you want available in every session.

# ~/.local/share/QGIS/QGIS3/profiles/default/python/startup.py
import sys

for folder in ("/home/ana/pyqgis_tools", "/home/ana/shared_gis_helpers"):
    if folder not in sys.path:
        sys.path.append(folder)

print("PyQGIS tools ready")

Breakdown: The path differs by platform — on Windows it is under AppData/Roaming/QGIS/QGIS3/profiles, on macOS under Library/Application Support — but the profile folder is always reachable from Settings → User Profiles → Open Active Profile Folder. Keep this file small and fast: it runs before the interface appears, and an exception here can prevent QGIS from starting cleanly. It is also profile-specific, which makes it a good way to keep an experimental setup separate from the profile you do real work in.

What a user profile containsA profile folder holds the startup script run at launch, the installed plugins, the settings file, and the authentication database. Because each profile has its own copy of all four, switching profiles gives a clean environment for testing without disturbing the one used for real work.Everything below belongs to one profile, not to QGISprofiles/default/python/startup.pyruns at every launchpython/plugins/what is installedQGIS3.inievery settingqgis-auth.dbstored credentials

Know when to move to a real editor

The built-in editor is deliberately modest. Three signs mean it is time to move on, all covered in Setting Up PyCharm for QGIS:

You want breakpoints. Print statements stop scaling somewhere around the third nested function. A real debugger attached to the running QGIS — the workflow in Debug a QGIS Plugin with debugpy — pays for its setup in one session.

The code is more than one file. Multi-module projects need proper navigation, refactoring and an import graph you can see. Reloading three modules by hand in the right order is a signal, not a workflow.

It belongs in version control. Anything shared, scheduled or shipped should be in a repository with tests, which means an editor that understands the project layout.

None of this makes the built-in editor obsolete. It remains the fastest way to run a fifty-line script against the project currently open in front of you, which is a large share of all PyQGIS ever written.

QGIS version compatibility

QGIS versionPythonNotes
3.22 LTR3.9Editor, Ctrl+Shift+E and startup.py all present.
3.28 LTR3.9Identical.
3.34 LTR3.12Baseline for this page.
3.40 / 3.443.12Editor gained better completion and an improved find dialog; behaviour is otherwise the same.

The console's script module name has been __console__ throughout the 3.x series, but do not rely on it in code that must also run standalone — check for both it and __main__.

Troubleshooting

  • Edits to an imported module have no effect. Module caching. Use importlib.reload(), or run the file from the editor rather than importing it.
  • ImportError for your own module. The folder is not on sys.path, or the file name does not match the import name. Print sys.path to check.
  • The script runs but nothing prints. Output goes to the console pane above the editor, which may be scrolled away or collapsed.
  • A syntax error points at the wrong line. Mixed tabs and spaces. The editor can show whitespace; turn it on once and the problem is obvious.
  • startup.py seems to be ignored. It is in the wrong profile folder. Open the active profile folder from the menu rather than guessing the path.
  • The script works once and fails on re-run. It mutates state left over from the previous run — an open edit session, a layer already added. Make scripts idempotent.

Conclusion

Use the console for one-liners and the built-in editor the moment a task is worth keeping: save the file, run it with Ctrl+Shift+E, and wrap the work in functions so the console can call them with different arguments. Remember that imports are cached and edits need a reload, add your own folder to sys.path for shared helpers, and use startup.py for anything that should be ready in every session.

Frequently Asked Questions

Does the editor run scripts in the same interpreter as the console? Yes. Everything the script defines is available in the console afterwards, and everything already imported is available to the script.

Why is __name__ not __main__? The console runs scripts under the name __console__. Check for that value, or for both, if the file should also run standalone.

Where are console scripts saved by default? Wherever you choose; QGIS offers a default folder in the profile directory but does not require it. Keeping scripts with the project they belong to is usually more useful.

Can I run a script without opening QGIS? Yes, with a standalone setup — see Running Python Scripts Outside QGIS Desktop. Anything using iface will need rewriting first.

How do I share a script with a colleague? A file plus a note about which layers it expects. If it is used often enough to be worth documenting properly, it is probably worth being a Processing script or a small plugin instead.