Explain clearly on Skia vs Impeller rendering engine in flutter with some proper examples
Answer
Overview
Flutter uses a rendering engine to draw every pixel on screen. Unlike native Android/iOS which use platform UI components, Flutter paints everything itself using its own engine.
- Skia — Flutter's original rendering engine (used from Flutter 1.0 until Flutter 3.x)
- Impeller — Flutter's new rendering engine (default since Flutter 3.16 on iOS, gradually replacing Skia on Android)
What is Skia?
Skia is an open-source 2D graphics library developed by Google. It's used by Chrome, Android, Firefox, and many other products.
textFlutter Widget Tree ↓ Render Objects (layout + paint commands) ↓ ┌─────────────────────────────────┐ │ SKIA ENGINE │ │ │ │ 1. Receives paint commands │ │ 2. Compiles GLSL shaders │ │ at RUNTIME (first use) │ │ 3. Rasterizes to pixels │ │ 4. Sends to GPU │ └─────────────────────────────────┘ ↓ Screen
Skia's Problem — Runtime Shader Compilation (Jank)
dart// When you first show a complex animation: AnimatedContainer( duration: Duration(milliseconds: 300), decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), gradient: LinearGradient(colors: [Colors.blue, Colors.purple]), boxShadow: [BoxShadow(blurRadius: 10, color: Colors.black26)], ), child: child, ) // Skia behavior: // Frame 1: "I need a shader for rounded corners + gradient + shadow" // → Compiles GLSL shader on CPU (takes 50-200ms) ← JANK! // Frame 2: Shader cached → smooth 60fps // Frame 3: Smooth // // The FIRST time any visual effect is rendered, // Skia must compile a shader → causes dropped frames
This is called "shader compilation jank" or "first-run jank" — the #1 performance complaint with Flutter.
What is Impeller?
Impeller is Flutter's purpose-built rendering engine designed to eliminate shader compilation jank entirely.
textFlutter Widget Tree ↓ Render Objects (layout + paint commands) ↓ ┌─────────────────────────────────┐ │ IMPELLER ENGINE │ │ │ │ 1. Receives paint commands │ │ 2. ALL shaders PRE-COMPILED │ │ at BUILD TIME (AOT) │ │ 3. Rasterizes to pixels │ │ 4. Sends to GPU via Metal/Vulkan│ └─────────────────────────────────┘ ↓ Screen
Impeller's Solution — Pre-compiled Shaders
dart// Same complex animation as before: AnimatedContainer( duration: Duration(milliseconds: 300), decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), gradient: LinearGradient(colors: [Colors.blue, Colors.purple]), boxShadow: [BoxShadow(blurRadius: 10, color: Colors.black26)], ), child: child, ) // Impeller behavior: // Frame 1: Shader already compiled → smooth 60fps ← NO JANK! // Frame 2: Smooth // Frame 3: Smooth // // ALL shaders are pre-compiled when you run flutter build // Nothing is compiled at runtime → zero shader jank
How Skia Causes Jank — Visual Timeline
textSkia (First Run): Frame 1 │████████████████████░░░░░░│ Shader compiling (JANK - 200ms) Frame 2 │████░░░░░░░░░░░░░░░░░░░░░│ Cached - fast (16ms) Frame 3 │████░░░░░░░░░░░░░░░░░░░░░│ Cached - fast (16ms) Frame 4 │████████████████░░░░░░░░░│ NEW effect → compile again (JANK) Frame 5 │████░░░░░░░░░░░░░░░░░░░░░│ Cached - fast (16ms) Impeller (First Run): Frame 1 │████░░░░░░░░░░░░░░░░░░░░░│ Pre-compiled - fast (16ms) Frame 2 │████░░░░░░░░░░░░░░░░░░░░░│ Fast (16ms) Frame 3 │████░░░░░░░░░░░░░░░░░░░░░│ Fast (16ms) Frame 4 │████░░░░░░░░░░░░░░░░░░░░░│ Fast (16ms) Frame 5 │████░░░░░░░░░░░░░░░░░░░░░│ Fast (16ms) █ = Frame time ░ = Idle time │ = 16ms budget (60fps)
Key Differences
| Feature | Skia | Impeller |
|---|---|---|
| Shader compilation | Runtime (causes jank) | Build time (pre-compiled, zero jank) |
| First frame | Slow (compiling shaders) | Fast (shaders ready) |
| Graphics API | OpenGL ES | Metal (iOS) / Vulkan (Android) |
| Designed for | General 2D graphics (Chrome, Android, etc.) | Flutter specifically |
| Animation smoothness | Jank on first run of effects | Consistently smooth |
| Text rendering | Mature, well-tested | Improved (uses own text renderer) |
| GPU utilization | Less efficient (OpenGL overhead) | More efficient (modern GPU APIs) |
| Memory usage | Higher (shader cache grows) | Lower (fixed shader set) |
| Platform support | All platforms | iOS (default), Android (default since 3.22) |
| Maturity | Battle-tested (10+ years) | Newer (still evolving) |
Graphics API Difference
textSkia's Approach: Paint Commands → Skia → OpenGL ES → GPU ↑ Old API (2003) Higher overhead More CPU work Impeller's Approach: Paint Commands → Impeller → Metal (iOS) → GPU → Vulkan (Android) → GPU ↑ Modern APIs (2014+) Lower overhead Direct GPU access
Metal (Apple) and Vulkan (Google/Khronos) are modern graphics APIs that give more direct control over the GPU with less driver overhead than OpenGL.
When You'll Notice the Difference
Scenarios Where Skia Had Jank
dart// 1. Complex page transitions Navigator.push(context, MaterialPageRoute( builder: (_) => ComplexPage(), // First transition → jank with Skia )); // 2. First time showing a custom painter CustomPaint( painter: ChartPainter(), // First render → shader compile with Skia ) // 3. Animated blur/shadow effects BackdropFilter( filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), // Expensive shader child: child, ) // 4. Complex gradient animations AnimatedBuilder( animation: controller, builder: (_, __) => Container( decoration: BoxDecoration( gradient: SweepGradient( colors: [Colors.red, Colors.blue, Colors.green], transform: GradientRotation(controller.value * 2 * pi), ), ), ), ) // With Impeller: ALL of these are smooth from Frame 1
How to Check Which Engine You're Using
dartimport 'dart:ui' as ui; void main() { // Check if Impeller is active print('Impeller enabled: Check flutter run logs'); runApp(MyApp()); }
bash# Check in terminal when running flutter run --verbose 2>&1 | grep -i impeller # Output: "Impeller rendering is enabled" # Force Impeller ON (if not default) flutter run --enable-impeller # Force Impeller OFF (fallback to Skia) flutter run --no-enable-impeller
Skia's Workaround — SkSL Warmup (Before Impeller)
Before Impeller existed, Flutter provided a workaround for shader jank:
bash# Step 1: Record shaders during test run flutter run --profile --cache-sksl # Use app, trigger all animations, navigate all pages # Press 'M' to export SkSL shaders # Step 2: Build with pre-cached shaders flutter build apk --bundle-sksl-path flutter_01.sksl.json
This was a manual, tedious process — Impeller eliminates this entirely by pre-compiling ALL shaders at build time automatically.
Current Status (Flutter 3.22+)
| Platform | Default Engine | Status |
|---|---|---|
| iOS | Impeller | Default since Flutter 3.16, stable |
| Android | Impeller | Default since Flutter 3.22, stable |
| macOS | Impeller | Default since Flutter 3.22 |
| Web | Skia (CanvasKit) | Impeller not available yet |
| Windows | Skia | Impeller in development |
| Linux | Skia | Impeller in development |
Performance Comparison
| Metric | Skia | Impeller | Improvement |
|---|---|---|---|
| Worst frame time | 50-200ms (shader compile) | < 16ms | 3-12x better |
| 99th percentile frame | 25-40ms | 8-12ms | 2-4x better |
| Average frame | 8-12ms | 6-10ms | Slightly better |
| First animation frame | Jank (noticeable) | Smooth | Major improvement |
| Memory (shaders) | Grows over time | Fixed at build | More predictable |
| App startup | Faster (no shader pre-load) | Slightly slower (loads pre-compiled shaders) | Trade-off |
Key Takeaway: Skia compiles shaders at runtime (causing jank the first time any visual effect renders). Impeller pre-compiles all shaders at build time, eliminating jank entirely. Impeller also uses modern GPU APIs (Metal/Vulkan) instead of OpenGL for better performance. For new Flutter projects, Impeller is the default — you don't need to do anything special to use it.
Learn more at Flutter Impeller and Flutter Rendering Architecture.