Qt Widgets vs QML: Which to Choose in Qt 6 (Decision Guide)

After you land on Qt 6, the next architecture fork is usually which UI technology owns the screen: Qt Widgets or Qt Quick / QML. Pick wrong and you pay in rewrites, hiring, and tooling. Pick well and your C++ core stays stable while the UI matches the product you actually ship.

Official Qt frames the split clearly: Qt Quick is for fluid, dynamic, touch-friendly interfaces; Qt Widgets are for complex, traditional desktop applications (User Interfaces). This guide turns that comparison into a decision framework, checklists, and hybrid warnings you can take to a design review.

Free practice material while you decide: download the Qt 6.9 book examples ZIP, skim the free English Chapter 1 — Qt class hierarchy overview (also as class hierarchy overview), and if you just finished a port, cross-link your notes to the sibling pillar Qt 5 to Qt 6 Migration Checklist. German readers can start with the DE tutorial on the first program and Qt modules.

Table of contents

  1. Why this choice matters in 2026
  2. What “Qt Widgets” and “QML / Qt Quick” actually mean
  3. Official comparison at a glance
  4. Decision framework: score your product
  5. Choose Qt Widgets when…
  6. Choose Qt Quick / QML when…
  7. Hybrid apps and QQuickWidget: useful, not free
  8. Team skills, tooling, and CMake
  9. Printable decision checklist
  10. FAQ
  11. Next free steps

Why this choice matters in 2026

Qt 6 keeps both stacks first-class. That is good news and a trap. Marketing pages sometimes imply “everything is QML now.” Production reality is different: line-of-business desktops, IDEs, and admin tools still ship heavily on Widgets, while automotive HMI, medical panels, kiosks, and branded consumer UIs lean Qt Quick.

Three reasons to decide deliberately:

  • Architecture: Widgets are imperative C++ UI trees. Qt Quick is a declarative scene graph driven by QML (and usually a C++ backend). Mixing without a plan creates two UI cultures in one repo.
  • Graphics: Qt Quick is GPU-accelerated via the Scene Graph / RHI path by default. Widgets primarily paint with software/QPainter (OpenGL widgets exist but are isolated). See the official comparison table (User Interfaces).
  • Hiring and velocity: A C++-only desktop team ramps faster on Widgets. A product with designers iterating on motion and layout ramps faster on QML—if you also plan C++ integration.

If you are mid-port, finish the migration checklist first, then lock the UI strategy before you invest in new screens.

What “Qt Widgets” and “QML / Qt Quick” actually mean

Qt Widgets are the classic desktop controls: buttons, menus, dock widgets, dialogs, QTableView / QTreeView, and friends. You write most UI in C++ (or load .ui files from Qt Designer). The look integrates with Windows, Linux, and macOS desktop conventions (Qt Widgets overview; User Interfaces).

Qt Quick is the runtime and scene graph for modern UIs. QML is the declarative language you use to describe those UIs. Qt Quick Controls supplies ready-made buttons, dialogs, and menus in QML. You typically keep business logic and performance-critical code in C++, and expose it to QML (User Interfaces).

Jargon once, then we move on:

Term Plain meaning
QML Declarative UI language (plus optional JavaScript for light logic).
Qt Quick Engine + scene graph that renders QML.
Qt Quick Controls Standard control set for Qt Quick apps.
Widgets Classic C++ desktop widget toolkit.
RHI Qt’s Rendering Hardware Interface behind modern Quick graphics.

Official comparison at a glance

Qt’s own feature matrix is the best neutral baseline. Condensed from User Interfaces — Comparison of UI Technologies:

Concern Prefer Qt Quick / QML Prefer Qt Widgets
Primary languages QML + JavaScript (+ C++ backend) C++ (+ Designer .ui)
Fluid animation / transitions Built for GPU-accelerated motion Possible via QPropertyAnimation, not the design center
Touch and gestures Designed for touch / multimodal input Mouse/keyboard first; touch needs more work
Dense desktop chrome (docks, MDI-style tools) Possible, but more custom work Mature out of the box
Hardware-accelerated full-scene graphics Scene Graph / GPU path Software by default; OpenGL widgets are isolated
Rich text editors Possible with more C++ glue Mature QTextDocument / QTextEdit stack
Rapid visual prototyping Very fast in QML Fast for classic UIs with Designer

Both stacks support native look-and-feel (via Quick Controls styles vs native Widgets), custom styling, and model/view patterns—just with different idioms (same page).

Decision framework: score your product

Use this scorecard in a 30-minute architecture meeting. Score each row Widgets, Quick, or Tie. Majority wins. A near-tie means “pick a primary stack and isolate the minority UI.”

Product and UX

  1. Primary input: mouse/keyboard denseness → Widgets; touch/gesture/animation → Quick.
  2. Visual brand: platform-native tool look → Widgets (or Fusion-style Quick); custom animated brand → Quick.
  3. Information density: wide tables, trees, property grids, multi-document tools → Widgets.
  4. Screen class: desktop LOB / IDE-like → Widgets; embedded HMI / kiosk / automotive-style → Quick.

Engineering constraints

  1. Team skills today: strong C++ / weak QML → Widgets first; designers comfortable with declarative UI → Quick.
  2. Existing codebase: large Widgets app → stay Widgets (or embed Quick islands carefully); greenfield with motion requirements → Quick.
  3. Performance profile: huge item views with classic delegates → Widgets often simpler; continuous animation / shader effects → Quick.
  4. Deployment footprint and GPU: low-end terminals without GPU expectations → lean Widgets; GPU always present → Quick is fine.

Process

  1. Designer collaboration: .ui + Designer → Widgets; Design Studio / QML iteration → Quick.
  2. Test strategy: mature Widgets UI tests in-house → Widgets; visual regression on animated UI → plan Quick tooling.

Write the ten answers down. If Widgets wins 7–10 rows, do not force QML for fashion. If Quick wins 7–10, do not cling to Widgets only because “we always used C++ UI.”

Choose Qt Widgets when…

Choose Qt Widgets when most of these are true:

  • You ship a traditional desktop product: menus, toolbars, dockable panels, modal dialogs, printers, system trays.
  • Users live in tables and trees all day (ops consoles, CAD-adjacent tools, data browsers).
  • The team is C++-first and wants compile-time structure without learning QML immediately.
  • You need the mature rich text and document editing classes with minimal ceremony (comparison notes).
  • Touch is secondary; keyboard shortcuts and accessibility on desktop are primary.

Typical good fits: internal admin tools, measurement/analysis desktops, developer tools, form-heavy LOB apps.

Starter shape (conceptual): QApplication + QMainWindow + layouts + model/view. Keep build hygiene on CMake—see Qt 6 build system — CMake & qmake.

Choose Qt Quick / QML when…

Choose Qt Quick / QML when most of these are true:

  • The UI must feel fluid: transitions, physics-like motion, custom chrome, or continuous visual feedback.
  • Targets include touch panels, embedded devices, or multi-form-factor products where mouse-first Widgets fight the UX.
  • Designers iterate on layout and style weekly; QML’s declarative files are the contract.
  • You want full-scene GPU rendering and shader-based effects as a normal part of the product (User Interfaces).
  • You are willing to keep logic in C++ and treat QML primarily as the view layer (recommended for serious apps).

Typical good fits: HMI dashboards, branded consumer apps, media/visualization front ends, modern touch desktops.

For desktop-looking Quick apps, pick a Qt Quick Controls style deliberately (for example Fusion for a consistent cross-platform desktop feel, or platform-oriented styles such as FluentWinUI3 where appropriate)—see Styling Qt Quick Controls.

Hybrid apps and QQuickWidget: useful, not free

Yes, you can show QML inside a Widgets UI. Qt documents this path via Qt Quick Widgets / QQuickWidget (User Interfaces note; QQuickWidget).

Use hybrid when:

  • You have a large Widgets shell (docks, menus) and need one animated or touch-friendly panel.
  • You are migrating screen-by-screen toward Quick without a big-bang rewrite.

Respect the documented costs (QQuickWidget — Performance Considerations):

  • At least one extra render pass (offscreen buffer, then a textured quad)—more GPU fragment work.
  • Threaded render loop is disabled on all platforms when using QQuickWidget, so some Animator / vsync-driven benefits are unavailable.
  • Avoid calling winId() on a QQuickWidget (forces a native window and hurts the point of the class).
  • One top-level window should stick to one graphics API; mixing e.g. Vulkan-backed Quick with QOpenGLWidget in the same window is a known foot-gun.

Rule of thumb: hybrid is a bridge or island, not a long-term excuse to never choose a primary stack. Prefer one owner for navigation, styling, and input conventions.

CMake reminder when you do embed Quick:

find_package(Qt6 REQUIRED COMPONENTS Widgets QuickWidgets)
target_link_libraries(MyApp PRIVATE Qt6::Widgets Qt6::QuickWidgets)

(As documented on the QQuickWidget page.)

Team skills, tooling, and CMake

Skills map

Role Widgets-heavy path Quick-heavy path
C++ engineers Own UI + logic Own models, services, QML-facing types
UI designers Limited (Designer / style sheets) Central (QML, Design Studio, Controls styles)
QA Classic widget automation Add scene/visual checks for animation

Tooling

  • Qt Designer + .ui files accelerate Widgets layouts.
  • Qt Design Studio and QML tooling accelerate Quick.
  • Qt Creator hosts both workflows; the choice is the UI stack, not the IDE.

Build system

Whichever UI you pick, treat CMake as the default application build for new Qt 6 work, and keep module boundaries clear (Widgets vs Quick / QuickControls / QuickWidgets). Deep dive: Qt 6 build system — CMake & qmake. Orient modules with the free class hierarchy overview.

Printable decision checklist

Copy into your architecture ticket:

  1. Primary platform class documented (desktop LOB / embedded HMI / hybrid).
  2. Input model chosen (mouse-keyboard vs touch-first).
  3. Scorecard completed (10 rows) with named decision owner.
  4. Primary UI stack declared: Widgets or Qt Quick.
  5. Hybrid policy written: none / islands only / migration bridge with end date.
  6. If hybrid: QQuickWidget performance and graphics-API constraints acknowledged.
  7. Controls/style strategy named (native Widgets look, or Quick Controls style).
  8. C++ ownership of business logic confirmed (especially for QML UIs).
  9. CMake modules listed (Widgets, Quick, QuickControls2 / Controls, QuickWidgets as needed).
  10. Spike: one vertical slice implemented in the chosen stack before locking the roadmap.

FAQ

Is QML replacing Qt Widgets in Qt 6?

No. Qt 6 continues to document both as main UI technologies, with different strengths. Widgets remain the practical choice for many complex desktop applications; Quick remains the practical choice for fluid and touch-centric UIs (User Interfaces).

Can I use C++ with QML, or is everything JavaScript?

You should use C++ for real application logic. QML describes structure and bindings; JavaScript is optional for light UI logic. Serious apps expose C++ types and models to QML rather than rewriting business rules in script.

Should a migrated Qt 5 Widgets app rewrite to QML?

Usually no, not as a migration requirement. Port Widgets to Qt 6 first (migration checklist). Rewrite to QML only if product UX demands fluid/touch UI that Widgets cannot deliver economically.

When is QQuickWidget the wrong tool?

When the whole window is effectively a Quick app—prefer QQmlApplicationEngine / QQuickView paths instead of paying QQuickWidget’s extra pass and disabled threaded render loop (QQuickWidget docs). Also avoid it when you need stacking tricks with widgets underneath the Quick view; the docs describe hard limitations there.

Do Qt Quick desktop apps look “non-native”?

They can look native-ish or fully custom depending on Qt Quick Controls style and your assets. Styles such as Fusion give a consistent desktop appearance; other styles target platform aesthetics. You choose the trade-off deliberately (Styling Qt Quick Controls).

Which should beginners learn first?

If your first job target is desktop tools, learn Widgets + signals/slots + model/view, then sample QML. If your target is HMI / embedded / animated UI, learn QML + a thin C++ backend early. Either path still needs solid Qt Core skills—start with free Chapter 1 and the examples ZIP.

Next free steps

  1. Run the scorecard on your real product (not a toy).
  2. Build a one-screen spike in the winning stack using the free examples.
  3. Align modules with the class hierarchy overview / Chapter 1 (EN).
  4. Keep CMake clean via Qt 6 build system — CMake & qmake.
  5. If you are still on Qt 5 APIs, finish the Qt 5 to Qt 6 Migration Checklist before expanding UI scope.
  6. Optional DE: Erstes Programm & Qt-Module.

When you want a structured, book-length path through modern Qt 6.9 (Widgets, Quick, build system, and more), Max Schlee’s Qt 6.9 book is available from the same site—the free chapter and examples above are intentionally enough to make the Widgets-vs-QML call without a purchase.

Qt 5 to Qt 6 Migration Checklist (CMake + Qt5Compat + RHI)

Migrating from Qt 5 to Qt 6 is less a single rewrite and more a sequenced engineering project: stabilize on Qt 5.15, kill deprecated APIs, move the build to CMake (recommended), bridge leftover types with Qt5Compat, then validate graphics under the RHI stack. This checklist is written for C++/Qt developers who are mid-migration or evaluating effort—and it stands alone without buying anything.

Official starting points: the Porting to Qt 6 guide and the per-module Changes to Qt Modules in Qt 6 index. For a curated set of blog posts and tooling hints, see Qt’s references and hints about porting.

Free practice material while you work: download the Qt 6.9 book examples ZIP and skim the free English Chapter 1 — Qt class hierarchy overview (same topic also as class hierarchy overview). German readers can start with the DE tutorial on the first program and Qt modules.

Table of contents

  1. Why migrate in 2026
  2. Phase 0 — Prepare on Qt 5.15
  3. Phase 1 — qmake to CMake (Qt 6)
  4. Phase 2 — Qt5Compat bridge (then remove it)
  5. Phase 3 — QRegExp → QRegularExpression
  6. Phase 4 — RHI, OpenGL, and Qt Quick
  7. Phase 5 — High-DPI, modules, and Clazy
  8. Printable master checklist
  9. FAQ
  10. Next free steps

Why migrate in 2026

Qt 6 is the actively developed line: C++17 as baseline, CMake as the primary application build story, and a unified Rendering Hardware Interface (RHI) behind Qt Quick so the same scene can target OpenGL, Vulkan, Metal, or Direct3D depending on the platform. Qt 5.15 remains a useful staging release for deprecation cleanup, but long-term product work belongs on Qt 6.

KDAB’s migration overview makes the same practical point: treat 5.15 as the intermediate step, turn on deprecation warnings early, then plan CMake and RHI work as first-class workstreams (KDAB — Qt 5 to Qt 6 Migration).

Phase 0 — Prepare on Qt 5.15

The official porting guide is unambiguous: update the application to Qt 5.15 before jumping to Qt 6. APIs already deprecated or obsolete in 5.15 may be gone in Qt 6 (Porting to Qt 6).

Checklist — Phase 0

  • ☐ Build and run the full product on Qt 5.15 (same feature set you intend to port).
  • ☐ Treat compiler deprecation warnings as defects; fix or quarantine them.
  • ☐ Force deprecated Qt 5.15 APIs to fail the build with QT_DISABLE_DEPRECATED_UP_TO=0x050F00 (0x050F00 encodes 5.15.0).

qmake:

DEFINES += QT_DISABLE_DEPRECATED_UP_TO=0x050F00

CMake:

add_compile_definitions(QT_DISABLE_DEPRECATED_UP_TO=0x050F00)

(Source: Porting to Qt 6.)

  • ☐ Inventory modules you use; cross-check module changes and removed/restored module notes linked from the porting guide.
  • ☐ Prefer replacing QRegExp with QRegularExpression while still on Qt 5—both exist there, so you can unit-test the port before the Qt 6 jump (Qt5Compat blog).

Phase 1 — qmake to CMake (Qt 6)

You can keep qmake for many Qt 6 applications—the Qt build itself moved to CMake, but qmake remains supported for apps (Build System Changes in Qt 6). For new tooling and long-term maintenance, Qt and the community strongly recommend CMake (porting references blog).

Custom Qt plugins / libraries that relied on Qt 5 qmake internals must move to CMake for Qt 6 (same build-system page).

Minimal Qt 6 CMake shape

From the official Getting started with CMake pattern (Widgets variant):

cmake_minimum_required(VERSION 3.16)

project(MyApp VERSION 1.0.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt6 REQUIRED COMPONENTS Widgets)

qt_standard_project_setup()

qt_add_executable(MyApp
    main.cpp
    mainwindow.cpp
)

target_link_libraries(MyApp PRIVATE Qt6::Widgets)

Notes that matter in migration reviews:

  • Qt 6 expects C++17+.
  • qt_standard_project_setup() turns on CMAKE_AUTOMOC / CMAKE_AUTOUIC—you typically do not list headers solely for moc the way qmake did (CMake get-started).
  • Prefer qt_add_executable / qt_add_library over raw add_executable when you want Qt’s plugin linking and platform defaults.

Checklist — Phase 1

  • ☐ Create a parallel CMake build; keep the .pro until CI is green on both (or until you cut over).
  • ☐ Map QT += … → find_package(Qt6 REQUIRED COMPONENTS …) + target_link_libraries(… Qt6::…).
  • ☐ Map RESOURCES → qt_add_resources(...).
  • ☐ Map DEFINES / INCLUDEPATH → target_compile_definitions / target_include_directories.
  • ☐ Optionally bootstrap with qmake2cmake (pip install qmake2cmake), then hand-fix custom rules—the converter is a starting point, not a finished port (references blog).
  • ☐ Deep dive on site: Qt 6 build system — CMake & qmake.

Phase 2 — Qt5Compat bridge (then remove it)

When types moved out of Qt Core, the Qt 5 Core Compatibility APIs module (Qt6::Core5Compat / core5compat) keeps common Qt 5 classes available so you can compile on Qt 6 while finishing replacements (Qt5Compat blog).

Qt 5 class (compat) Prefer in new Qt 6 code
QRegExp QRegularExpression
QStringRef QStringView
QTextCodec / QTextEncoder / QTextDecoder QStringConverter / QStringEncoder / QStringDecoder
QXmlSimpleReader QXmlStreamReader
QLinkedList std::list (or QList if you do not need reference stability)

qmake:

QT += core5compat

CMake:

find_package(Qt6 REQUIRED COMPONENTS Core5Compat)
target_link_libraries(MyApp PRIVATE Qt6::Core5Compat)

Includes can stay as #include <QRegExp> or use #include <QtCore5Compat/QRegExp> (same blog; also QRegExp class docs).

Checklist — Phase 2

  • ☐ Add Core5Compat only where the linker complains—not as a permanent dumping ground.
  • ☐ Track every remaining compat type in a ticket; remove the module when the list is empty.
  • ☐ Remember: Qt5Compat is a portability bridge, not the destination architecture (also listed under add-on modules in the free class hierarchy overview).

Phase 3 — QRegExp → QRegularExpression

QRegExp is deprecated in Qt 6 and lives in Core5Compat; new code should use QRegularExpression (QRegExp documentation). The match model differs: QRegularExpression is immutable during matching and returns QRegularExpressionMatch / iterators.

High-signal porting rules (from official docs)

  • Exact match: wrap with QRegularExpression::anchoredPattern(...) instead of QRegExp::exactMatch().
  • Global match: replace indexIn loops with globalMatch() + QRegularExpressionMatchIterator.
  • Silent semantic traps: \xHHHH often needs \x{HHHH}; {,n} should become {0,n}; . does not match newline by default—use DotMatchesEverythingOption if you need Qt 5 QRegExp behavior; enable UseUnicodePropertiesOption if you relied on Unicode-aware \d / \w.
  • Wildcards: use QRegularExpression::wildcardToRegularExpression(...); pass UnanchoredWildcardConversion when you need unanchored globs.

Example — exact match:

QRegularExpression re(QRegularExpression::anchoredPattern(QStringLiteral("[a-z]+\\d+")));
if (re.match(text).hasMatch()) {
    // full-string match
}

Example — global match:

QRegularExpression re(QStringLiteral("(\\w+)"));
auto it = re.globalMatch(subject);
while (it.hasNext()) {
    const QRegularExpressionMatch m = it.next();
    // use m.captured(1) …
}

(Source patterns: Porting to QRegularExpression section on the QRegExp page.)

Checklist — Phase 3

  • ☐ Grep for QRegExp, QRegExpValidator, and related APIs.
  • ☐ Port hot paths first; keep Core5Compat only for cold leftovers.
  • ☐ Add tests for newline / Unicode / wildcard cases—these are where silent behavior changes hide.

Phase 4 — RHI, OpenGL, and Qt Quick

In Qt 6, Qt Quick’s default scene graph path is QRhi-based. There is no supported “direct OpenGL only” scene-graph path like the Qt 5 default; OpenGL remains one RHI backend among others (Graphics in Qt 6.0: QRhi, Qt Quick, Qt Quick 3D). The porting guide also warns: OpenGL is no longer guaranteed as the default on every target—test visual output (Porting to Qt 6).

Widget painting that never touched the Quick scene graph is largely unchanged; OpenGL helpers moved (for example QOpenGLWidget lives in the OpenGL Widgets module). Apps that inject OpenGL under/over Quick should pin the API explicitly, e.g. QQuickWindow::setGraphicsApi(...), so Qt Quick and your code agree (RHI blog).

Shader / material migration highlights:

  • ShaderEffect no longer takes inline GLSL strings; point vertexShader / fragmentShader at .qsb URLs produced by the qsb toolchain / qt6_add_shaders() (RHI blog).
  • Custom QSGMaterialShader follows the RHI-era API (the Qt 5.14/5.15 QSGMaterialRhiShader preview direction became the default).
  • OpenGL-specific helpers such as raw GLuint textureId() / FBO setters on Quick types were removed in favor of native-texture wrappers queryable per API.

Environment variables such as QSG_RHI_BACKEND (e.g. opengl, vulkan, metal, d3d11) remain the usual way to force a backend during testing; KDAB’s graphics guidance emphasizes identifying OpenGL-only code, converting shaders via the modern pipeline, and multi-backend QA (KDAB migration services).

Checklist — Phase 4

  • ☐ Classify graphics: Widgets-only / Quick / custom OpenGL / Qt 3D / Quick 3D.
  • ☐ Run visual regression on each shipping OS with the default RHI backend and forced OpenGL where you still depend on it.
  • ☐ Port ShaderEffect and custom materials to .qsb assets.
  • ☐ Replace removed OpenGL-only Quick APIs; use QSGRendererInterface / native texture helpers as documented.
  • ☐ For Qt 3D, know that RHI is default and a legacy OpenGL renderer may still be selectable via QT3D_RENDERER=opengl when you are not ready to port techniques (Qt 3D Render Porting to RHI).

Phase 5 — High-DPI, modules, and Clazy

High-DPI

Qt 6 enables high-DPI handling broadly and defaults the scale-factor rounding policy to PassThrough (Qt 5 behaved like Round). Widget apps can show glitches at fractional scales (e.g. 175% on Windows); restore Qt 5-like rounding if needed (Porting to Qt 6).

Modules and small API landmines

Walk the module changes index. One concrete Core example called out on the porting page: QTextStream::setCodec() → QTextStream::setEncoding().

Use the free Qt class hierarchy overview to re-orient which modules you actually need after streamlining.

Clazy Qt 6 checks

Qt documents Clazy checks dedicated to porting—run them against a Qt 5 build; the fixed code targets Qt 6 (Porting with Clazy):

  • qt6-deprecated-api-fixes
  • qt6-header-fixes
  • qt6-qhash-signature
  • qt6-fwd-fixes
  • missing-qobject-macro

Checklist — Phase 5

  • ☐ Test fractional DPI (Windows) and Retina (macOS).
  • ☐ Diff your module list against Qt 6 availability for your exact minor version (6.2 restored many gaps relative to early 6.0).
  • ☐ Run Clazy Qt 6 checks once before the final cutover.
  • ☐ Smoke-test encoding / stream / container edge cases that often slip past compile.

Printable master checklist

Copy into your ticket tracker:

  1. 5.15 baseline green; QT_DISABLE_DEPRECATED_UP_TO=0x050F00 clean.
  2. Module inventory reconciled with modulechanges.
  3. CMake builds the product; CI artifact matches qmake (if still dual-building).
  4. Core5Compat linked only for listed leftovers.
  5. QRegExp (and related) ported or explicitly deferred with tests.
  6. Quick/RHI visual QA on default + forced backends; shaders are .qsb.
  7. High-DPI policy decided and documented.
  8. Clazy Qt 6 checks applied; release candidate signed off.

FAQ

Is qmake dead in Qt 6?

No. qmake is still supported for building many Qt applications, but Qt’s own build and ongoing tooling investment center on CMake. Prefer CMake for new work and for plugins that depended on Qt 5 qmake internals (Build System Changes in Qt 6).

Must I use Qt5Compat forever?

No. Link Qt6::Core5Compat to keep compiling while you replace types such as QRegExp and QTextCodec. Plan to delete the dependency once replacements and tests are done (Qt5Compat blog).

Will my Qt Widgets app break on RHI?

Widget applications’ graphical backend is called out as largely unchanged versus Qt 5; the big RHI default shift is in Qt Quick (and related 3D stacks). Still verify High-DPI and any custom OpenGL widgets (Porting to Qt 6; RHI blog).

How do I force OpenGL for Qt Quick during migration?

Request the OpenGL RHI backend via QQuickWindow::setGraphicsApi(...) and/or QSG_RHI_BACKEND=opengl while you port custom rendering. That pins Qt Quick to the same API your OpenGL code expects (RHI blog).

Where should I start if I only have one week?

Spend the week on Phase 0 (5.15 + deprecations) and a CMake compile of the main binary with Core5Compat allowed. Defer deep Quick shader work to week two unless graphics is your release blocker—compile green first, then visual parity.

Next free steps

Work through the checklist against a small vertical slice of your app, then compare patterns with the free materials on this site:

When you want a structured, book-length path through modern Qt 6.9 (widgets, Quick, build system, and more), Max Schlee’s Qt 6.9 book is available from the same site—the free chapter and examples above are intentionally enough to start the migration without a purchase.