Impeller Rendering Engine
3 min read
Flutter Internals
| Skia (legacy) | Impeller (modern default) | |
|---|---|---|
| Shader compilation | At runtime — first frame using a new shader jitters | Precompiled at build time — no shader-compile jank |
| Graphics API | OpenGL (deprecated by Apple) | Metal (iOS), Vulkan (Android), OpenGL (legacy Android fallback) |
| Designed for | General-purpose 2D graphics (used by Chrome, Android, etc.) | Flutter's specific rendering needs |
| Frame consistency | Variable — worse on first frame with a new shader | More predictable |
| Status (as of 2026) | Available behind a flag; legacy | Default on iOS (3.16+) and Android (3.27+) |
The original Skia path had a long-standing class of bugs known as "shader compilation jank" — the first time the GPU saw a new shader, it took a few ms to compile, causing a visible stutter. Impeller eliminates that entirely.
What changes for app developers
For most code: nothing. The framework hides the engine. The places it can matter:
| Scenario | Notes |
|---|---|
Custom FragmentShader usage | Works on Impeller, but the build pipeline handles compilation |
Heavy use of BackdropFilter | Generally faster on Impeller |
| Specific paint operations that hit Skia bugs | May render slightly differently — test on both engines |
| Older devices (Android < 7 without Vulkan) | Falls back to OpenGL Impeller path; some perf characteristics differ |
| Profile/benchmarks made on Skia | Re-run on Impeller — numbers will shift |
You can opt out (or in) per-platform via the impeller-enabled flag in Info.plist (iOS) / AndroidManifest.xml (Android), but the default is now the right choice for nearly all apps.
When this question comes up in interviews
Interviewers typically want to know that you:
- Understand the user-visible problem Impeller solves (shader jank).
- Know it's not just "newer renderer" but a deliberate API choice (Metal/Vulkan instead of OpenGL).
- Recognise that your existing Flutter code keeps working — it's an engine swap, not a framework change.
Common mistakes to avoid
❌ "Impeller makes apps faster" — too vague.
✅ "Impeller removes shader compilation jank by precompiling at build time."
❌ Treating Skia as gone for good.
Skia still ships as a fallback for some edge cases; Impeller doesn't erase it.
❌ Assuming custom shaders break.
FragmentShader works on Impeller; build pipeline handles the precompilation.
❌ Benchmarking app perf on debug mode.
Engines differ but DEBUG instrumentation dominates — always measure in profile or release.
❌ Forcing the legacy Skia path "for compatibility" without a real reason.
The default is Impeller for good reason; opt out only if you've reproduced a specific bug.
Interview follow-ups
-
What problem did Impeller solve that Skia couldn't? Shader compilation jank. On Skia, the first frame a shader was used, the engine had to compile it at runtime — visible stutter. Impeller precompiles all shaders during the app build, so every frame uses already-compiled GPU code.
-
Why move from OpenGL to Metal/Vulkan? OpenGL is deprecated on Apple platforms and increasingly legacy on Android. Metal and Vulkan are modern, lower-overhead APIs that give the engine finer control over GPU command submission. Better baseline performance, fewer driver quirks, future-proof.
-
Is Skia gone for good? Not entirely. Skia still exists in some fallback paths (older Android devices without Vulkan, certain edge cases). But for the user-facing default on supported platforms, Impeller is the engine.
-
How would you debug a rendering issue that reproduces on Impeller but not Skia? File it as a Flutter engine bug with a minimal reproduction. Until fixed, you can toggle engines via platform manifest flags. In the meantime, work around the specific paint operation — common culprits are exotic
BlendModes, certainImageFiltercombinations, or large saveLayer scopes.
How helpful was this content?
Please sign in to rate this article.