diff --git a/pressure-vessel/runtime.c b/pressure-vessel/runtime.c
index bb5d72a5916e6d9d5a3c8b999ca137455cfb88de..35632b45cdcb00caaf19256dc92efa7b56fa8c4f 100644
--- a/pressure-vessel/runtime.c
+++ b/pressure-vessel/runtime.c
@@ -54,6 +54,8 @@ struct _PvRuntime
   GObject parent;
 
   gchar *bubblewrap;
+  gchar *source;
+  gchar *id;
   gchar *deployment;
   gchar *source_files;          /* either deployment or that + "/files" */
   gchar *tools_dir;
@@ -96,9 +98,10 @@ struct _PvRuntimeClass
 enum {
   PROP_0,
   PROP_BUBBLEWRAP,
-  PROP_DEPLOYMENT,
+  PROP_SOURCE,
   PROP_ORIGINAL_ENVIRON,
   PROP_FLAGS,
+  PROP_ID,
   PROP_VARIABLE_DIR,
   PROP_PROVIDER_IN_CURRENT_NAMESPACE,
   PROP_PROVIDER_IN_CONTAINER_NAMESPACE,
@@ -399,6 +402,10 @@ pv_runtime_get_property (GObject *object,
         g_value_set_flags (value, self->flags);
         break;
 
+      case PROP_ID:
+        g_value_set_string (value, self->id);
+        break;
+
       case PROP_VARIABLE_DIR:
         g_value_set_string (value, self->variable_dir);
         break;
@@ -411,8 +418,8 @@ pv_runtime_get_property (GObject *object,
         g_value_set_string (value, self->provider_in_container_namespace);
         break;
 
-      case PROP_DEPLOYMENT:
-        g_value_set_string (value, self->deployment);
+      case PROP_SOURCE:
+        g_value_set_string (value, self->source);
         break;
 
       case PROP_TOOLS_DIRECTORY:
@@ -471,6 +478,12 @@ pv_runtime_set_property (GObject *object,
 
         break;
 
+      case PROP_ID:
+        /* Construct-only */
+        g_return_if_fail (self->id == NULL);
+        self->id = g_value_dup_string (value);
+        break;
+
       case PROP_PROVIDER_IN_CURRENT_NAMESPACE:
         /* Construct-only */
         g_return_if_fail (self->provider_in_current_namespace == NULL);
@@ -483,20 +496,20 @@ pv_runtime_set_property (GObject *object,
         self->provider_in_container_namespace = g_value_dup_string (value);
         break;
 
-      case PROP_DEPLOYMENT:
+      case PROP_SOURCE:
         /* Construct-only */
-        g_return_if_fail (self->deployment == NULL);
+        g_return_if_fail (self->source == NULL);
         path = g_value_get_string (value);
 
         if (path != NULL)
           {
-            self->deployment = realpath (path, NULL);
+            self->source = realpath (path, NULL);
 
-            if (self->deployment == NULL)
+            if (self->source == NULL)
               {
                 /* It doesn't exist. Keep the non-canonical path so we
                  * can warn about it later */
-                self->deployment = g_strdup (path);
+                self->source = g_strdup (path);
               }
           }
 
@@ -524,7 +537,7 @@ pv_runtime_constructed (GObject *object)
   g_return_if_fail (self->original_environ != NULL);
   g_return_if_fail (self->provider_in_current_namespace != NULL);
   g_return_if_fail (self->provider_in_container_namespace != NULL);
-  g_return_if_fail (self->deployment != NULL);
+  g_return_if_fail (self->source != NULL);
   g_return_if_fail (self->tools_dir != NULL);
 }
 
@@ -843,14 +856,103 @@ pv_runtime_create_copy (PvRuntime *self,
   return TRUE;
 }
 
+/*
+ * mutable_lock: (out) (not optional):
+ */
+static gboolean
+pv_runtime_unpack (PvRuntime *self,
+                   PvBwrapLock **mutable_lock,
+                   GError **error)
+{
+  g_autoptr(FlatpakBwrap) tar = NULL;
+  g_autofree gchar *deploy_basename = NULL;
+  g_autofree gchar *unpack_dir = NULL;
+
+  g_return_val_if_fail (PV_IS_RUNTIME (self), FALSE);
+  g_return_val_if_fail (mutable_lock != NULL, FALSE);
+  g_return_val_if_fail (*mutable_lock == NULL, FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+  g_return_val_if_fail (self->source != NULL, FALSE);
+  g_return_val_if_fail (self->id != NULL, FALSE);
+  g_return_val_if_fail (self->variable_dir != NULL, FALSE);
+  g_return_val_if_fail (self->variable_dir_fd >= 0, FALSE);
+  g_return_val_if_fail (self->deployment == NULL, FALSE);
+
+  if (!g_file_test (self->source, G_FILE_TEST_IS_REGULAR))
+    return glnx_throw (error, "\"%s\" is not a regular file", self->source);
+
+  if (!g_str_has_suffix (self->source, ".tar.gz"))
+    return glnx_throw (error, "\"%s\" is not a .tar.gz file", self->source);
+
+  deploy_basename = g_strdup_printf ("deploy-%s", self->id);
+  self->deployment = g_build_filename (self->variable_dir,
+                                       deploy_basename, NULL);
+
+  /* Fast path: if we already unpacked it, nothing more to do! */
+  if (g_file_test (self->deployment, G_FILE_TEST_IS_DIR))
+    return TRUE;
+
+  /* Lock the parent directory. Anything that directly manipulates the
+   * unpacked runtimes is expected to do the same, so that
+   * it cannot be deleting unpacked runtimes at the same time we're
+   * creating them.
+   *
+   * This is an exclusive lock, to avoid two concurrent processes trying
+   * to unpack the same runtime. */
+  *mutable_lock = pv_bwrap_lock_new (self->variable_dir_fd, ".ref",
+                                     (PV_BWRAP_LOCK_FLAGS_CREATE
+                                      | PV_BWRAP_LOCK_FLAGS_WAIT),
+                                     error);
+
+  if (*mutable_lock == NULL)
+    return FALSE;
+
+  /* Slow path: we need to do this the hard way. */
+  unpack_dir = g_build_filename (self->variable_dir, "tmp-XXXXXX", NULL);
+
+  if (g_mkdtemp (unpack_dir) == NULL)
+    return glnx_throw_errno_prefix (error,
+                                    "Cannot create temporary directory \"%s\"",
+                                    unpack_dir);
+
+  g_info ("Unpacking \"%s\" into \"%s\"...", self->source, unpack_dir);
+
+  tar = flatpak_bwrap_new (NULL);
+  flatpak_bwrap_add_args (tar,
+                          "tar",
+                          "--force-local",
+                          "-C", unpack_dir,
+                          "-xf", self->source,
+                          NULL);
+  flatpak_bwrap_finish (tar);
+
+  if (!pv_bwrap_run_sync (tar, NULL, error))
+    {
+      glnx_shutil_rm_rf_at (-1, unpack_dir, NULL, NULL);
+      return FALSE;
+    }
+
+  g_info ("Renaming \"%s\" to \"%s\"...", unpack_dir, deploy_basename);
+
+  if (!glnx_renameat (self->variable_dir_fd, unpack_dir,
+                      self->variable_dir_fd, deploy_basename,
+                      error))
+    {
+      glnx_shutil_rm_rf_at (-1, unpack_dir, NULL, NULL);
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
 static gboolean
 pv_runtime_initable_init (GInitable *initable,
                           GCancellable *cancellable G_GNUC_UNUSED,
                           GError **error)
 {
   PvRuntime *self = PV_RUNTIME (initable);
+  g_autoptr(PvBwrapLock) mutable_lock = NULL;
   g_autofree gchar *contents = NULL;
-  g_autofree gchar *files_ref = NULL;
   g_autofree gchar *os_release = NULL;
   gsize len;
 
@@ -868,6 +970,26 @@ pv_runtime_initable_init (GInitable *initable,
   if (!pv_runtime_init_variable_dir (self, error))
     return FALSE;
 
+  if (self->flags & PV_RUNTIME_FLAGS_UNPACK_ARCHIVE)
+    {
+      if (self->id == NULL)
+        return glnx_throw (error, "Cannot unpack archive without unique ID");
+
+      if (self->variable_dir_fd < 0)
+        return glnx_throw (error,
+                           "Cannot unpack archive without variable directory");
+
+      if (!pv_runtime_unpack (self, &mutable_lock, error))
+        return FALSE;
+
+      /* Set by pv_runtime_unpack */
+      g_assert (self->deployment != NULL);
+    }
+  else
+    {
+      self->deployment = g_strdup (self->source);
+    }
+
   if (!g_file_test (self->deployment, G_FILE_TEST_IS_DIR))
     {
       return glnx_throw (error, "\"%s\" is not a directory",
@@ -904,10 +1026,15 @@ pv_runtime_initable_init (GInitable *initable,
    * continue to be locked until all processes in the container exit.
    * If we make a temporary mutable copy, we only hold this lock until
    * setup has finished. */
-  files_ref = g_build_filename (self->source_files, ".ref", NULL);
-  self->runtime_lock = pv_bwrap_lock_new (AT_FDCWD, files_ref,
-                                          PV_BWRAP_LOCK_FLAGS_CREATE,
-                                          error);
+  if (self->runtime_lock == NULL)
+    {
+      g_autofree gchar *files_ref = NULL;
+
+      files_ref = g_build_filename (self->source_files, ".ref", NULL);
+      self->runtime_lock = pv_bwrap_lock_new (AT_FDCWD, files_ref,
+                                              PV_BWRAP_LOCK_FLAGS_CREATE,
+                                              error);
+    }
 
   /* If the runtime is being deleted, ... don't use it, I suppose? */
   if (self->runtime_lock == NULL)
@@ -915,8 +1042,6 @@ pv_runtime_initable_init (GInitable *initable,
 
   if (self->flags & PV_RUNTIME_FLAGS_COPY_RUNTIME)
     {
-      g_autoptr(PvBwrapLock) mutable_lock = NULL;
-
       if (self->variable_dir_fd < 0)
         return glnx_throw (error,
                            "Cannot copy runtime without variable directory");
@@ -925,10 +1050,11 @@ pv_runtime_initable_init (GInitable *initable,
        * can safely be creating their own temporary copy at the same
        * time. If another process is doing GC, wait for it to finish,
        * then take our lock. */
-      mutable_lock = pv_bwrap_lock_new (self->variable_dir_fd, ".ref",
-                                        (PV_BWRAP_LOCK_FLAGS_CREATE
-                                         | PV_BWRAP_LOCK_FLAGS_WAIT),
-                                        error);
+      if (mutable_lock == NULL)
+        mutable_lock = pv_bwrap_lock_new (self->variable_dir_fd, ".ref",
+                                          (PV_BWRAP_LOCK_FLAGS_CREATE
+                                           | PV_BWRAP_LOCK_FLAGS_WAIT),
+                                          error);
 
       if (mutable_lock == NULL)
         return FALSE;
@@ -1085,6 +1211,7 @@ pv_runtime_finalize (GObject *object)
   g_free (self->provider_in_container_namespace);
   g_free (self->runtime_files_on_host);
   g_free (self->runtime_usr);
+  g_free (self->source);
   g_free (self->source_files);
   g_free (self->deployment);
   g_free (self->tools_dir);
@@ -1126,6 +1253,13 @@ pv_runtime_class_init (PvRuntimeClass *cls)
                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
                          G_PARAM_STATIC_STRINGS));
 
+  properties[PROP_ID] =
+    g_param_spec_string ("id", "ID",
+                         "Unique identifier of runtime to be unpacked",
+                         NULL,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS));
+
   properties[PROP_VARIABLE_DIR] =
     g_param_spec_string ("variable-dir", "Variable directory",
                          ("Path to directory for temporary files, or NULL"),
@@ -1151,10 +1285,10 @@ pv_runtime_class_init (PvRuntimeClass *cls)
                          (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
                           G_PARAM_STATIC_STRINGS));
 
-  properties[PROP_DEPLOYMENT] =
-    g_param_spec_string ("deployment", "Deployment",
+  properties[PROP_SOURCE] =
+    g_param_spec_string ("source", "Source",
                          ("Path to read-only runtime files (merged-/usr "
-                          "or sysroot) in current namespace"),
+                          "or sysroot) or archive, in current namespace"),
                          NULL,
                          (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
                           G_PARAM_STATIC_STRINGS));
@@ -1170,7 +1304,8 @@ pv_runtime_class_init (PvRuntimeClass *cls)
 }
 
 PvRuntime *
-pv_runtime_new (const char *deployment,
+pv_runtime_new (const char *source,
+                const char *id,
                 const char *variable_dir,
                 const char *bubblewrap,
                 const char *tools_dir,
@@ -1180,7 +1315,7 @@ pv_runtime_new (const char *deployment,
                 PvRuntimeFlags flags,
                 GError **error)
 {
-  g_return_val_if_fail (deployment != NULL, NULL);
+  g_return_val_if_fail (source != NULL, NULL);
   g_return_val_if_fail (bubblewrap != NULL, NULL);
   g_return_val_if_fail (tools_dir != NULL, NULL);
   g_return_val_if_fail ((flags & ~(PV_RUNTIME_FLAGS_MASK)) == 0, NULL);
@@ -1191,7 +1326,8 @@ pv_runtime_new (const char *deployment,
                          "bubblewrap", bubblewrap,
                          "original-environ", original_environ,
                          "variable-dir", variable_dir,
-                         "deployment", deployment,
+                         "source", source,
+                         "id", id,
                          "tools-directory", tools_dir,
                          "provider-in-current-namespace",
                            provider_in_current_namespace,
diff --git a/pressure-vessel/runtime.h b/pressure-vessel/runtime.h
index 0050c066ecaa26552e73d50ccf748b03f6a7f7ce..45ab34a027f00f12c19591e25be95942ea32207b 100644
--- a/pressure-vessel/runtime.h
+++ b/pressure-vessel/runtime.h
@@ -39,6 +39,7 @@
  * @PV_RUNTIME_FLAGS_VERBOSE: Be more verbose
  * @PV_RUNTIME_FLAGS_IMPORT_VULKAN_LAYERS: Include host Vulkan layers
  * @PV_RUNTIME_FLAGS_COPY_RUNTIME: Copy the runtime and modify the copy
+ * @PV_RUNTIME_FLAGS_UNPACK_ARCHIVE: Source is an archive, not a deployment
  * @PV_RUNTIME_FLAGS_NONE: None of the above
  *
  * Flags affecting how we set up the runtime.
@@ -51,6 +52,7 @@ typedef enum
   PV_RUNTIME_FLAGS_VERBOSE = (1 << 3),
   PV_RUNTIME_FLAGS_IMPORT_VULKAN_LAYERS = (1 << 4),
   PV_RUNTIME_FLAGS_COPY_RUNTIME = (1 << 5),
+  PV_RUNTIME_FLAGS_UNPACK_ARCHIVE = (1 << 6),
   PV_RUNTIME_FLAGS_NONE = 0
 } PvRuntimeFlags;
 
@@ -61,6 +63,7 @@ typedef enum
    | PV_RUNTIME_FLAGS_VERBOSE \
    | PV_RUNTIME_FLAGS_IMPORT_VULKAN_LAYERS \
    | PV_RUNTIME_FLAGS_COPY_RUNTIME \
+   | PV_RUNTIME_FLAGS_UNPACK_ARCHIVE \
    )
 
 typedef struct _PvRuntime PvRuntime;
@@ -74,7 +77,8 @@ typedef struct _PvRuntimeClass PvRuntimeClass;
 #define PV_RUNTIME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PV_TYPE_RUNTIME, PvRuntimeClass)
 GType pv_runtime_get_type (void);
 
-PvRuntime *pv_runtime_new (const char *deployment,
+PvRuntime *pv_runtime_new (const char *source,
+                           const char *id,
                            const char *variable_dir,
                            const char *bubblewrap,
                            const char *tools_dir,
diff --git a/pressure-vessel/wrap.1.md b/pressure-vessel/wrap.1.md
index 7d0106e4f02277d285cdb0a53bfaac58e57909f3..66d5f2cbb64d5cd0b03cf923b9470e33001ca2cd 100644
--- a/pressure-vessel/wrap.1.md
+++ b/pressure-vessel/wrap.1.md
@@ -115,9 +115,32 @@ pressure-vessel-wrap - run programs in a bubblewrap container
     (containing bin/sh, bin/env and many other OS files).
     For example, a Flatpak runtime is a suitable value for *PATH*.
 
+`--runtime-archive` *ARCHIVE*
+:   Unpack *ARCHIVE* and use it to provide /usr in the container, similar
+    to `--runtime`. The `--runtime-id` option is also required.
+
+    If this option is used, then `--variable-dir`
+    (or its environment variable equivalent) is also required.
+    This option and `--runtime` cannot both be used.
+
+    The archive will be unpacked into a subdirectory of the `--variable-dir`.
+    Any other subdirectories of the `--variable-dir` that appear to be
+    different runtimes will be deleted, unless they contain a file
+    at the top level named `keep` or are currently in use.
+
+    The archive must currently be a gzipped tar file whose name ends
+    with `.tar.gz`. Other formats might be allowed in future.
+
 `--runtime-base` *PATH*
-:   If `--runtime` specifies a relative path, look for it relative
-    to *PATH*.
+:   If `--runtime` or `--runtime-archive` is specified as a relative path,
+    look for it relative to *PATH*.
+
+`--runtime-id` *ID*
+:   Use *ID* to construct a directory into which the `--runtime-archive`
+    will be unpacked. If the *ID* is the same as in a previous run of
+    pressure-vessel-wrap, the content of the `--runtime-archive` will
+    be assumed to be the same as in that previous run, resulting in
+    the previous runtime being reused.
 
 `--share-home`, `--unshare-home`
 :   If `--unshare-home` is specified, use the home directory given
diff --git a/pressure-vessel/wrap.c b/pressure-vessel/wrap.c
index 4a48a1fb827c751dc67d235ae714cfe467fcd389..bb2142e708a6d660bb48bca8e6420e9c4f04f13a 100644
--- a/pressure-vessel/wrap.c
+++ b/pressure-vessel/wrap.c
@@ -724,8 +724,10 @@ static gboolean opt_import_vulkan_layers = TRUE;
 static PvShell opt_shell = PV_SHELL_NONE;
 static GPtrArray *opt_ld_preload = NULL;
 static GArray *opt_pass_fds = NULL;
-static char *opt_runtime_base = NULL;
 static char *opt_runtime = NULL;
+static char *opt_runtime_archive = NULL;
+static char *opt_runtime_base = NULL;
+static char *opt_runtime_id = NULL;
 static Tristate opt_share_home = TRISTATE_MAYBE;
 static gboolean opt_share_pid = TRUE;
 static double opt_terminate_idle_timeout = 0.0;
@@ -1105,11 +1107,22 @@ static GOptionEntry options[] =
     "it with the provider's graphics stack. The empty string "
     "means don't use a runtime. [Default: $PRESSURE_VESSEL_RUNTIME or '']",
     "RUNTIME" },
+  { "runtime-archive", '\0',
+    G_OPTION_FLAG_NONE, G_OPTION_ARG_FILENAME, &opt_runtime_archive,
+    "Unpack the ARCHIVE and use it as the runtime, using --runtime-id to "
+    "avoid repeatedly unpacking the same archive. "
+    "[Default: $PRESSURE_VESSEL_RUNTIME_ARCHIVE]",
+    "ARCHIVE" },
   { "runtime-base", '\0',
     G_OPTION_FLAG_NONE, G_OPTION_ARG_FILENAME, &opt_runtime_base,
-    "If a --runtime is a relative path, look for it relative to BASE. "
+    "If a --runtime or --runtime-archive is a relative path, look for "
+    "it relative to BASE. "
     "[Default: $PRESSURE_VESSEL_RUNTIME_BASE or '.']",
     "BASE" },
+  { "runtime-id", '\0',
+    G_OPTION_FLAG_NONE, G_OPTION_ARG_FILENAME, &opt_runtime_id,
+    "Reuse a previously-unpacked --runtime-archive if its ID matched this",
+    "ID" },
   { "share-home", '\0',
     G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, opt_share_home_cb,
     "Use the real home directory. "
@@ -1298,6 +1311,7 @@ main (int argc,
                             NULL, NULL);
   opt_copy_runtime = pv_boolean_environment ("PRESSURE_VESSEL_COPY_RUNTIME",
                                              opt_copy_runtime);
+  opt_runtime_id = g_strdup (g_getenv ("PRESSURE_VESSEL_RUNTIME_ID"));
 
     {
       const char *value = g_getenv ("PRESSURE_VESSEL_VARIABLE_DIR");
@@ -1350,21 +1364,57 @@ main (int argc,
   if (opt_verbose)
     pv_set_up_logging (opt_verbose);
 
-  if (opt_runtime == NULL)
-    opt_runtime = g_strdup (g_getenv ("PRESSURE_VESSEL_RUNTIME"));
+  /* Specifying either one of these mutually-exclusive options as a
+   * command-line option disables use of the environment variable for
+   * the other one */
+  if (opt_runtime == NULL && opt_runtime_archive == NULL)
+    {
+      opt_runtime = g_strdup (g_getenv ("PRESSURE_VESSEL_RUNTIME"));
+
+      /* Normalize empty string to NULL to simplify later code */
+      if (opt_runtime != NULL && opt_runtime[0] == '\0')
+        g_clear_pointer (&opt_runtime, g_free);
+
+      opt_runtime_archive = g_strdup (g_getenv ("PRESSURE_VESSEL_RUNTIME_ARCHIVE"));
+
+      if (opt_runtime_archive != NULL && opt_runtime_archive[0] == '\0')
+        g_clear_pointer (&opt_runtime_archive, g_free);
+    }
+
+  if (opt_runtime_id != NULL)
+    {
+      const char *p;
+
+      if (opt_runtime_id[0] == '-' || opt_runtime_id[0] == '.')
+        {
+          g_warning ("--runtime-id must not start with dash or dot");
+          goto out;
+        }
+
+      for (p = opt_runtime_id; *p != '\0'; p++)
+        {
+          if (!g_ascii_isalnum (*p) && *p != '_' && *p != '-' && *p != '.')
+            {
+              g_warning ("--runtime-id may only contain "
+                         "alphanumerics, underscore, dash or dot");
+              goto out;
+            }
+        }
+    }
 
   if (opt_runtime_base == NULL)
     opt_runtime_base = g_strdup (g_getenv ("PRESSURE_VESSEL_RUNTIME_BASE"));
 
-  if (opt_runtime != NULL
-      && opt_runtime[0] != '\0'
-      && !g_path_is_absolute (opt_runtime)
-      && opt_runtime_base != NULL
-      && opt_runtime_base[0] != '\0')
+  if (opt_runtime != NULL && opt_runtime_archive != NULL)
     {
-      g_autofree gchar *tmp = g_steal_pointer (&opt_runtime);
+      g_warning ("--runtime and --runtime-archive cannot both be used");
+      goto out;
+    }
 
-      opt_runtime = g_build_filename (opt_runtime_base, tmp, NULL);
+  if (opt_runtime_archive != NULL && opt_runtime_id == NULL)
+    {
+      g_warning ("--runtime-archive requires --runtime-id");
+      goto out;
     }
 
   if (opt_graphics_provider == NULL)
@@ -1703,9 +1753,11 @@ main (int argc,
                               NULL);
     }
 
-  if (opt_runtime != NULL && opt_runtime[0] != '\0')
+  if (opt_runtime != NULL || opt_runtime_archive != NULL)
     {
       PvRuntimeFlags flags = PV_RUNTIME_FLAGS_NONE;
+      g_autofree gchar *runtime_resolved = NULL;
+      const char *runtime_path = NULL;
 
       if (opt_gc_runtimes)
         flags |= PV_RUNTIME_FLAGS_GC_RUNTIMES;
@@ -1725,7 +1777,29 @@ main (int argc,
       if (opt_copy_runtime)
         flags |= PV_RUNTIME_FLAGS_COPY_RUNTIME;
 
-      g_debug ("Configuring runtime %s...", opt_runtime);
+      if (opt_runtime != NULL)
+        {
+          /* already checked for mutually exclusive options */
+          g_assert (opt_runtime_archive == NULL);
+          runtime_path = opt_runtime;
+        }
+      else
+        {
+          flags |= PV_RUNTIME_FLAGS_UNPACK_ARCHIVE;
+          g_assert (opt_runtime_id != NULL);
+          runtime_path = opt_runtime_archive;
+        }
+
+      if (!g_path_is_absolute (runtime_path)
+          && opt_runtime_base != NULL
+          && opt_runtime_base[0] != '\0')
+        {
+          runtime_resolved = g_build_filename (opt_runtime_base,
+                                               runtime_path, NULL);
+          runtime_path = runtime_resolved;
+        }
+
+      g_debug ("Configuring runtime %s...", runtime_path);
 
       if (is_flatpak_env && !opt_copy_runtime)
         {
@@ -1735,7 +1809,8 @@ main (int argc,
           goto out;
         }
 
-      runtime = pv_runtime_new (opt_runtime,
+      runtime = pv_runtime_new (runtime_path,
+                                opt_runtime_id,
                                 opt_variable_dir,
                                 bwrap_executable,
                                 tools_dir,
@@ -2601,8 +2676,10 @@ out:
   g_clear_pointer (&opt_steam_app_id, g_free);
   g_clear_pointer (&opt_home, g_free);
   g_clear_pointer (&opt_fake_home, g_free);
-  g_clear_pointer (&opt_runtime_base, g_free);
   g_clear_pointer (&opt_runtime, g_free);
+  g_clear_pointer (&opt_runtime_archive, g_free);
+  g_clear_pointer (&opt_runtime_base, g_free);
+  g_clear_pointer (&opt_runtime_id, g_free);
   g_clear_pointer (&opt_pass_fds, g_array_unref);
   g_clear_pointer (&opt_variable_dir, g_free);