My experience with snaps

Snap experience

Updated on: 18.7.2025

Snaps are universally hated by the online Linux community, however I always liked the way they worked. And so I decided to dive deeper into how they are made and learn how to make them. Long story short: anyone can learn this but the difficulty heavily depends on each individual app you try to snap.

In this article I will dissect a few of the snaps I maintain to show the way I created them, what problems I faced and lastly why you might consider learning snap if you want to package stuff for Linux and don't know which method to pick.

Disclaimer: I'm not a developer. I'm just a dude that likes Ubuntu.

Snapping Picocrypt

The snapcraft.yaml

When starting out I knew I had to pick something super simple. Something distributed as a single binary so that I don't have to deal with compiling. In case you didn't know, Snaps don't require compiling, all it needs is some binaries/scripts. How you manage to get them inside of the snap doesn't matter. Most of my snaps are repackages of either .deb or tar.gz

Retrieving its binary

What I tried at first was using the default dump plugin and just grabbing the binary. This didn't work as the binary needs to be executable, which makes sense.

So I decided to do this instead:

override-build: |
      mkdir -p "$SNAPCRAFT_PART_INSTALL/usr/bin"
      wget -q -O "$SNAPCRAFT_PART_INSTALL/usr/bin/picocrypt" "https://github.com/Picocrypt/Picocrypt/releases/download/${SNAPCRAFT_PROJECT_VERSION}/Picocrypt"
      chmod +x "$SNAPCRAFT_PART_INSTALL/usr/bin/picocrypt"
      craftctl default

SNAPCRAFT_PART_INSTALL is basically the directory snap will download into by default. Think of it as your workspace. When you wget anything it will be downloaded there, and that space will be shipped the final snap.

So the first line simply tells snap to go create usr/bin/ in that workspace. This is not necessary at all for this specific app but I did it anyways. You could totally just wget the binary, chmod +x it and that's it. In which case this

apps:
  picocrypt-tsugu:
    command: usr/bin/picocrypt

Would turn into

apps:
  picocrypt-tsugu:
    command: picocrypt

But now you know that you can create directories in snap's folder! We're learning.

So the binary is inside of our snap, and we can launch it. Cool.

Dependencies

Each app's dependencies are different, so you will have to consult the build instructions of each app. Orrrr, you run

ldd path/to/binary | grep "not found"

which would produce something like

    libnss3.so => not found
    libnssutil3.so => not found
    libsmime3.so => not found
    libnspr4.so => not found

(Just an example output. Not the dependencies of this app.)

Define the dependencies in

stage-packages:
      - libc6 
      - libgcc-s1 
      - libgl1 
      - libgtk-3-0 
      - libstdc++6 
      - libx11-6
      - libproxy1v5
      - libproxy1-plugin-gsettings

Stage packages are just that, dependencies shipped with the snap. Build packages are only used for building it and won't be shipped to the user.

When reading my snapcraft.yaml you are surely wondering, how the fuck did I come up with a lot of the stuff in it. What's libproxy??? How did I know to include it?? Simple. it threw an error, I googled it, and this was the fix. It's a good idea to keep libproxy in mind as I had to use this LD_LIBRARY_PATH workaround in multiple snaps.

Including another app inside of the snap

You might've noticed another app defined in the file, called cli. You're reading that correctly. Every snap can contain an infinite ammount of apps. Personally I make use of this to include the TUI/CLI variants of apps if they exist. This one can be launched by typing

picocrypt-tsugu.cli

Defining the app and its plugs

In the app section, you will need to define both apps, define their plugs and include an extension if it's a GUI app. The [gnome] extension helps the app to work better with the desktop. I haven't looked too deep into what they actually do.

The plugs are pretty self explanatory as well. Oh! When snapping Filen Cloud's desktop client I encountered an error regarding Unity and I was left flabbergasted. Then I remembered the unity7 plug exists. I defined it and the app launched. You may encounter bizzare stuff like this sometimes.

You don't have to remember what each plug does, that's what the documentation is for. Feel free to define as many of them as you want, you can always remove the redundant ones.

A good rule of thumb is: If it's a GUI app, it needs the GNOME extension and these plugs

plugs:
    - home
    - removable-media
    - wayland
    - x11
    - desktop
    - desktop-legacy
    - network
    - network-bind

And that was it for this snap. Pretty easy. The most important lesson I learned from this is that snaps are just containers filled with executables, and you can modify their content however you please. Now they don't seem as scary anymore.

Snapping Lagrange

The snapcraft.yaml

Since we're on Gemini, let's talk about how I snapped an app where actual compiling was needed. The core concepts are the same however this one was way more involved since a compiler was involved. We aren't simply wgetting a binary.

Building it

Lagrange provides an entire page dedicated to compiling it, with all of the dependencies. Yoink. The nil plugin means we don't want to use any plugin, we want to do stuff in the environment ourselves. I don't remember why I didn't use a plugin but there is probably a reason for it, specifically something not working. But that's okay, all the plugins do is run some default set of commands.

the override-build: section is our commands. All present on Lagrange's website.

Now, the build-environment: part is important because the snap wouldn't compile without it. Remember when I said I'm not a developer and just a dude? So yeah. I have a feeling the CMAKE_PREFIX_PATH is redundant as there's already DCMAKE_INSTALL_PREFIX up in the override build flags but if it compiles and works fine, don't touch it.

the PKG_CONFIG_PATH is another thing I just had to search up when it was throwing errors. Just take these things the way they are, we can't understand everything. When building other apps I don't remember having to do this so it may just apply to cmake?

Defining the app

I had to use the same LD_LIBRARY_PATH workaround as with Picocrypt interestingly enough. Told you it would be relevant.

According to the documentation, XDG_CONFIG_HOME is used by Lagrange to determine your HOME. In this case SNAP_USER_DATA is /home/tsugu/snap/lagrange/current/. Not to worry tho, it will be mostly storing its configuration there. Since I gave it the home plug, you can just download into any folder in HOME as usual.

TUI

There's the TUI app defined, but where did it come from?

Look into override-build:

      cmake .. \
        [OTHER FLAGS]
        -DENABLE_TUI=YES

Now anyone curious in trying it out can just do lagrange-tsugu.tui. Pretty good no? In exchanged for a few megabytes of space you have this alternative user interface available. I also had to include an ncurses library into stage packages which makes sense. This is an ncurses app.

The problem I faced

I wanted to add in WebP support and since there was a flag for it I set it to YES. No webp. I investigated further, tried adding multiple different packages, nothing.

So I decided to build Lagrange outside of Snap. As it turned out, webp did not work there either even tho the compiler said it found libwebp, library needed for this. What is the reason for this I never found out, but the other variations of Lagrange don't have webp support either so it's probably fine.

Final thoughts

I enjoy working with Snap. Despite it being universally hated in online Linux spaces, seeing an app launch feels really good. I also like to think that if Ubuntu Core launches, the bigger the catalogue of apps the better.

Wait! I never showed you how to create a desktop entry for a snap!

Go into your project's folder and create a folder called "gui"

So it will look like

lagrange-snap/
├── snapcraft.yaml
└── gui/
    ├── lagrange-tsugu.desktop
    └── lagrange-tsugu.png

The only special thing about these is that in the .desktop file you need to define the icon as

Icon=${SNAP}/meta/gui/lagrange-tsugu.png

This will make it have an icon in your taskbar too. Obviously you could take a different route such as extracting the .desktop files from the app and manipulating them but this is just so straightforward with no chance of going wrong.