AppImage, Snap, and Flatpak — The Honest Review

Posted by Andrew Denner on March 20, 2026 · 22 mins read

I gave this talk at CIALUG on March 18, 2026. This is the long-form version — the full opinionated breakdown of all three universal Linux package formats, informed by years of using each of them, occasionally loving them, and at least twice nuking them from orbit.

Fair warning: I have opinions. The facts are accurate to the best of my knowledge. The takes are mine.


Why These Formats Exist (And Why It’s Not Your Distro’s Fault)

Let me start with the thesis, because I’m tired of people framing this wrong.

Linux does not have an app problem. Linux has a distribution contract problem.

Your distro’s package maintainers have a job: make sure every package in the repo works together, doesn’t break your server at 2am, and doesn’t introduce security vulnerabilities by surprise. They optimize for stability, security, and policy. This is a good job and they do it well.

App developers have a different job: ship software that uses the latest version of every library they depend on, tested against their own development environment, on a timeline that doesn’t involve waiting for Debian to unfreeze. They optimize for shipping fast and not answering bug reports about Ubuntu 18.04.

These goals are fundamentally incompatible, and no amount of goodwill makes them compatible. Universal packages are the peace treaty: the app developer bundles everything their app needs into one isolated unit, and your distro doesn’t have to care what’s in it.

The catch — and I want you to internalize this before we go further — is that you’ve moved the problem, not solved it. You didn’t eliminate dependency hell. You moved it into a zip file. The zip file now weighs 400 megabytes. Some people think this is progress.


AppImage: The Cowboy Method

AppImage is the oldest of the three formats and, in some ways, the most honest. It makes no promises about security, integration, or management. It’s a file. You run it. It works.

Technically, an AppImage is an ELF binary that contains a squashfs filesystem. When you execute it, the binary mounts the squashfs, finds the app entrypoint, and runs it. The entire app — binary, libraries, assets — is in that one file. No install required.

The install process is:

chmod +x MyApp.AppImage && ./MyApp.AppImage

That’s it. That’s the whole thing.

The Good Stuff

The portability story is genuinely compelling. Copy an AppImage to a USB stick and run it on any modern Linux machine without touching the package manager. This is not theoretical — it actually works. I’ve used this for distributing internal tools to machines I don’t control, and it’s the cleanest solution I’ve found.

No root required. No system changes. No daemon watching it. No database entry. Delete the file and the app is completely uninstalled. For people who’ve spent decades navigating “dpkg –purge” and leftover config files in /etc, this is surprisingly satisfying.

AppImages are also great for running multiple versions of the same app simultaneously, which sounds niche until you need it. I maintain three different AppImage versions of a scientific computing tool because different projects have different requirements, and they coexist without conflict.

The Bad and Ugly

The security model is, diplomatically, “trust me bro.” There is no built-in sandbox. An AppImage runs with your full user permissions on your system. You are trusting that whoever compiled and uploaded the AppImage is a reasonable person who didn’t do anything sketchy.

Download from official project pages. Check the appimage.github.io catalog, which maintains a list of vetted AppImages. Never run an AppImage from a link someone posted in a forum. This is not theoretical advice.

No auto-updates by default. The AppImage spec includes an update protocol, but implementing it is optional, and most AppImages don’t. Your AppImage will never tell you there’s a newer version. You have to care about this yourself.

Desktop integration is also manual or nonexistent by default. No .desktop file, no app menu entry, no file associations. The solution is AppImageLauncher, which is excellent — it handles integration automatically when you double-click an AppImage — but you have to install it separately.

The chmod +x Tax

I’ve given this section a name because it deserves one. Every single time I do an AppImage demo, I forget to chmod +x the file before trying to run it. Every time. I’ve been doing this for a decade. I will forget again.

The error is “Permission denied,” which is not the most informative error message for someone who doesn’t know what’s happening. The fix is obvious in retrospect but annoying every time.

This is the single most common AppImage support question. If someone tells you AppImages don’t work, check for chmod +x first.

Who AppImage Is For

AppImage is the right choice when portability is the primary constraint. Air-gapped systems, one-off tool deployments, situations where you need to know exactly what version of an app is running and guarantee it doesn’t change without your knowledge. Devs who want to ship to users without caring what distro they’re running.

It is not a replacement for your package manager. Don’t use AppImages for system tools, libraries, or anything where you want security updates to happen automatically.


Snap: Canonical’s Walled Garden

Snap is Canonical’s answer to universal packaging, and it carries all the hallmarks of Canonical’s approach to Ubuntu: opinionated, integrated, centralized, and occasionally doing things without asking you first.

I’ve rage-deleted snapd twice. I reinstalled it once. My feelings are complicated.

What Snap Actually Is

At a technical level, a snap is a squashfs image wrapped in metadata, distributed through Canonical’s Snap Store (snapcraft.io). When you install a snap, snapd downloads the image, mounts it at /snap/<name>/<revision>/, and wraps it in an AppArmor confinement profile.

The confinement is real and meaningful. Each snap declares “interfaces” — named permission scopes that correspond to things like home directory access, network access, camera, microphone, USB devices. The snap only gets what it declares, and even then only what you’ve connected.

snap connections <name> shows you exactly what a snap can access. It’s genuinely impressive. I wish more people knew this existed.

The Ubuntu Integration Story

On Ubuntu, snapd is pre-installed and always running. snap install works out of the box. This is either a feature or an annoyance depending on your perspective.

The Chromium situation is worth explaining clearly because it surprises people the first time: on Ubuntu, apt install chromium-browser does not install a .deb. Ubuntu intercepts the command and installs the Chromium snap. This is documented behavior, not a bug, and Canonical’s reasoning is that the snap version is better maintained and more secure.

Worth noting: if you specifically want a .deb Chromium, alternatives exist — Google Chrome has always distributed a .deb directly, and Ungoogled Chromium is available through community PPAs. But the default apt install chromium-browser path on Ubuntu leads to snap.

Your reaction to all of this tells me everything about your relationship with Canonical.

The Startup Latency Problem

Every snap app mounts its squashfs image on launch. This is the source of the notorious snap startup latency.

On an SSD with a cold cache, expect a noticeable delay — particularly on first boot or slower drives. NVMe SSDs and improved squashfs caching have narrowed the gap compared to a few years ago, but the first cold start is still measurably slower than an equivalent apt-installed binary. The latency improves after the first launch as the OS caches the squashfs blocks.

This matters more for some apps than others. Firefox snap’s startup time is one of the most-criticized aspects of Ubuntu’s default setup. Server apps where you don’t care about interactive startup time? The latency is irrelevant.

The Auto-Update Gotcha

Snaps auto-update. By default. Without asking you. While you’re working.

This is usually fine. Sometimes a snap update changes behavior in a way that breaks your workflow. And once — I’m speaking from experience — a snap refreshed during a live presentation, closing the app mid-demo with no warning.

Run this before any presentation, demo, or situation where an unexpected app close would be embarrassing:

sudo snap refresh --hold=48h

Hold a specific snap for longer if needed:

sudo snap refresh --hold=168h vlc

This is the most practically useful Snap tip I know. I wish I’d known it earlier.

The 2025–2026 Reality Check

By 2025–2026, the fiercest “Snap wars” era of desktop Linux has largely cooled. The most contentious flashpoints — Firefox and Chromium being snap-only on Ubuntu — have been resolved by well-maintained .deb alternatives: Mozilla publishes a Firefox .deb via their own PPA, Google Chrome has always been a .deb, and Ungoogled Chromium is available through community PPAs. Many experienced Ubuntu users simply pin the .deb versions over the snap equivalents for desktop apps where startup time matters.

Snap’s center of gravity has shifted more clearly toward what it was always best at: Ubuntu server and Ubuntu Core IoT. The Snap Store is the right distribution channel for daemons, services, and appliance software running on Canonical’s platforms. The desktop wars have cooled — which is good for everyone.

Who Snap Is For

Snap is at its best for server-side daemons and background services on Ubuntu, browsers (the security benefits are real even if the startup is slow), and any situation where you want automatic security patching and don’t care much about the startup time.

Snap is at its worst for CLI tools (latency is painful), apps where you want theme integration, and non-Ubuntu systems (Snap essentially requires systemd and doesn’t work well outside the Canonical ecosystem).


Flatpak: The Community Darling

Flatpak is the universal package format that most of the Linux community outside of Ubuntu’s gravity well has converged on. It ships by default on Fedora, Linux Mint, and elementary OS. On Ubuntu, you install it yourself — which is, incidentally, one of the things people resent.

I use Flatpak for most of my desktop GUI apps. I also complain about it constantly. Both of these things are true and not in conflict.

The Technical Differences

Flatpak uses Bubblewrap for sandboxing rather than AppArmor. Bubblewrap creates a minimal namespace environment for each app — separate filesystem view, separate process tree, no access to things it hasn’t been explicitly granted.

The portal system is Flatpak’s most interesting idea. Rather than giving apps direct access to system resources, they go through “portal” services — OS-managed brokers that handle things like file access, camera, screen capture, and notifications. When a Flatpak app opens a file dialog, it’s actually asking the portal for a file, and the portal shows the native file picker. The app never sees your filesystem directly unless you grant it access.

This is clever and mostly works. It’s occasionally annoying for CLI tools that expect to do file operations directly without asking permission.

Flatpak also supports decentralized remotes — you’re not locked into a single corporate store. Flathub is the main one and has around 2,500 apps at this point, but you can add any remote including your own.

Flatseal Is Non-Negotiable

Install Flatseal before any other Flatpak. This is not optional advice.

flatpak install flathub com.github.tchx84.Flatseal

Flatseal is a GUI permission manager for Flatpak apps. Without it, managing permissions requires knowing the CLI override syntax and looking up the right portal names. With it, you can see every permission each app has and toggle them with checkboxes.

If you’re going to show one thing to someone who’s skeptical about sandboxing, show them Flatseal. It’s the clearest demonstration of “here’s exactly what this app can access, and you can control it” I’ve seen on Linux.

The Disk Usage Reality

Do du -sh ~/.var/app after using Flatpak for a few months. I’ll wait.

The shared runtime system means apps that use the same base runtime (say, GNOME Platform 45) share that runtime rather than each bundling it. This is better than every app bundling everything. It is not as good as “install GIMP and it uses the system GTK like a normal package.”

If you install GNOME apps and KDE apps, you’re downloading both runtimes. Each can be 500MB+. If you install apps casually and don’t prune regularly, your Flatpak storage will grow in ways that will surprise you.

Prune it regularly:

flatpak uninstall --unused          # remove orphaned runtimes
flatpak uninstall --delete-data     # also wipe app data dirs for removed apps
flatpak repair                      # fix corruption and deduplicate

The --unused flag is the main one to run monthly. If you’ve been casual about installing and removing apps for a while, flatpak repair will reclaim space from duplicate objects. Put flatpak uninstall --unused in a cron job — disk reclamation you never have to think about.

CLI Verbosity: The App ID Problem

Flatpak uses reverse-domain app IDs. Installing LibreOffice is:

flatpak install flathub org.libreoffice.LibreOffice

Running it is:

flatpak run org.libreoffice.LibreOffice

This is verbose. Tab completion helps. Shell aliases help more. But it’s a real friction point, especially when you’re used to apt install libreoffice.

Who Flatpak Is For

Flatpak is the right choice for desktop GUI applications where you want sandboxing with visible, controllable permissions. If you’re on a non-Ubuntu distro, it’s probably already there and is the natural choice. If you want to run apps that actually respect your desktop theme, Flatpak integrates better than Snap.

It is not ideal for CLI tools (portal permission prompts are annoying for things that just need to write a file), and the verbose CLI means it’s not the best choice for quick one-off installs.


Head to Head: The Actual Comparison

Let me be blunt about the decision matrix.

Use AppImage when:

  • Portability is the primary constraint
  • You’re on an air-gapped system
  • You need a specific version and don’t want it to update
  • You want zero system changes
  • You’re on a weird distro and just need something to run

Use Snap when:

  • You’re on Ubuntu and the app is available
  • It’s a server or daemon app where auto-updates are a feature
  • You want the app to auto-patch and you trust Canonical’s update cadence
  • Startup latency doesn’t matter (background services, browsers you keep open)

Use Flatpak when:

  • It’s a desktop GUI app
  • You care about sandboxing and want to see what the app can access
  • You’re on any non-Ubuntu distro that ships Flatpak
  • You want your apps to actually look like they belong on your desktop

Use apt/dnf/pacman when:

  • The app is in your distro’s repo
  • Performance matters
  • You want proper system integration
  • You want security updates handled by people who know your distro
  • You like your sanity

That last option is the one people forget. Native package managers exist, work well for most software, and are the correct default. Universal packages are the fallback, not the baseline.


The Ugly Truths I Didn’t Want to Say But Will

Universal packages do not replace your distro’s package manager. If you’re using Flatpak for everything on Ubuntu, you’re doing it wrong. Your distro’s maintainers package most of what you need and they package it better.

They all increase disk usage. Significantly. This is the price of bundling. It’s a reasonable price for some use cases and an unreasonable one for others.

They all shift trust boundaries. With apt, you’re trusting your distro’s security team. With universal packages, you’re trusting the developer — or the Flathub submission reviewers, or Canonical’s store team. This is not necessarily worse, but it’s different, and you should be aware of it.

The reason we have three competing formats is because the Linux community couldn’t agree on one. This is both a joke and a tragedy. Each format made different tradeoffs, found different communities, and entrenched. We now live in a world where you might reasonably have AppImages, Snaps, Flatpaks, and native packages all installed on the same machine.

I do. I complain about it. I keep all of them.


The Series Goes Much Deeper

This post is the overview and decision matrix. If you want the real internals, the six-part series has you covered:

Part 2 — AppImage Deep Dive: Goes byte-for-byte into the ELF + squashfs structure, how FUSE mounting works without root, the libfuse2/libfuse3 transition that broke Ubuntu 22.04, and the zsync update protocol. Includes the --appimage-* debugging flags nobody tells you about.

Part 3 — Snap Deep Dive: Dissects why snapd needs to run forever as a daemon, the full snap-confine → AppArmor → seccomp execution chain, the snap type hierarchy (app/base/kernel/gadget/content), and how snap assertions build the trust chain back to Canonical.

Part 4 — Flatpak Deep Dive: Bubblewrap user namespaces, OSTree content-addressable storage, and how xdg-desktop-portal lets sandboxed apps open a file picker without ever seeing your filesystem.

Part 5 — vs Docker: Compares all three formats with Docker’s full namespace stack, cgroups resource limits, and OverlayFS storage. Answers the “is a Flatpak app a container?” question properly.

Part 6 — Build Your Own: The guide I wish existed. Full walkthroughs for packaging in all three formats — including the glibc floor problem, confinement debugging, no-network-during-build constraints, and CI patterns that actually work.


Resources

AppImage:

Snap:

  • snapcraft.io — store and docs
  • sudo snap refresh --hold=48h — memorize this command

Flatpak:

  • flathub.org — the app store
  • Flatseal — install immediately
  • flatpak uninstall --unused — run monthly

Talk materials: