In Flutter 3.47, which graphics backend does the renderer use on each platform, and where does Skia still render?
answer
- Metal on Apple platforms
- Vulkan first on Android 29+
- Impeller OpenGL ES fallback
- below API 29: Skia OpenGL ES
- web stays on Skia
basics
~10 siOS and macOS: Impeller on Metal. Android API 29+: Impeller on Vulkan, else Impeller's OpenGL ES backend; below API 29, Skia on OpenGL ES. Windows and Linux: Impeller since 3.47, over OpenGL. Web: Skia.
solid answer
~40 sImpeller is portable across graphics APIs, so the backend depends on the platform. On **iOS** Impeller is the only renderer, on **Metal**; **macOS** also uses Metal and defaults to Impeller since 3.47. On **Android**, the engine selects Impeller for API 29 and newer and then tries **Vulkan** (1.1 with the required extensions), falling back to Impeller's **OpenGL ES** backend on emulators, on known-bad drivers and chipsets, or when a Vulkan context cannot be created; below API 29 (and on Vivante GPUs) it uses the legacy **Skia OpenGL ES** renderer. **Windows** and **Linux** default to Impeller since 3.47 and render through OpenGL surfaces (ANGLE on Windows). The **web** still renders with Skia. On Android you can read which backend was chosen from logcat, which prints `Using the Impeller rendering backend (Vulkan).` or `(OpenGLES).`
go deeper
Recall the short version: Apple platforms use Metal, Android prefers Vulkan, and the web still uses Skia.
Explain Android's selection: API 29 floor, Vulkan first, Impeller OpenGL ES fallback, Skia below 29, and how to read the chosen backend from logcat.
Use backend knowledge when triaging device-specific rendering bugs, include backend and chipset in reports, and treat emulators and pre-Android-10 devices as separate cases.
Factor the renderer matrix into the device support policy, deciding how long to keep testing legacy Skia paths for older Android devices.
## Renderer vs backend Two separate choices decide how a Flutter frame reaches the GPU: - the **renderer**: Impeller or the legacy Skia path, which turns the scene into drawing operations; - the **backend**: the graphics API the renderer talks to, such as **Metal**, **Vulkan** or **OpenGL ES**. Impeller was designed to be portable: its shaders are written once and compiled at engine build time into each backend's format (Metal libraries, Vulkan SPIR-V archives, OpenGL ES shader archives). So one renderer runs on several APIs. ## The platform table for Flutter 3.47 | Platform | Default renderer | Backend | |---|---|---| | iOS | Impeller (the only option) | Metal | | macOS | Impeller (default since 3.47) | Metal | | Android API 29+ | Impeller | Vulkan when usable, otherwise Impeller's OpenGL ES | | Android below API 29 | legacy Skia | OpenGL ES | | Windows | Impeller (default since 3.47) | OpenGL ES, through ANGLE | | Linux | Impeller (default since 3.47) | OpenGL | | Web | Skia | the browser's graphics stack | The web renderers themselves are a separate topic; here it is enough that Impeller is not used there yet. ## How Android chooses Android has the most varied hardware, and the engine's selection is explicit in its source: 1. If Impeller is enabled and the device runs **API 29 or newer** (and is not a Vivante GPU), the engine picks **Impeller** with automatic backend selection. Otherwise it uses **Skia on OpenGL ES**. 2. Within Impeller, it avoids Vulkan on **emulators**, on some vendors and chipsets whose Vulkan drivers are known to misbehave, and on older MediaTek devices. 3. Otherwise it tries to create a **Vulkan** context (Vulkan 1.1 with the extensions needed for platform views). If that fails, it falls back to Impeller's **OpenGL ES** backend. API 29 is the floor because Android 10 provides `HardwareBuffer` support that Impeller relies on for platform views. The public docs summarize the fallback as "the legacy OpenGL renderer" for non-Vulkan devices; the engine source distinguishes the two cases: below API 29 it is Skia, while on API 29+ without usable Vulkan it is Impeller's own OpenGL ES backend. ## Finding out what a device is using - **Android logcat** prints `Using the Impeller rendering backend (Vulkan).` or `Using the Impeller rendering backend (OpenGLES).` at startup. No such line means the Skia path. - For testing, debug and profile builds accept an `io.flutter.embedding.android.ImpellerBackend` manifest entry with the value `opengles` to force the OpenGL ES backend; this does not work in release builds. - On iOS there is nothing to check: Impeller on Metal is the only path. ## Why the backend matters to an app developer - **Bug reports need the backend.** A visual glitch that appears only on some Android phones is often backend-specific (Vulkan vs OpenGL ES) or driver-specific. The Impeller issue template asks for the device and chip. - **Emulators are not representative.** An Android emulator avoids Vulkan, so it renders through a different backend from most real devices. - **Old Android devices still behave like the Skia era.** An app with a large installed base on Android 9 and lower can still see first-run shader-compilation stutter there. - **Skia is not gone from the binary.** Under Impeller, text layout (SkParagraph) and image codecs still come from Skia components. ## Interview traps - Saying Impeller "is Vulkan": Impeller is a renderer; Vulkan is one of its backends, and iOS never uses it. - Saying non-Vulkan Android phones fall back to Skia: on API 29 and newer the engine stays in Impeller and uses its OpenGL ES backend. - Forgetting desktop: Impeller has been the default on macOS, Windows and Linux only since 3.47, so older answers that describe desktop as Skia-only are out of date. - Treating the web as part of this picture: web rendering is a separate, Skia-based design. ## Summary - Apple platforms: Impeller on Metal. - Android: Impeller on Vulkan, with Impeller OpenGL ES as the fallback on API 29+, and Skia OpenGL ES below 29. - Desktop: Impeller by default since 3.47. - Web: Skia.
- Why does an Android emulator not tell you how a Vulkan-capable phone renders?The engine deliberately avoids Vulkan on known emulators, so Impeller runs on its OpenGL ES backend there. Most modern phones use Vulkan, so a glitch or performance profile seen on an emulator may not match real devices. Check logcat's backend line and test on hardware.
- An app still supports Android 9 devices. What renderer-related difference should the team expect on them?Below API 29 the engine uses the legacy Skia renderer on OpenGL ES, not Impeller. Those devices can still show the old first-run shader-compilation stutter and may render some effects slightly differently. Treat them as a separate test target.
saying these in an interview costs you the question
- Impeller uses Vulkan on iOS.
- Every Android device renders with Impeller on Vulkan.
- An Android phone without Vulkan falls back to Skia even on API 29 or newer.
- Flutter web switched to Impeller in 3.47.
- The Android emulator uses the same backend as most real phones.