System requirements

Building a Day app requires Rust and the SDK or development libraries for each target. The requirements below are grouped by development host and target platform. day doctor can check the installed tools and report what is missing.

Check with day doctor

day doctor checks your development host for installed toolchains and reports missing requirements with setup guidance. The sections below describe the tools needed by each target.

day doctor                       # every toolkit buildable on this host
day doctor --toolkit android     # focus one toolkit, with full setup instructions

Bare day doctor treats a missing toolkit as a warning and exits 0, because you only need the toolkits you build for. Naming a toolkit with --toolkit turns its misses into errors and prints that toolkit’s setup text. For a full check, day doctor verify scaffolds a throwaway app and builds (and packs) it for each target; see CLI & projects.

For build errors or device connection problems, see Troubleshooting.

Every host

WhatVersionWhere
Rust1.89 or newerrustup.rs
The day CLIfrom the Day Git repositoryGetting started
Gitanygit-scm.com

Install Rust through rustup, not Homebrew or a distro package. Cross-compiled targets (iOS, Android, HarmonyOS, and the web) need rustup’s per-target standard library, which a system rustc does not carry. day build adds the one a target needs the first time it builds for it (rustup target add …, said on the terminal as it happens), so the rustup target add lines in the sections below are for doing that ahead of time, on a machine that will be offline or in a CI image. rustup update stable keeps you current.

Everything else depends on which targets you build.

Which targets build on which host

TargetmacOSLinuxWindows
macos-appkit✅——
ios-uikit✅——
windows-winui——✅
windows-xaml (deprecated)——✅
linux-gtk / windows-gtk / macos-gtk✅✅✅
linux-qt / windows-qt / macos-qt✅✅✅
android-mdc✅✅✅
harmony-arkui✅✅✅
web-dom✅✅✅

Apple’s toolkits build only on macOS, and WinUI and XAML only on Windows, because they compile against SDKs that exist only on the host OS. GTK and Qt are portable, so a macOS or Windows machine can build and run them for development even though you ship linux-gtk and linux-qt.

macOS

macOS and iOS app builds require Xcode 27 or newer. Your macOS version must support that Xcode release; check Apple’s minimum requirements if you are on an older release. Continuous integration builds on the current macos-latest runner (Apple silicon).

The GTK, Qt, Android, and web targets need Apple’s command-line development tools on macOS:

xcode-select --install

Full Xcode 27 or newer (App Store) is required for macos-appkit and ios-uikit, whose builds run through xcodebuild. Point the command-line tools at it once installed:

sudo xcode-select -s /Applications/Xcode.app
rustup target add aarch64-apple-ios-sim

Day derives build/day/xcode/macos/DayApp.xcodeproj unless an app supplies its own platform/macos/DayApp.xcodeproj. macos-appkit builds through xcodebuild, so it needs full Xcode 27 or newer too. (An app that predates the scaffold adopts it with day project add-target macos-appkit.)

Both hosts use the JSON5 project.xcproj format introduced in Xcode 27. day doctor --toolkit appkit --toolkit uikit checks the selected installation.

Homebrew provides the rest:

brew install gtk4 libadwaita librsvg pkg-config    # macos-gtk
brew install qt pkg-config                 # macos-qt
brew install openjdk@21                    # android-mdc
brew install qemu                          # the HarmonyOS emulator

Swift is needed only when a dependency embeds SwiftUI (SwiftUI embedding); Xcode and the command-line tools both provide it.

Windows

windows-winui builds on Windows 10 or 11. It renders WinUI 3 from the Windows App SDK 2.5.1; see the Windows platform page for the details.

For windows-winui, install the Visual Studio 2022 C++ Build Tools (MSVC plus the Windows 10/11 SDK) and the MSVC Rust toolchain:

rustup default stable-msvc

Development builds (day build, day launch) also need the Windows App Runtime 2.5.1 or newer, from Microsoft’s Windows App SDK downloads; an app started without it offers that page. The Windows App SDK packages themselves need no install: the build downloads them on first use (about 270 MB) into %LOCALAPPDATA%\day\winappsdk. Set DAY_WINAPPSDK to an already laid-out copy on an offline machine, or DAY_WINAPPSDK_CACHE to move the cache. day doctor --toolkit winui checks the toolchain and the runtime.

A packed app is self-contained: the runtime travels inside the .msix and the installer, so your users install nothing extra. The deprecated windows-xaml target needs the same Build Tools and toolchain but no Windows App Runtime, since it uses the XAML that ships in Windows.

For windows-qt and windows-gtk, install MSYS2 and build with a GNU Rust toolchain, because MSVC cannot link MSYS2’s import libraries, and the C++ shims are built from pkg-config’s flags, which an online-installer Qt does not ship:

# Qt: run in the MINGW64 shell
pacman -S mingw-w64-x86_64-qt6-base mingw-w64-x86_64-qt6-svg
# GTK: run in the UCRT64 shell
pacman -S mingw-w64-ucrt-x86_64-gtk4 mingw-w64-ucrt-x86_64-libadwaita mingw-w64-ucrt-x86_64-librsvg
rustup toolchain install stable-x86_64-pc-windows-gnu

On ARM64 hosts, use the CLANGARM64 environment’s mingw-w64-clang-aarch64- packages and the stable-aarch64-pc-windows-gnullvm toolchain. Build with MSYS2’s bin on PATH and RUSTUP_TOOLCHAIN set to the GNU toolchain; the Windows page walks through it.

Linux

Day’s minimums are library versions: GTK 4.10 with libadwaita 1.5, and Qt 6. Any distribution whose repositories carry those development packages works. Continuous integration builds on Ubuntu 24.04.

Native vector rendering also requires librsvg 2.52+ development files for GTK and Qt SVG development files for Qt. day doctor checks these build dependencies.

# Debian / Ubuntu
sudo apt install libgtk-4-dev libadwaita-1-dev librsvg2-dev pkg-config    # linux-gtk
sudo apt install qt6-base-dev qt6-svg-dev pkg-config                    # linux-qt
sudo apt install qemu-system-x86 qemu-system-gui unzip       # harmony-arkui (emulator)

The GTK minimums are hard requirements. Day builds stack navigation on AdwNavigationView, and its file and alert dialogs on GtkFileDialog and GtkAlertDialog; none of those exist in earlier releases. Debian 12 ships GTK 4.8 and cannot build linux-gtk; run -p linux-qt there, which needs only Qt 6, or build against a newer runtime. day doctor reports the installed versions against these minimums, so run it first; a version miss otherwise surfaces as a build failure inside gdk4-sys.

Fedora, Arch, and openSUSE ship the same libraries under different package names; check GTK’s installation page and Qt’s for the equivalents.

Day finds both toolkits through pkg-config, so it is required.

Optional: web views

The web view piece needs one extra development package on the Linux desktop toolkits. Without it the piece compiles out and renders a placeholder; the rest of the app is unaffected.

ToolkitPackageEngine
GTKlibwebkitgtk-6.0-dev (Debian/Ubuntu), mingw-w64-x86_64-webkitgtk6 (MSYS2)WebKitGTK 6
Qtqt6-webengine-dev (Debian/Ubuntu)Qt WebEngine

Two toolkit combinations have no web view package. Homebrew’s webkitgtk vends the GTK 3 API and has no bottle, so macos-gtk builds without a web view. MSYS2 ships no Qt 6 WebEngine, so windows-qt does too.

Optional: media playback

The media piece plays through GStreamer on the Linux GTK target (GtkVideo). The build needs nothing extra, but playback needs GTK’s GStreamer module and a decoder for each format. Without a decoder the player stays a blank black rectangle rather than showing an error.

# Debian / Ubuntu
sudo apt install libgtk-4-media-gstreamer gstreamer1.0-plugins-good gstreamer1.0-libav

gstreamer1.0-plugins-good reads MP4 and streams over HTTPS (qtdemux, souphttpsrc), and gstreamer1.0-libav decodes H.264 video and AAC audio, which is what most MP4 files carry; Ubuntu’s desktop install does not include it. To check a particular file or URL, run gst-discoverer-1.0 <url>: any “Missing plugins” it lists is what the player lacks.

Optional: sound effects

day-part-sound plays through libpulse on the Linux desktop toolkits, which reaches both PulseAudio and PipeWire. The build needs nothing extra. At run time the part loads libpulse-simple.so.0, which a desktop install already has. A minimal container or CI image may need it installed; without it the app runs and stays silent.

sudo apt install libpulse0          # Debian / Ubuntu
sudo dnf install pulseaudio-libs    # Fedora

Optional: packaging tools

These are needed only to produce an installable artifact with day pack. Packaging & distribution covers the formats themselves.

TargetToolInstall
linux-gtk, linux-qtflatpak-builderflatpak.org, plus the Flathub remote
linux-gtk, linux-qtlinuxdeploy and its GTK or Qt pluginlinuxdeploy releases
windows-winui, windows-xamlmakeappx, signtoolthe Windows 10/11 SDK (installed with the Build Tools)
windows-winui, windows-xamlmakensisNSIS, or choco install nsis

Without the linuxdeploy GTK or Qt plugin an AppImage still builds, but it will only run on a machine that already has the toolkit installed.

Android

Android cross-compiles the app to a JNI shared library and runs it inside a Gradle app, so it needs the Android SDK, an NDK, and a JDK regardless of which host you are on.

  1. Install the Android SDK, using Android Studio, or the standalone command-line tools. Day finds it at the platform default (~/Library/Android/sdk on macOS, %LOCALAPPDATA%\Android\Sdk on Windows, ~/Android/Sdk on Linux). If you moved it in Android Studio’s settings, Day reads the new location from there. Set ANDROID_HOME to override either.
  2. Install an NDK. Android Studio’s SDK Manager does not install one by default: open Settings ▸ Languages & Frameworks ▸ Android SDK ▸ SDK Tools and check NDK (Side by side). Without Studio, run sdkmanager --install "ndk;<version>". Studio does not put sdkmanager on PATH: it lives at <sdk>/cmdline-tools/latest/bin/sdkmanager once the Android SDK Command-line Tools package (also under SDK Tools) is installed. Day uses the newest NDK under <sdk>/ndk unless ANDROID_NDK_HOME says otherwise.
  3. You need a JDK, version 17 or newer. If Android Studio is installed, you already have one: when JAVA_HOME is unset, Day builds with Studio’s bundled JDK, the one Studio runs Gradle with. That also sidesteps a system java newer than Gradle supports. Day finds Studio in its standard install locations (the macOS app bundle, the Windows installer’s directory, and on Linux the Snap, /opt/android-studio, ~/android-studio, JetBrains Toolbox or Flathub). Set ANDROID_STUDIO_HOME for anywhere else. Without Studio, install a JDK (brew install openjdk@21, or Adoptium) and set JAVA_HOME if the java on your PATH is older than 17.

day doctor shows what it found for each of these, including which Android Studio it is using. 4. Add the Rust target and cargo-ndk:

rustup target add aarch64-linux-android    # arm64 device or emulator
rustup target add x86_64-linux-android     # x86_64 emulator
cargo install cargo-ndk

To open, build, or run the app from Android Studio, use Android Studio 2026.1.4 (Quail 4) or newer. Day’s Gradle plugin builds with the Android Gradle Plugin 9.4, and Android Studio syncs only the AGP versions it supports. day build and day launch run Gradle themselves, so they work with any Android Studio release.

Setting up an emulator

Create an AVD in Android Studio’s Device Manager, or with avdmanager create avd, then start it:

emulator -avd <name>
adb devices                 # confirm it is listed as `device`

Day can list existing AVDs with day devices list -t android-mdc and start one with day devices boot -t android-mdc AVD_NAME --wait. An AVD stays listed after its system image is removed, so day devices boot checks the image first and names the package to reinstall. See Android troubleshooting if it is not detected. Match the emulator’s ABI to an installed Rust target; an x86_64 system image needs x86_64-linux-android. Set ANDROID_SERIAL when more than one device or emulator is attached, so day launch and day drive act on the one you mean.

A booted emulator is needed only to run an app.

iOS

ios-uikit builds on a macOS host with full Xcode 27 or newer, as covered above. Xcode installs one iOS simulator runtime; add others from Xcode’s settings under Platforms (or Components, depending on your Xcode version); Apple documents the flow in Installing additional simulator runtimes.

xcrun simctl list devices          # what exists, and what is booted
xcrun simctl boot "iPhone 16 Pro"  # or open Simulator.app

day launch -t ios-uikit installs into a booted simulator, so boot one first. Apps ship to a physical device through Xcode’s normal signing setup.

HarmonyOS

HarmonyOS has two halves with different tool needs, which is why a partial install is common. The HarmonyOS platform page has the detail.

  1. The Rust cross-compile runs through cargo-ohos, which finds the OpenHarmony SDK’s native component (the NDK) and sets up the cross-compiler for cargo. Install it, download the SDK, and add the targets:

    cargo install --locked cargo-ohos                  # or: cargo binstall cargo-ohos
    cargo ohos init sdk --api 18                       # the public SDK, no account needed
    rustup target add aarch64-unknown-linux-ohos x86_64-unknown-linux-ohos

    An SDK you already have works too: point OHOS_SDK_NATIVE at its native directory.

  2. Packaging the .hap needs hvigor and ohpm, which are not part of the public SDK. They ship with the OpenHarmony command-line-tools, bundled with DevEco Studio or downloadable on their own without an account. Put their bin/ directory on PATH. hvigor builds against the SDK named by OHOS_BASE_SDK_HOME, which must use the versioned layout <dir>/<api>/…. The download above already has it: cargo ohos init sdk prints the SDK’s path, and its <version>/<host> directory is the value.

  3. Signing runs Day’s sign-hap.mjs under node, so node must be on PATH too.

hdc, which installs and launches the app, sits in the SDK’s toolchains/ directory, beside native/; Day finds it there or on PATH.

On Linux

The Linux command-line-tools bundle carries everything above: hvigor, ohpm, a bundled node, and an API 18 OpenHarmony SDK (native, ets, toolchains with hdc and the signing material) whose tools run natively on a Linux x86_64 host. So one download covers the whole build, with no separate SDK. It needs about 2.1 GB to download and 6.5 GB unpacked:

mkdir -p ~/ohos-clt && cd ~/ohos-clt
curl -fSLO https://repo.huaweicloud.com/harmonyos/ohpm/5.1.0/commandline-tools-linux-x64-5.1.0.840.zip
unzip -q commandline-tools-linux-x64-5.1.0.840.zip && rm commandline-tools-linux-x64-5.1.0.840.zip

# hvigor wants a versioned SDK layout; link the bundled SDK in as API 18.
mkdir -p ~/ohos/sdk
ln -sfn ~/ohos-clt/command-line-tools/sdk/default/openharmony ~/ohos/sdk/18

Then add these to your shell profile:

export OHOS_CLT=$HOME/ohos-clt/command-line-tools
export OHOS_SDK_NATIVE=$OHOS_CLT/sdk/default/openharmony/native
export OHOS_BASE_SDK_HOME=$HOME/ohos/sdk
export PATH=$OHOS_CLT/bin:$OHOS_CLT/tool/node/bin:$OHOS_CLT/sdk/default/openharmony/toolchains:$PATH

The bundle’s bin/hvigorw and bin/ohpm run as-is on Linux, using the bundle’s own node, and tool/node/bin puts that node on PATH for signing, so no separate node install is needed. The node wrapper scripts in the HarmonyOS notes are only for macOS. day doctor --toolkit harmonyos should now pass every check.

On macOS

Use the same Linux command-line-tools bundle for hvigor and ohpm, which are pure JavaScript, through the node wrappers in the HarmonyOS notes. The bundle’s SDK tools are Linux binaries, though, so hvigor fails with spawn ENOEXEC. Take the SDK from cargo ohos init sdk --api 18 instead: it is the macOS public SDK in the layout hvigor wants, so cargo ohos finds its NDK by itself, hdc sits in its toolchains/, and OHOS_BASE_SDK_HOME is the <version>/darwin directory the download prints.

Setting up the Oniro emulator

Day runs the Oniro OpenHarmony emulator directly under QEMU, from a public image download. You need qemu-system-x86_64 (on Linux your distribution’s, with its display modules: sudo apt install qemu-system-x86 qemu-system-gui; on macOS brew install qemu) and about 7 GB of disk: a 1.4 GB zip that unpacks to 5.5 GB of images. The zip holds an images/ directory, so unpacking it in ~/ohos/emulator lands the images at the default location:

mkdir -p ~/ohos/emulator && cd ~/ohos/emulator
curl -fSLO https://github.com/eclipse-oniro4openharmony/device_board_oniro/releases/download/v6.1/oniro_emulator.zip
unzip -q oniro_emulator.zip && rm oniro_emulator.zip     # → ~/ohos/emulator/images
day devices boot -t harmony-arkui                       # --headless for no window

The image comes from the device_board_oniro releases (v6.1, OpenHarmony 6.1, is what Day’s CI runs). Set DAY_OHOS_EMULATOR if you keep the images anywhere other than ~/ohos/emulator/images.

To test on OpenHarmony 7.0, use the x86_64_virt phone package from harmony-contrib/ohos-qemu instead (0.7 GB download, 4.7 GB unpacked). day devices boot recognizes its layout by its extra sys_prod.img and chip_prod.img, so every day command works against either image:

mkdir -p ~/ohos/ohos-qemu && cd ~/ohos/ohos-qemu
curl -fSLO https://github.com/harmony-contrib/ohos-qemu/releases/download/v20260919/openharmony-qemu-x86_64-x86_64_virt-phone.tar.gz
tar xzf openharmony-qemu-x86_64-x86_64_virt-phone.tar.gz
export DAY_OHOS_EMULATOR=~/ohos/ohos-qemu/openharmony-qemu-x86_64-x86_64_virt-phone/images
day devices boot -t harmony-arkui --headless

Apps built for API 18 install and run on 7.0 unchanged. Boot prints which OpenHarmony came up. Boot returns once the guest has finished starting, and QEMU keeps running in the background; day launch -t harmony-arkui then installs and starts the app on it.

On an x86_64 Linux host, the emulator runs KVM-accelerated when you can open /dev/kvm. That normally means membership in the kvm group:

sudo usermod -aG kvm $USER      # then log out and back in

Without it, Day falls back to TCG software emulation, and boot takes several minutes. The emulator gets six vCPUs, or as many as the host has cores when that is fewer; set DAY_OHOS_SMP to override. On macOS the emulator always runs under TCG.

On Linux the emulator window is QEMU’s SDL display, as the Oniro image’s own run.sh opens it, at the panel --device names (a 360×720 phone unless you say otherwise). That needs your distribution’s QEMU with its display modules (sudo apt install qemu-system-x86 qemu-system-gui); Homebrew’s QEMU has no SDL display, and day refuses it for a windowed boot. A panel larger than your screen comes up at the size the window manager allows; --headless keeps the requested panel. To watch a headless emulator, take screenshots with hdc shell uitest screenCap -p /data/local/tmp/s.png and hdc file recv /data/local/tmp/s.png.

The x86_64 emulator image carries an arm64-only ArkWeb engine, so the web view piece does not render there. It works on a physical device.

Web

web-dom needs only the wasm target, which the first day build -t web-dom adds; to add it yourself:

rustup target add wasm32-unknown-unknown

day build -t web-dom writes a self-contained static site, and day launch -t web-dom serves it and opens a browser.

What your apps require

These are the minimums your users need, which the scaffold sets and you can change in your project’s platform configuration — up to whatever your code needs, or down as far as the platform’s own tooling still allows. The iOS value is day-uikit’s own floor: the toolkit guards the UIKit calls that arrived after iOS 15, and a piece that needs a newer OS declares that platform floor, which day build applies to the build. They are unrelated to what your development machine needs.

TargetMinimum
macos-appkitmacOS 13
ios-uikitiOS 15
android-mdcAPI level 24 (Android 7.0), compiled against API 37
harmony-arkuiAPI level 18
windows-winuiWindows 10 version 1809 (Windows 11 recommended); packed apps carry the Windows App SDK runtime
windows-xaml (deprecated)Windows 10 or 11
linux-gtk / linux-qtGTK 4.10 with libadwaita 1.5 / Qt 6
web-doma current browser, served as static files

Check your toolchain

Run day doctor --toolkit <toolkit> before building. It checks the SDK and tool versions for that backend. The target registry lists which hosts can build each target.