Port QML modules to CMake

QML modules have become more powerful and easier to use in Qt 6. The following sections describe how to port QML modules to the qt_add_qml_module CMake API.

See also Modern QML modules on how to modernize a QML module that already uses qt_add_qml_module.

Identify issues to fix

Use qmllint to support you through the process.

Each QML module defined with qt_add_qml_module has a _qmllint CMake target that you can use to identify potential issues or improvements. For a QML module called MyQmlLibrary use MyQmlLibrary_qmllint, for example. To run qmllint on all QML modules, use all_qmllint.

The warning categories of qmllint that hint at QML module issues are:

Prepare the project for qt_add_qml_module

Make qt_add_qml_module available in CMake

To make qt_add_qml_module available in CMake, add Core and Qml to your find_package call in the project's top-level CMakeLists.txt file:

find_package(Qt6 REQUIRED COMPONENTS Core Qml)

Use qt_standard_project_setup

qt_standard_project_setup sets up Qt CMake policies needed for qt_add_qml_module, among other things.

Call qt_standard_project_setup in the project's top-level CMakeLists.txt file before any qt_add_qml_module call:

qt_standard_project_setup(REQUIRES 6.8)

Use qt_add_qml_module

qt_add_qml_module is the CMake function that takes care of generating QML modules. It automatically generates qmldir and qmltypes files, and sets up tooling like qmlcachegen or qmllint.

QML modules can be added to both executable and library targets in CMake. QML modules attached to the executable target can't be used or linked by other executables, while QML modules attached to library targets can.

Add a QML module to your executable target

In this case, the source files of the QML module are treated as part of the executable itself, rather than being compiled into a separate library. This means neither a module nor plugin library for this module is created—–the module is fully integrated into the executable. As a result, the module is tied to that specific program and cannot be reused by other executables or libraries.

To add a QML module to your executable, in your CMakeLists.txt:

# pre-existing:
qt_add_executable(MyApp main.cpp)

# add this
qt_add_qml_module(MyApp
    URI MyAppModule
    QML_FILES
        Main.qml # and possibly more .qml files
)

The Main.qml should start with an upper case letter so that it can be instantiated by loadFromModule methods like QQmlApplicationEngine::loadFromModule or QQmlComponent::loadFromModule. Also, the QML module URI should be different from the target name to avoid name clashes in the build folder.

Add a QML module to your library target

To add a QML module to your library, in your CMakeLists.txt:

qt_add_qml_module(MyQmlLibrary
    URI MyQmlModule
    QML_FILES MyQmlComponent1.qml MyQmlComponent2.qml...
    SOURCES MyCppComponent1.h MyCppComponent1.cpp MyCppComponent2.h MyCppComponent2.cpp...
    RESOURCES MyResource1.png MyResource2.png...
)

qt_add_qml_module creates a SHARED library via qt_add_library if the MyQmlLibrary target does not exist yet, like in this example.

Note: Your QML module URI should be different from the target name to avoid name clashes in the build folder.

Use loadFromModule to load your QML files

Use loadFromModule to load your QML file, for example:

engine.load(QUrl(QStringLiteral("qrc:/MyQmlModule/Main.qml")));
// becomes
engine.loadFromModule("MyQmlModule", "Main");

Remove handwritten qmldir files

qt_add_qml_module automatically generates qmldir files. If you have singletons in your qmldir, declare them in your CMakeLists.txt before the qt_add_qml_module call with:

set_source_files_properties(MySingleton.qml PROPERTIES QT_QML_SINGLETON_TYPE TRUE)

Delete the handwritten qmldir after that.

Remove qmltypes files generated by qmlplugindump

qt_add_qml_module auto-generates qmltypes files when all your types are using declarative type registration, which removes the need to generate qmltypes files by hand using tools like qmlplugindump.

To achieve that, remove manual calls to qmlRegisterType and its variants. Then, register your types declaratively by using QML_ELEMENT, for example:

// add this header
#include <QtQml/qqmlregistrations.h>

class MyComponent: public QObject {
    Q_OBJECT

    // add this line to register MyComponent as 'MyComponent' in QML.
    QML_ELEMENT
    ....
};

See Registering C++ Types with the QML Type System on how to handle more complicated registration cases like foreign type registration.

Delete the handwritten qmltypes files after that.

Remove handwritten type registration plugins

qt_add_qml_module can generate a QML module plugin automatically for you. You don't need a handwritten plugin if your plugin's only task is to do type registration. Remove the plugin altogether if switching to declarative type registration did remove all the code from your plugin.

Make sure that you remove the NO_PLUGIN, NO_PLUGIN_OPTIONAL, NO_CREATE_PLUGIN_TARGET, and NO_GENERATE_PLUGIN_SOURCE arguments from qt_add_qml_module to allow automatic plugin generation.

Remove qrc files

qt_add_qml_module automatically generates qrc files. To list resources in the qrc files, like images or sound files, add them to qt_add_qml_module's RESOURCES argument. You can find the Module's resources under :/qt/qml/MyQmlLibraryModule/.

Replace directory imports with QML module imports

Replace directory imports with QML module imports. For example,

import "content" // contains SomeType.qml
// becomes
import MyQmlModule // contains SomeType.qml

SomeType {
    ...
}

Note that files inside a QML module automatically import their own QML module. You can remove the self-imports.

See also Changes to Qt QML and Modern QML modules.

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.