Open-source project
mappu/miqt avatar
mappu/miqt

miqt: Qt bindings for Go that call Qt in process

MIT-licensed Qt bindings for Go

799 stars48 forksGoMIT

At a glance

What is it?
MIQT is an MIT licensed set of Qt bindings for Go built on CGO, covering most Qt modules and calling Qt directly instead of routing through a helper process. The trade is real: you need a Qt C++ toolchain, the first build is slow, and the licence of Qt still governs what you ship.
Who is it for?
Adopt miqt when you want a native desktop GUI in Go and need to call Qt directly rather than pay for an out of process helper, and skip it when your team cannot maintain a Qt C++ toolchain or when LGPL obligations on a commercial product are a blocker. Verify first that your Qt version falls inside the supported range of 5.15 or 6.4 and newer, and that the module you need is one of the listed modules rather than a gap in the coverage.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 15 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The binding calls Qt directly, not through a helper process

MIQT is a straightforward binding of the Qt 5.15 and Qt 6.4 and newer API using CGO. The documentation is blunt about the consequence: you must have a working Qt C++ development toolchain to use this Go binding.

The architectural choice is what separates it from the alternatives. The README describes MIQT as a clean-room binding that does not use any code from other Qt bindings, and the comparison notes that the most mature Go binding, therecipe/qt, works by making IPC calls to a separate C++ binary downloaded at runtime from a site under the maintainer's control, which the documentation says may be less performant than calling Qt directly.

That difference propagates into everything else. There is no runtime download step, no helper process to supervise, and no IPC in the hot path of your UI. The cost is on the build side, because the C++ half has to be compiled and linked into your binary.

The Go API mostly mirrors the official Qt C++ API one to one, according to the documentation, which is what makes the official Qt reference usable as your reference. The module path is `github.com/mappu/miqt/qt` for Qt 5 and `github.com/mappu/miqt/qt6` for Qt 6, and the go.mod file declares `go 1.19` as the minimum version.

Module coverage is wide, and the project says it may be rough

The list of bound modules is long: QtCore, QtGui, QtWidgets, Qt SQL, QtMultimedia, QtMultimediaWidgets, QtSpatialAudio, QtPrintSupport, QtSvg, QtScript, QtNetwork, QtWebkit, QtWebChannel, QtWebEngine, QtCharts, QtPositioning, Qt Websockets, QStateMachine, QtUiPlugin/QtUiTools, QML, QScintilla, ScintillaEdit and Qwt. Subclassing support is included, as is a uic, rcc and lupdate implementation.

That last group matters more than it first appears. A binding that only exposes types cannot be used to write a custom widget, and a binding without uic and rcc support forces you to hand compile designer files and resource files. Those pieces are what turn the library from a demo into something you can ship a real application on.

The project is candid about its state. The documentation says the bindings were newly started in August 2024 and that they may be immature in some ways, then asks people to try them and raise issues. The repository topics list `qt5`, `qt6`, `qt6-widgets`, `qtwidgets`, `bindings` and `cgo`, which matches a project still filling in the corners of a very large API.

The examples directory shows what is actually exercised: `helloworld`, `helloqml6`, `tetrix`, `modelview`, `subclass`, `systemtray`, `uidesigner`, `linguist`, `screenshot`, `lcdclock6`, `pixels`, `marshalling` and `wiggly`, in both Qt 5 and Qt 6 flavours where a version applies.

Seven platforms, static or dynamic linkage

The supported platforms table in the README is short enough to take in at a glance. Linux on x86_64 and on ARM64 work with static or dynamic `.so` linkage. Windows on x86_64 works with static or dynamic `.dll`. Android on ARM64 works with dynamic linkage bundled into the `.apk` package. FreeBSD on x86_64 works with static or dynamic `.so`. macOS works on both x86_64 and ARM64 with static or dynamic `.dylib`.

So the practical answer to a common question is yes on Linux, Windows and macOS, on both Intel and ARM, with the choice of static or dynamic left to you. That choice is not cosmetic, because it decides who has to comply with the Qt licence, which the documentation addresses directly in its second FAQ entry.

Dynamic linkage means you ship against the LGPL terms and distribute the shared libraries. Static linkage means the Qt code is compiled into your binary, and the documentation states that in that case you need a Qt commercial licence. That is a procurement question before it is a technical one, and it is the single fact that most often decides whether a project can use MIQT at all.

The first build takes about ten minutes, later builds do not

The third FAQ entry addresses compile time directly. The first time MIQT is used, a `go build` takes about ten minutes, and after that any build is very fast. The documentation also notes that Go 1.26 is significantly faster for this.

The mechanism is the CGO compilation of the binding layer and the Qt libraries themselves, which is a one time cost per machine as long as the build cache survives. That is why the documentation gives caching advice for containerised builds. If you compile inside a Dockerfile, you can cache the step by running `go install github.com/mappu/miqt/qt`.

For one shot `docker run` builds, the suggestion is to bind mount the Go build cache directory into the container.

bash
-v $(pwd)/container-build-cache:/root/.cache/go-build

The `miqt-docker` helper app does this automatically, and the Makefile shows how the build is driven: the `genbindings` target builds the helper and the generator, then runs the generator inside the container to produce the bindings.

bash
.PHONY: genbindings
genbindings: cmd/miqt-docker/miqt-docker cmd/genbindings/genbindings
	cd cmd/genbindings && ../miqt-docker/miqt-docker genbindings ./genbindings

The `clean-cache` target removes the cached JSON files under `cmd/genbindings/cachedir`, and `build-all` and `test-cmd` run the generator before the Go build and the Go test respectively.

Binary size is a Qt problem, not a Go problem

The first FAQ entry explains why the binaries are large. The advice is to compile with linker flags that strip debug information.

bash
go build -ldflags "-s -w"

The documentation gives the numbers: this reduces the `helloworld` example from 43MB to 6MB. Going further, packing the executable with UPX reaches about 2MB with `upx --best`, and about 1.4MB with `upx --lzma`.

bash
upx --best
upx --lzma

There is a third option aimed at the C++ side of the build, `miqt-docker native -minify-build`, which the documentation says uses aggressive `CFLAGS`.

The reason these numbers matter is that a Go developer expects a binary of a few megabytes, and a Qt application ships tens of megabytes regardless of how it was written. Stripping the Go binary does not shrink the Qt libraries embedded in it, which is why the remaining 6MB in the stripped example is still dominated by C++ code you did not write.

MIT covers the bindings, Qt's own terms still apply

The licensing section is short and the message is that there are two licences, not one. The MIQT Go bindings are licensed under the MIT licence, and the documentation adds that you must also meet your Qt license obligations.

The FAQ entry on commercial releases makes that concrete. Yes, you can release a proprietary commercial app with this binding, but you must meet the Qt licence obligations either by using Qt dynamically linked dll, so or dylib files under the LGPL, or by purchasing a Qt commercial licence for static linking.

Compared with the alternatives listed in the README, that is the advantage. therecipe/qt and kitech/qt.go are both LGPL, and the documentation notes that under LGPL it is extremely difficult to make a proprietary app with therecipe/qt, linking to its FAQ and issue 259 for detail. qamel is MIT licensed, but the documentation states it supports only QML and not Qt Widgets.

This is a reading of the stated licence terms and not legal advice. For a product you intend to sell, the static linking question is the one to put to your counsel, because the answer changes with the linking model rather than with anything in the Go code.

A clean-room binding with no tagged releases

The repository is not archived and the last push was on 2026-10-09, so the work is current. There are no GitHub releases at all, which means there is no version to pin to in the way you would pin a tagged release of a normal library.

The practical consequence is that you consume MIQT as a Go module at whatever commit the module proxy resolves, and the `go.mod` in the repository only declares `go 1.19`, with no version strategy of its own. The binding layer is generated rather than hand written, with `cmd/genbindings` and the `miqt-docker` helper producing the Go sources inside `qt/` and `qt6/`, alongside `libmiqt/` and the two extras directories `qt-extras/` and `qt-restricted-extras/`.

The CHANGELOG.md at the repository root is where you would look for the record of what changed between generations, and the `doc/` directory holds the documentation, including the logo and the Go reference badge links for both `qt` and `qt6`.

The honest summary is that MIQT is young, wide and unversioned. It is a good fit if you accept living at the tip of a fast moving branch and are prepared to file issues, which is exactly what the README asks for. It is a poor fit if your build requires a reproducible, tagged dependency you can point a compliance reviewer at.

Editorial conclusion

Adopt miqt when you want a native desktop GUI in Go and need to call Qt directly rather than pay for an out of process helper, and skip it when your team cannot maintain a Qt C++ toolchain or when LGPL obligations on a commercial product are a blocker. Verify first that your Qt version falls inside the supported range of 5.15 or 6.4 and newer, and that the module you need is one of the listed modules rather than a gap in the coverage.

Frequently asked questions

What do I need to build a Go application with miqt?

A working Qt C++ development toolchain, because MIQT is a binding of the Qt 5.15 and Qt 6.4 and newer API using CGO. The README states that the toolchain is a prerequisite for using the binding.

How long does the first build of a miqt application take?

The documentation states that the first `go build` takes about ten minutes because of the CGO and Qt compilation, while later builds are fast. Running `go install github.com/mappu/miqt/qt` lets you cache that step in a Dockerfile, and Go 1.26 is noted as significantly faster.

Can I ship a proprietary commercial application built with miqt?

Yes, but you must also meet the Qt licence obligations: use Qt dynamically linked dll, so or dylib files under the LGPL, or purchase a Qt commercial licence for static linking. The MIQT bindings themselves are MIT licensed.

How does miqt differ from therecipe/qt for Go?

MIQT is a clean-room binding that calls Qt directly, while therecipe/qt makes IPC calls to a separate C++ binary downloaded at runtime, which the documentation says may be less performant. therecipe/qt also does not support Go Modules or Qt 6, and its LGPL licence makes a proprietary app difficult according to the README.

Why are miqt binaries so large?

The Qt libraries compiled into the binary dominate the size. The documentation says to build with `go build -ldflags "-s -w"`, which takes the `helloworld` example from 43MB to 6MB, and further packing with `upx --best` or `upx --lzma` can bring it to about 2MB or 1.4MB.

Official sources

  1. Issues
  2. License: MIT
  3. mappu/miqt on GitHub
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mappu-miqt.svg)](https://hysenlabs.com/projects/mappu-miqt)

Was this useful?