The first thing to do is to create a general snaps directory followed by a working directory for this specific snap project:
$ mkdir -p ~/mysnaps/hello
$ cd ~/mysnaps/hello
It is from within this hello
directory where we will invoke all subsequent commands.
NOTE: Due to a limitation in the project we’re going to build, the path of the directory you put the hello
directory in shouldn’t contain any spaces.
Get started by initialising your snap environment:
$ snapcraft init
This creates a snapcraft.yaml
in which you declare how the snap is built and which properties it exposes to the user. We will edit this later.
The directory structure now looks like this:
mysnaps/
└── hello
└── snap
└── snapcraft.yaml
Note: Any future snaps you want to create should be put within their own directory under mysnaps
.
Let’s take a look at the top part of your snapcraft.yaml file. It should look somewhat as shown below:
name: my-snap-name # you probably want to 'snapcraft register <name>'
base: core22 # the base snap is the execution environment for this snap
version: '0.1' # just for humans, typically '1.2+git' or '1.3.2'
summary: Single-line elevator pitch for your amazing snap # 79 char long summary
description: |
This is my-snap's description. You have a paragraph or two to tell the
most important story about your snap. Keep it under 100 words though,
we live in tweetspace and your description wants to look good in the snap
store.
grade: devel # must be 'stable' to release into candidate/stable channels
confinement: devmode # use 'strict' once you have the right plugs and slots
parts:
my-part:
# See 'snapcraft plugins'
plugin: nil
This part of snapcraft.yaml
is mandatory and is basic metadata for the snap.
Let’s go through this line by line:
-
name: The name of the snap.
-
base: A foundation snap that provides a run-time environment with a minimal set of libraries that are common to most applications. The template defaults to using core22
, which equates to Ubuntu 24.04 LTS. See Base snaps for further options.
-
version: The current version of the snap. This is just a human readable string. All snap uploads will get an incremental snap revision, which is independent from this version. It’s separated so that you can upload multiple times the same snap for the same architecture with the same version. See it as a string that indicates to your user the current version, like “stable”, “2.0”, etc.
-
summary: A short, one-line summary or tag-line for your snap.
-
description: A longer description of the snap. It can span over multiple lines if prefixed with the ‘|’ character.
-
grade: Can be used by the publisher to indicate the quality confidence in the build. The store will prevent publishing ‘devel’ grade builds to the ‘stable’ channel.
-
confinement: A snap’s confinement level is the degree of isolation it has from your system, and there are three levels: strict
, classic
and devmode
. strict snaps run in complete isolation, classic
snaps have open access to system resources and devmode snaps run as strict but with open access to the system. The latter is ideal for development, but your snap will need move from devmode to be published. See Snap confinement for more details.
In this tutorial, we will focus on devmode
and strict
confinement.
For more detailed information on this top-level metadata, see Adding global metadata.
And that’s it for the basics. It’s now time to customise the snapcraft.yaml file for our own snap. Taking the above into account, we can change the top of the file to be:
name: hello
base: core22
version: '2.10'
summary: GNU Hello, the "hello world" snap
description: |
GNU hello prints a friendly greeting.
grade: devel
confinement: devmode
Note: Version information is for snap user consumption only, and has no effect on snap updates. It’s defined within quotes, ('2.10'
), because it needs to be a YAML string rather than a floating-point number. Using a string allows for non-numeric version details, such as ‘myfirstversion
’ or ‘2.3-git
’.
Parts are used to describe your application, where its various components can be found, its build and run-time requirements, and those of its dependencies. A snap consists of one or more parts, depending on its complexity.
Here are a few multiple-part snap examples:
- snaps with separate logical parts, such as a server snap containing a web server, a database and the application itself
- a game which ships the game engine and game data for three different games, each one being defined in its own part
- snaps with parts from different locations - parts which are built in a different way
Our hello
snap will be nice and simple. It will consist of only one part for now. In the following pages we are going to gradually extend it.
Two must-haves for every part are the ‘source’ and ‘plugin’ definition. Think of these as the “what” and the “how”, respectively. As source you can, for example, pick a source repository (like git
), a tarball, or a local directory. Snapcraft supports many plugins, allowing you to build a wide variety of project types (e.g. autotools, cmake, go, maven, nodejs, python2, python3).
To build hello
, add the following ‘parts’ stanza to your snapcraft.yaml
file (replace anything else that might be there):
parts:
gnu-hello:
source: http://ftp.gnu.org/gnu/hello/hello-2.10.tar.gz
plugin: autotools
So we have added a part called gnu-hello
(its name is arbitrary). For ‘source’, we specified a tarball located on the GNU project’s FTP server. As ‘plugin’ we’ve chosen autotools
which uses the traditional ./configure && make && make install
build steps.
See Supported plugins, or run snapcraft list-plugins
, to get more information on which build-tools and platforms Snapcraft supports.
To build our snap all you need to do is:
$ snapcraft
The first time you run snapcraft, you may be asked for permission to install Multipass. Snapcraft uses Multipass to both simplify the build process and to confine the build environment within a virtual machine. It offers the best build experience, so we highly recommend answering ‘y’. However, if you’d rather not use Multipass, you can also build natively, remotely, and with LXD. See Build options for details.
During the build, snapcraft will show progress messages, and a successful build will end with:
Generated snap metadata
Created snap package hello_2.10_amd64.snap
The full output from the snapcraft
execution can be found in ~/.local/state/snapcraft/log/snapcraft-<date-time>.log
Congratulations! You’ve just built your first snap, which is now ready to be installed:
$ sudo snap install --devmode hello_2.10_amd64.snap
The output should declare:
hello 2.10 installed
To get some info on the installed snap:
$ snap list hello
Sample output:
Name Version Rev Tracking Publisher Notes
hello 2.10 x1 - - devmode
Let’s try to execute it:
$ hello
On traditional Ubuntu you will get:
Command 'hello' not found, but can be installed with:
sudo snap install hello # version 2.10, or
sudo apt install hello # version 2.10-3
sudo apt install hello-traditional # version 2.10-6
See 'snap info hello' for additional versions.
Or you might get a different error if you previously installed the hello
snap:
$ hello
Output:
bash: /snap/bin/hello No such file
The command doesn’t exist despite being part of our snap and installed! Indeed, snaps don’t expose anything to the user by default (command, services, etc.). We have to do this explicitly and that’s exactly what you are going to tackle next!
If it does work for you, you should verify that it’s the correct hello
command. Check the output of which hello
- it might list something like /usr/bin/hello
. What we’re after is a binary under the /snap/bin
directory.