I changed my mind about Vector Graphics

Managing image assets in a Flutter app can quickly become tedious. Every image must look sharp at various screen sizes and pixel densities. This often means preparing multiple versions of the same asset—one for each device resolution you want to support.

This got me thinking: why not use vector graphics—like SVGs—as much as possible? Vector images scale cleanly at any size, so I could eliminate the need for multiple versions of the same asset. I could use a single file for icons, illustrations, and UI elements, and be done with it.

It seemed like the perfect solution: simpler asset management, crisp visuals on any device, and fewer files to maintain.

Modern hardware is powerful. Surely it can handle rendering a few SVGs without breaking a sweat… right?

Well, here’s what I learned: I was wrong.

 

The hidden cost of Vector Graphics

It’s easy to think of SVGs and other vector formats as “free” in terms of performance, but that’s not the case—especially in environments like Flutter.

What really happens when you display a vector graphic?

Every vector image must go through several steps before it appears on screen:


  • Parsing: The SVG file—essentially XML—has to be read and parsed. The rendering engine analyzes each element (paths, shapes, groups, styles) and builds an internal representation of the drawing instructions.
  • Tessellation: The shapes in the SVG (lines, curves, circles, etc.) are converted into polygons or triangles that the GPU can render efficiently. This is done on the CPU. For complex SVGs, this can mean a large number of operations—sometimes far more than a comparable raster image.
  • Rasterization: Finally, the GPU takes the polygon data, applies shaders, and outputs pixels to the screen.

In the end, the GPU is still displaying a bitmap—a matrix of pixels—just as it would if you had used a pre-made raster image like PNG or WebP. The difference is that you’ve burned CPU cycles (and maybe GPU cycles too) to generate that bitmap at runtime.

Why does this matter?

  • Extra processing: Each time you render an SVG (especially if it’s dynamic or changes size), your app spends CPU time on parsing and tessellation. This can cause frame drops or jank, particularly on lower-end devices.
  • Battery impact: More CPU and GPU work means more power consumption, which can hurt battery life.
  • Memory footprint: Once rasterized, the memory usage is similar to a raster image—so you don’t save memory by using a vector graphic at runtime.

The Performance of Raster Images

Raster images, on the other hand, come pre-baked. There’s no runtime tessellation or rasterization—they’re ready for the GPU to display. But raster images have their own (smaller) cost to be aware of:

  • Compression and decompression: Raster formats like PNG and WebP are compressed to reduce app bundle size. Before the GPU can use them, the CPU must decompress the image into raw pixel data. This decompression happens the first time the image is loaded into memory.

For small icons and UI elements, this decompression cost is usually negligible. But if you have a lot of small individual images, each one needs to be decompressed separately—which can add up.

That’s where sprite sheets come in. I will come back to it below.

 

Why raster images are better for the user

In most cases, using raster images is faster and more efficient:

No runtime processing — The image is ready to display as-is.

Faster rendering — Fewer CPU and GPU cycles are needed, improving responsiveness.

Better battery life — Less computation means less power drain.

Predictable performance — You avoid surprises from inefficient SVGs with hidden complexity.

Another often overlooked issue: optimizing SVGs is hard.

  • SVGs are powerful, but that means they can also be inefficient if not carefully crafted. Many designers (understandably) focus on visual fidelity rather than performance.
  • Some tools export SVGs filled with unnecessary data, redundant nodes, or overly complex paths.
  • Flutter’s SVG rendering support is limited. It doesn’t handle all SVG features, so you may end up spending time cleaning up or simplifying your files anyway.

In short: you don’t really save time. You just shift the work to a different (and often more frustrating) part of the workflow.

 

The app bundle tradeoff

There is one valid advantage to vector graphics: smaller app size.

If you’re targeting platforms where bundle size is critical (e.g., web apps or very low-end devices), using SVGs can help keep the app lightweight. But even here, I’ve found it’s usually worth accepting slightly larger app bundles to deliver better runtime performance—especially for first launch and animation smoothness.

For me, user experience matters more than shaving off a few megabytes from the bundle.

 

Simplifying my workflow: introducing icon_bundler

Despite all this, I still like the idea of managing my assets as SVG source files. It keeps things simple from a design and maintenance perspective.

That’s why I created icon_bundler — a tool that lets me have the best of both worlds.

What does icon_bundler do?

  • It takes a directory of SVG files as input.
  • It generates a sprite sheet: a single raster image containing all the icons at multiple pixel densities (e.g., 1x, 2x, 3x).
  • It generates a Dart widget that can render individual icons from the sprite sheet.
  • It supports dynamic coloring and resizing of icons, without having to re-rasterize anything at runtime.

Now, I can work with clean, simple SVG files in my source code—but ship efficient, pre-rasterized assets in my app.

It is open-source and available on Github and pub.

The result?

  • A single command generates all my icons.
  • Using sprite sheets means you only pay that decompression cost once for a whole set of icons.
  • My app stays fast and efficient.
  • My design workflow stays clean and maintainable.
 

Conclusion

I’ve completely changed my approach:

“Always use raster images first, unless you truly need dynamic, advanced vector visuals.”

Vector graphics are a fantastic tool—but they aren’t a silver bullet. In most apps, prioritizing raster assets means better performance, smoother animations, and a happier end-user.

Next
Next

Hidden Gems in My Flutter Toolbox