QDT Profile¶
A QDT profile is a regular QGIS profile folder with a profile.json file at its root. QDT reads this file to identify, compare, filter and complete the profile during deployment.
Tip
Since writing a JSON file from scratch is not recommended for mental health, it’s better to:
start from project’s examples
get inspired by public projects
use the Profile Manager plugin for QGIS
add the
$schemakey pointing to the JSON schema to get completion and validation in your code editor.
Attributes details¶
The Optional column reflects the JSON schema, used for validation in code editors. QDT itself does not validate profile.json at runtime: missing attributes are ignored and unknown ones are silently dropped.
alias¶
Optional |
Default |
|---|---|
|
Profile’s name in a human readable form, allowing special characters. Informative only: not used by QDT jobs.
deprecated¶
Added in version 0.49
Optional |
Default |
|---|---|
|
|
When it’s set to true, the profile is not deployed anymore: it’s excluded from every job dealing with profiles.
Its installed folder can also be removed from the end-user machine by the cleanup-manager job, through its profiles_deprecated scope.
It’s the recommended way to retire a profile: keep it in your repository with the flag, so QDT can clean up the machines where it has been deployed, instead of removing it from the repository and leaving it installed everywhere.
description¶
Optional |
Default |
|---|---|
|
Profile description. Informative only: not used by QDT jobs.
email¶
Optional |
Default |
|---|---|
|
Contact email.
folder_name¶
Optional |
Default |
|---|---|
|
Name of the profile’s directory in QGIS.
icon¶
Optional |
Default |
|---|---|
|
Path to the icon used by the shortcuts manager job, relative to the profile’s root folder. When set and the file exists, it takes precedence over the icon set in the scenario.
If a file with the same stem and the extension preferred by the operating system exists alongside (.ico on Windows, .png or .svg on Linux, .icns on macOS), it is used instead. Otherwise, the original file is used as is.
name¶
Optional |
Default |
|---|---|
|
Profile name without any special characters. It’s used:
as the folder name of the installed profile (
QGIS/QGIS3/profiles/{name}),to match the
profilevalue used in scenario jobs (shortcuts, splash screen…), along with the name of the profile’s folder in the source.
qdtMinVersion¶
Added in version 0.45
Optional |
Default |
|---|---|
|
Optional attribute to state the minimum QDT version required to deploy the profile (following simple SemVer). If the running QDT is older than this, the profile is skipped during synchronization.
qgisMaximumVersion¶
Optional |
Default |
|---|---|
|
Maximum QGIS version (included) where the profile can be deployed. It should comply with SemVer (X.Y.Z).
The profile is not deployed if the targeted QGIS version is out of bounds. See Deploying a profile only on compatible QGIS versions.
Its installed folder can also be removed from the end-user machine by the cleanup-manager job, through its profiles_incompatible_qgis scope.
Tip
Behind the scenes, we use the official Python package ‘packaging’ to compare versions. So for example, "qgisMaximumVersion": "3.40" is equivalent to "qgisMaximumVersion": "3.40.0" so QGIS 3.40.1 and later are out of bounds. Use 3.40.99 to include every 3.40 release.
qgisMinimumVersion¶
Optional |
Default |
|---|---|
|
Minimum QGIS version (included) where the profile can be deployed, included. It should comply with SemVer (X.Y.Z).
The profile is not deployed if the targeted QGIS version is out of bounds. See Deploying a profile only on compatible QGIS versions.
Its installed folder can also be removed from the end-user machine by the cleanup-manager job, through its profiles_incompatible_qgis scope.
splash¶
Optional |
Default |
|---|---|
|
Path to the image used as QGIS splash screen, relative to the profile’s root folder. Used by the splash screen manager job.
version¶
Optional |
Default |
|---|---|
|
Profile version. Must comply with SemVer (X.Y.Z).
Used by the profiles synchronizer job to compare downloaded and installed profiles, depending on its sync_mode. If missing on either side, versions can’t be compared.
plugins¶
List of plugins to be installed in the profile.
Example for a plugin from the official repository:
{
"plugins": [
{
"name": "Profile Manager",
"folder_name": "profile_manager",
"official_repository": true,
"plugin_id": 3547,
"version": "0.7.4"
}
]
}
folder_name¶
Optional |
Default |
|---|---|
|
Name of the plugin folder once installed (python/plugins/{folder_name}). If not set, it’s deduced from the download URL, then from the slugified name.
Also used to build the download URL for the official repository.
location¶
Optional |
Default |
|---|---|
|
|
Where the plugin archive is located: remote or local. Also accepted under the type key. Invalid values fall back to remote.
name¶
Optional |
Default |
|---|---|
|
Plugin name, as referenced in the source plugins repository.
official_repository¶
Optional |
Default |
|---|---|
|
true if the plugin is published on plugins.qgis.org. Automatically set when url or repository_url_xml point to it.
When true and url is not set, the download URL is built from folder_name (or name) and version.
plugin_id¶
Optional |
Default |
|---|---|
|
Plugin ID in the repository. Used to name the downloaded archive in QDT’s cache.
Tip
To retrieve the ID of a plugin see this page.
qgisMaximumVersion¶
Optional |
Default |
|---|---|
|
Maximum QGIS version where the plugin can be installed.
Warning
Informative only: not yet used by QDT.
qgisMinimumVersion¶
Optional |
Default |
|---|---|
|
Minimum QGIS version where the plugin can be installed.
Warning
Informative only: not yet used by QDT.
repository_url_xml¶
Optional |
Default |
|---|---|
|
URL to the plugins repository XML file. Used with folder_name (or name) and version to build the download URL when url is not set.
upgrade_mode¶
Added in version 0.41
Optional |
Default |
|---|---|
|
|
By default, when upgrading a plugin, the new version is unpacked on top of the existing folder (keep mode). This works well in most cases but can cause issues when a plugin removes or renames files between versions: leftover files from the old version may remain and cause conflicts or unexpected behavior.
Setting upgrade_mode to delete on a plugin ensures a clean installation by removing the existing plugin folder before unpacking the new version. This is recommended for plugins that are known to have breaking changes between versions or that do not handle leftover files gracefully.
Example in profile.json:
{
"plugins": [
{
"name": "my_plugin",
"version": "2.0.0",
"official_repository": true,
"upgrade_mode": "delete"
}
]
}
Possible values:
keep(default): existing plugin folder is kept, newer version is unpacked on top of it.delete: existing plugin folder is deleted before unpacking the new version.
url¶
Optional |
Default |
|---|---|
|
Direct URI (URL, file:// or local path) to the plugin archive (.zip). Takes precedence over the other ways to build the download URL.
version¶
Optional |
Default |
|---|---|
|
|
Version of the plugin to install. Used to build the download URL and to compare with the installed version. Set it explicitly.
rules¶
Added in version 0.34
You can add rules to make the profile deployment conditional. In the following example, the profile will be deployed only on Linux:
{
"$schema": "https://raw.githubusercontent.com/qgis-deployment/qgis-deployment-toolbelt-cli/main/docs/schemas/profile/qgis_profile.json",
"name": "only_linux",
"folder_name": "qdt_only_linux",
"description": "A QGIS profile for QDT with a conditional deployment rule.",
"author": "Julien Moura",
"email": "infos+qdt@oslandia.com",
"qgisMinimumVersion": "3.34.0",
"qgisMaximumVersion": "3.99.10",
"version": "1.7.0",
"rules": [
{
"name": "Environment",
"description": "Profile is configured to run only on Linux.",
"conditions": {
"all": [
{
"path": "$.environment.operating_system_code",
"value": "linux",
"operator": "equal"
}
]
}
}
]
}
The rules engine is based on Python Rule Engine project whom rules syntax belongs to JSON Rules Engine.
Added in version 0.38
You can also deploy profiles based on environment variables. In the following example, the profile will be deployed only if QDT_IS_GIS_ADMIN exists:
{
"$schema": "https://raw.githubusercontent.com/qgis-deployment/qgis-deployment-toolbelt-cli/main/docs/schemas/profile/qgis_profile.json",
"name": "only_gis_admin",
"folder_name": "qdt_only_gis_admin",
"description": "A QGIS profile for QDT with a conditional deployment rule for GIS admin",
"author": "Julien Moura",
"email": "infos+qdt@oslandia.com",
"qgisMinimumVersion": "3.34.0",
"qgisMaximumVersion": "3.99.10",
"version": "1.7.0",
"rules": [
{
"name": "QDT_IS_GIS_ADMIN exists",
"description": "Deploy only if $env:QDT_IS_GIS_ADMIN exists",
"conditions": {
"all": [
{
"path": "$.env.QDT_IS_GIS_ADMIN",
"operator": "not_equal",
"value": ""
}
]
}
}
]
}
By default, only prefixed variables can be used in rules. Default prefixes are QDT_ and QGIS_. You can use your own prefixes in scenario settings:
[...]
settings:
RULES_VARIABLES_PREFIX: "QDT_,QGIS_,MYPREFIX_,MYOTHERPREFIX_"
[...]
You can by-pass prefix check by setting RULES_ONLY_PREFIXED_VARIABLES to false in scenario settings.
Warning
Be careful if you allow all variables, as it could cause security issues.
Nested conditions¶
all and any can contain other all / any groups, so that you can combine conditions with both logical operators. In the following example, the profile is deployed from September 2026 to September 2027, or whenever QDT_ATTENDEE is set to true:
{
"rules": [
{
"name": "Event window or attendee",
"description": "Deploy during the event period or if the attendee flag is set.",
"conditions": {
"any": [
{
"all": [
{
"path": "$.date.current_year",
"operator": "equal",
"value": 2026
},
{
"path": "$.date.current_month",
"operator": "greater_than_inclusive",
"value": 9
}
]
},
{
"all": [
{
"path": "$.date.current_year",
"operator": "equal",
"value": 2027
},
{
"path": "$.date.current_month",
"operator": "less_than_inclusive",
"value": 9
}
]
},
{
"path": "$.env.QDT_ATTENDEE",
"operator": "equal",
"value": "true"
}
]
}
}
]
}
Conditions and rules context¶
Rules is a set of conditions that use logical operators to compare values with context (a set of facts) which is exposed as a JSON object. Here comes the context for a Linux environment:
{
"date": {
"current_day": 10,
"current_month": 11,
"current_weekday": 1,
"current_year": 2026
},
"env": {},
"environment": {
"computer_network_name": "runnervmwuk1x",
"linux_distribution_name": "Ubuntu",
"linux_distribution_version": "26.04",
"operating_system_code": "linux",
"operating_system_release": "7.0.0-1019-azure",
"processor_architecture": "x86_64",
"windows_edition": null
},
"user": {
"groups_domain": [],
"groups_local": [
"adm",
"docker",
"systemd-journal",
"users"
],
"name": "runner",
"windows_extended": null
}
}
To help you writing rules, QDT provides a command to export rules context:
qdt export-rules-context -o qdt_rules_context.json
Model definition¶
The project comes with a JSON schema describing the model of a profile.
Put this line at the top of the profile.json to get completion and validation in your code editor:
{
"$schema": "https://raw.githubusercontent.com/qgis-deployment/qgis-deployment-toolbelt-cli/main/docs/schemas/profile/qgis_profile.json",
[...]
}
Here is the schema:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://github.com/qgis-deployment/qgis-deployment-toolbelt-cli/raw/main/docs/schemas/profile/qgis_profile.json",
"$comment": "A QGIS profile described in a JSON file in the QDT formalism.",
"type": "object",
"properties": {
"alias": {
"description": "Profile's name in an human readable form, allowing special characters.",
"type": "string"
},
"author": {
"description": "Name of profile author and maintainer.",
"type": "string"
},
"deprecated": {
"default": false,
"description": "If true, the profile is not deployed anymore. Its installed folder can also be removed from the end-user machine by the cleanup-manager job, through its 'profiles_deprecated' scope.",
"type": "boolean"
},
"description": {
"description": "Profile description.",
"type": "string"
},
"email": {
"description": "Email of profile's author and maintainer.",
"format": "email",
"maxLength": 127,
"minLength": 6,
"type": "string"
},
"folder_name": {
"description": "Name of the profile's directory in QGIS.",
"type": "string"
},
"icon": {
"description": "Relative path to the icon used for shortcuts.",
"type": "string"
},
"name": {
"description": "Profile name without any special characters.",
"type": "string"
},
"qdtMinVersion": {
"description": "Minimum version of QGIS Deployment Toolbelt required to deploy this profile. Must follow Semver. If the running QDT version is older, the profile is not deployed.",
"type": "string",
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$",
"examples": [
"0.45.0"
]
},
"plugins": {
"description": "Plugins installed with the profile.",
"title": "QGIS Plugins",
"type": "array",
"items": {
"$ref": "qgis_plugin.json"
}
},
"qgisMaximumVersion": {
"description": "Maximum QGIS version where the profile can be deployed. It should complies with SemVer.",
"maxLength": 14,
"minLength": 5,
"pattern": "^(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)$",
"type": "string"
},
"qgisMinimumVersion": {
"description": "Minimum QGIS version where the profile can be deployed. It should complies with SemVer.",
"maxLength": 14,
"minLength": 5,
"pattern": "^(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)$",
"type": "string"
},
"rules": {
"description": "Logical rules based on contextual elements that condition profile deployment.",
"title": "QGIS Plugins",
"type": "array",
"items": {
"$ref": "rules.json"
}
},
"splash": {
"description": "Relative path to the splash image.",
"type": "string"
},
"version": {
"description": "Profile version. Must complies with SemVer.",
"maxLength": 14,
"minLength": 5,
"pattern": "^(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)$",
"type": "string"
}
},
"required": [
"author",
"email",
"name",
"version"
]
}
With a submodel for plugin object:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://raw.githubusercontent.com/qgis-deployment/qgis-deployment-toolbelt-cli/main/docs/schemas/profile/qgis_plugin.json",
"$comment": "A QGIS plugin described in a JSON file.",
"type": "object",
"properties": {
"folder_name": {
"description": "Name of the plugins's directory once installed in QGIS. Useful when name does not complies with filename conventions.",
"type": "string"
},
"location": {
"description": "Indicates if the plugin is located on a remote server or on local drive/network.",
"enum": [
"local",
"remote"
],
"type": "string"
},
"name": {
"description": "Plugin name, as referenced in the source plugins repository.",
"type": "string"
},
"official_repository": {
"description": "Indicates if the plugin is referenced on plugins.qgis.org",
"type": "boolean"
},
"plugin_id": {
"description": "Plugin ID as referenced into the repository (XML version). Typically for official repository: https://plugins.qgis.org/plugins/plugins.xml?qgis=3.22",
"type": "number"
},
"qgisMaximumVersion": {
"description": "Maximum QGIS version where the plugin can be installed.",
"maxLength": 14,
"minLength": 3,
"pattern": "^(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)$",
"type": "string"
},
"qgisMinimumVersion": {
"description": "Minimum QGIS version where the plugin can be installed.",
"maxLength": 14,
"minLength": 3,
"pattern": "^(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)$",
"type": "string"
},
"repository_url_xml": {
"description": "URL to the plugin repository file (XML).",
"type": "string",
"examples": [
"https://oslandia.gitlab.io/qgis/ngp-connect/plugins.xml"
]
},
"upgrade_mode": {
"description": "Indicates whether the existing plugin folder should be deleted or not when upgrading.",
"default": "keep",
"enum": [
"delete",
"keep"
],
"type": "string"
},
"url": {
"description": "Direct URI (URL or local path) to download the plugin archive (.zip).",
"type": "string",
"format": "uri",
"examples": [
"https: //plugins.qgis.org/plugins/QuickOSM/version/2.2.2/download/",
"/home/jmo/Git/Oslandia/QGIS/stsi-plugin-qgis-geocoder-locator-filter/stsi_locator_filter.1.0.0.zip"
]
},
"version": {
"description": "Version of the plugin to be installed.",
"type": "string"
}
}
}
Sample profile.json¶
{
"$schema": "https://raw.githubusercontent.com/qgis-deployment/qgis-deployment-toolbelt-cli/main/docs/schemas/profile/qgis_profile.json",
"name": "demo_qdt",
"folder_name": "demo_qdt",
"description": "QGIS profile made to demonstrate how QGIS Deployement Toolbelt works.",
"author": "Julien Moura",
"email": "qgis@oslandia.com",
"icon": "images/qgis_icon_oslandia.ico",
"qgisMinimumVersion": "3.24",
"qgisMaximumVersion": "3.99",
"version": "1.1.0",
"plugins": [
{
"name": "Layers menu from project",
"folder_name": "menu_from_project",
"official_repository": true,
"plugin_id": 43,
"version": "2.1.0"
},
{
"name": "QuickOSM",
"folder_name": "QuickOSM",
"location": "remote",
"official_repository": true,
"plugin_id": 2733,
"version": "2.1.1"
},
{
"name": "QTribu",
"folder_name": "qtribu",
"official_repository": true,
"plugin_id": 2733,
"version": "0.14.2"
}
]
}