diff --git a/build.py b/build.py
index f08cba548fb0eb227e21cd7c2036f2cbf3dc0c2f..d05a7298408dd3713f2962793e8e48b369de12ba 100755
--- a/build.py
+++ b/build.py
@@ -305,6 +305,12 @@ def run_dependencies(args):
     elif args.distribution == WIN32_DISTRIBUTION_NAME:
         print("The win32 version does not install dependencies with this script.\nPlease continue with the --install instruction.")
         sys.exit(1)
+    elif args.distribution == 'guix':
+        print("Building the environment defined in 'guix/manifest.scm'...")
+        execute_script(['mkdir -p ~/.config/guix/profiles',
+                        ('guix time-machine  --channels=guix/channels.scm -- '
+                         'package --manifest=guix/manifest.scm '
+                         '--profile=$HOME/.config/guix/profiles/jami')])
 
     else:
         print("Not yet implemented for current distribution (%s). Please continue with the --install instruction. Note: You may need to install some dependencies manually." %
@@ -398,8 +404,28 @@ def run_install(args):
             install_args += ("-q", args.qtver)
             install_args += ("-Q", args.qt)
 
-    print(f'info: Invoking scripts/install.sh with arguments: {install_args}')
-    return subprocess.run(["./scripts/install.sh"] + install_args, env=environ, check=True)
+    command = ['bash', 'scripts/install.sh'] + install_args
+
+    if args.distribution == 'guix':
+        if args.global_install:
+            print('error: global install is not supported when using Guix.')
+            sys.exit(1)
+        # Run the build in an isolated container.
+        share_tarballs_args = []
+        if 'TARBALLS' in os.environ:
+            share_tarballs_args = ['--preserve=TARBALLS',
+                             f'--share={os.environ["TARBALLS"]}']
+        # Note: we must expose /gnu/store because /etc/ssl/certs
+        # contains certs that are symlinks to store items.
+        command = ['guix', 'time-machine', '-C', 'guix/channels.scm', '--',
+                   'environment', '--manifest=guix/manifest.scm',
+                   '--expose=/gnu/store', '--expose=/etc/ssl/certs',
+                   '--expose=/usr/bin/env',
+                   '--container', '--network'] + share_tarballs_args \
+                   + ['--'] + command
+
+    print(f'info: Building/installing using the command: {" ".join(command)}')
+    return subprocess.run(command, env=environ, check=True)
 
 
 def run_uninstall(args):
@@ -525,13 +551,25 @@ def execute_script(script, settings=None, fail=True):
             sys.exit(1)
 
 
+def has_guix():
+    """Check whether the 'guix' command is available."""
+    with open(os.devnull, 'w') as f:
+        try:
+            subprocess.run(["sh", "-c", "command -v guix"],
+                           check=True, stdout=f)
+        except subprocess.CalledProcessError:
+            return False
+        else:
+            return True
+
+
 def validate_args(parsed_args):
     """Validate the args values, exit if error is found"""
 
     # Filter unsupported distributions.
     supported_distros = [
         ANDROID_DISTRIBUTION_NAME, OSX_DISTRIBUTION_NAME, IOS_DISTRIBUTION_NAME,
-        WIN32_DISTRIBUTION_NAME
+        WIN32_DISTRIBUTION_NAME, 'guix'
     ] + APT_BASED_DISTROS + DNF_BASED_DISTROS + PACMAN_BASED_DISTROS \
       + ZYPPER_BASED_DISTROS + FLATPAK_BASED_RUNTIMES
 
@@ -551,6 +589,7 @@ def validate_args(parsed_args):
     # The Qt client support will be added incrementally.
     if parsed_args.qt is not None:
         supported_qt_distros = [
+            'guix',
             WIN32_DISTRIBUTION_NAME
         ] + APT_BASED_DISTROS + DNF_BASED_DISTROS + PACMAN_BASED_DISTROS
 
@@ -619,7 +658,7 @@ def parse_args():
 
     parsed_args = ap.parse_args()
 
-    if (parsed_args.distribution is not None):
+    if parsed_args.distribution:
         parsed_args.distribution = parsed_args.distribution.lower()
     else:
         parsed_args.distribution = dist
@@ -642,6 +681,8 @@ def choose_distribution():
                     if k.strip() == 'ID':
                         return v.strip().replace('"', '').split(' ')[0]
         except FileNotFoundError:
+            if has_guix():
+                return 'guix'
             return 'Unknown'
     elif system == "darwin":
         return OSX_DISTRIBUTION_NAME
@@ -669,7 +710,23 @@ def main():
         run_uninstall(parsed_args)
 
     elif parsed_args.run:
-        run_run(parsed_args)
+        if (parsed_args.distribution == 'guix'
+                and 'GUIX_ENVIRONMENT' not in os.environ):
+            if parsed_args.qt is not None:
+                print('FIXME: Qt fails loading QML modules due to '
+                      'https://issues.guix.gnu.org/47655')
+            # Relaunch this script, this time in a pure Guix environment.
+            guix_args = ['time-machine', '--channels=guix/channels.scm',
+                         '--', 'environment', '--pure',
+                         # to allow pulseaudio to connect to an existing server
+                         "-E", "XAUTHORITY", "-E", "XDG_RUNTIME_DIR",
+                         '--manifest=guix/manifest.scm', '--']
+            args = sys.argv + ['--distribution=guix']
+            print('Running in a guix environment spawned with: guix {}'
+                  .format(str.join(' ', guix_args + args)))
+            os.execlp('guix', 'guix', *(guix_args + args))
+        else:
+            run_run(parsed_args)
 
     elif parsed_args.stop:
         run_stop(parsed_args)
diff --git a/guix/channels.scm b/guix/channels.scm
new file mode 100644
index 0000000000000000000000000000000000000000..b31ce8dbc293237b5b6ef9e868a6e16d0082bd9e
--- /dev/null
+++ b/guix/channels.scm
@@ -0,0 +1,8 @@
+(list (channel
+       (inherit %default-guix-channel)
+       ;; Use the staging branch for now, as it includes more debug
+       ;; symbols and fixes a propagation conflict between
+       ;; gdk-pixbuf+svg and gdk-pixbuf.
+       (branch "staging")
+       (commit
+        "42231bc15df441d6426dec57283aca9ae7a03fcf")))
diff --git a/guix/manifest.scm b/guix/manifest.scm
new file mode 100644
index 0000000000000000000000000000000000000000..7e66817555c8a3737c1cba0190e18044590a30a3
--- /dev/null
+++ b/guix/manifest.scm
@@ -0,0 +1,142 @@
+;;; To use with the GNU Guix package manager.
+;;; Available at https://guix.gnu.org/.
+;;;
+;;; Commentary:
+;;;
+;;; A full-blown development environment that can be used to build the
+;;; whole project.  It includes both the GNOME as well as the Qt
+;;; libraries, so that both clients can be built.  The sensitive
+;;; (i.e., patched) dependencies are consciously omitted from this
+;;; list so that the bundled libraries are the ones used, which is
+;;; usually what is desired for development purposes.
+
+;;; The make-jami.py script makes use of it to build Jami in a Linux
+;;; container with the dependencies below when Guix is detected (and
+;;; no /etc/os-release file exists) or when explicitly specified,
+;;; e.g.:
+;;;
+;;; $ ./make-jami.py --distribution=guix --install
+;;;
+;;; It can also be invoked directly to spawn a development environment, like so:
+;;;
+;;; $ guix environment --pure --manifest=guix/manifest.scm
+
+(specifications->manifest
+ (list
+  ;; Minimal requirements of the daemon contrib build system.
+  "coreutils"
+  "gcc-toolchain"
+  "git-minimal"
+  "grep"
+  "gzip"
+  "make"
+  "nss-certs"
+  "pkg-config"
+  "python"
+  "sed"
+  "tar"
+  "wget"
+  "xz"
+
+  ;; For the daemon and its contribs.
+  "alsa-lib"
+  "autoconf"
+  "automake"
+  "bash"
+  "bzip2"
+  "cmake"
+  "dbus"
+  ;; Bundled because broken with GCC 7 upstream (unmaintained).  When
+  ;; attempting to use it, it would cause confusing errors such as
+  ;; "ld: ../src/.libs/libring.a(libupnpcontrol_la-upnp_context.o): in
+  ;; function `jami::upnp::UPnPContext::updateMappingList(bool)':
+  ;; upnp_context.cpp:(.text+0xa4be): undefined reference to
+  ;; `std::__cxx11::basic_ostringstream<char, std::char_traits<char>,
+  ;; std::allocator<char> >::basic_ostringstream()'
+  ;;"dbus-c++"                          ;for dbusxx-xml2cpp
+  "diffutils"
+  "doxygen"
+  "eudev"                               ;udev library
+  "expat"
+  "findutils"
+  "gawk"
+  "gettext"
+  "gnutls"
+  ;;"ffmpeg"                            ;bundled because patched
+  "gmp"
+  "gsm"
+  "gtk-doc"
+  "http-parser"
+  "jsoncpp"
+  "libarchive"
+  "libnatpmp"
+  "libupnp"
+  "libsecp256k1"
+  "libtool"
+  "libva"                               ;vaapi
+  "libvdpau"
+  "libx264"
+  "nasm"
+  "nettle"
+  "openssl"
+  "opus"
+  "patch"
+  "pcre"
+  "perl"
+  ;;"pjproject"                         ;bundled because patched
+  "pulseaudio"
+  "speex"
+  "speexdsp"
+  "which"
+  "yaml-cpp"
+  "yasm"
+
+  ;; For libringclient (LRC) and the Qt client.
+  "qtbase"
+  "qtbase:debug"
+
+  ;; Shared by the GNOME and Qt clients.
+  "qrencode"
+
+  ;; Shared by the LRC, GNOME and Qt clients.
+  "network-manager"                     ;libnm
+
+  ;; For the GNOME client (client-gnome)
+  "adwaita-icon-theme"
+  "hicolor-icon-theme"
+  "clutter"
+  "clutter-gtk"
+  "glib:bin"                            ;for glib-compile-resources
+  "gtk+"
+  "gtk+:debug"
+  "libcanberra"
+  "libindicator"
+  "libnotify"
+  "sqlite"
+  "webkitgtk"
+
+  ;; For the Qt client.
+  "qtsvg"
+  "qtsvg:debug"
+  "qttools"
+  "qtwebengine"
+  "qtwebengine:debug"
+  "qtwebchannel"
+  "qtwebchannel:debug"
+  "qtmultimedia"
+  "qtmultimedia:debug"
+  "qtdeclarative"
+  "qtdeclarative:debug"
+  "qtgraphicaleffects"
+  "qtgraphicaleffects:debug"
+  "qtquickcontrols"
+  "qtquickcontrols:debug"
+  "qtquickcontrols2"
+  "qtquickcontrols2:debug"
+
+  ;; For tests and debugging.
+  "cppunit"
+  "file"
+  "gdb"
+  "ltrace"
+  "strace"))