diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,37 @@
 # Revision history for Arion
 
+## Next 0.2.0.0
+
+### BREAKING
+
+* The `project.name` option is now mandatory for projects that aren't deployed with the NixOS module.
+
+
+* The NixOS module now sets the default network name to the project name (commonly referred to as `<name>` in the option path).
+  If this is not desired, for instance if you need the projects to be on the same network, set `networks.default.name` in each of them.
+
+* The NixOS module now sets the default project name. You can still set your own value with the `project.name` option.
+  If you did not set one, docker compose heuristically determined the name to be `store`, so you may want to set `project.name = "store"` or prepare to rename the network manually.
+
+### Removed
+
+ - NixOS 20.09 support. Its docker-compose does not support the
+   `networks.<name>.name` option, which is important in later versions.
+   A newer, bundled docker compose may work there, but for now the decision
+   is to drop this legacy version.
+
+### Changed
+
+* Healthcheck-based dependencies in `service.depends_on`.
+
+### Added
+
+* Support `service.healthcheck` for defining custom healthchecks.
+* Arion now declares a `networks.default` by default, with `name` set to
+  `project.name`. This improves compatibility with container runtimes by
+  copying pre-existing behavior. Most users will want to keep using this
+  behavior, but it can be disabled with `enableDefaultNetwork`.
+
 ## 0.1.3.0 -- 2020-05-03
 
 ### Changed
diff --git a/arion-compose.cabal b/arion-compose.cabal
--- a/arion-compose.cabal
+++ b/arion-compose.cabal
@@ -1,7 +1,7 @@
 cabal-version:       2.4
 
 name:                arion-compose
-version: 0.1.3.0
+version: 0.2.0.0
 synopsis:            Run docker-compose with help from Nix/NixOS
 description:         Arion is a tool for building and running applications that consist of multiple docker containers using NixOS modules. It has special support for docker images that are built with Nix, for a smooth development experience and improved performance.
 homepage:            https://github.com/hercules-ci/arion#readme
@@ -17,6 +17,7 @@
                      src/haskell/testdata/**/*.json
 data-files:          nix/*.nix
                    , nix/modules/composition/*.nix
+                   , nix/modules/networks/*.nix
                    , nix/modules/nixos/*.nix
                    , nix/modules/service/*.nix
                    , nix/modules/lib/*.nix
@@ -24,9 +25,13 @@
 -- all data is verbatim from some sources
 data-dir:            src
 
+source-repository head
+  type: git
+  location: https://github.com/hercules-ci/arion
+
 common common
-  build-depends:     base >=4.12.0.0 && <4.15
-                   , aeson
+  build-depends:     base >=4.12.0.0 && <4.17
+                   , aeson >=2
                    , aeson-pretty
                    , async
                    , bytestring
diff --git a/src/haskell/exe/Main.hs b/src/haskell/exe/Main.hs
--- a/src/haskell/exe/Main.hs
+++ b/src/haskell/exe/Main.hs
@@ -60,7 +60,7 @@
           <> help "Use Nix expression EXPR to get the Nixpkgs attrset used for bootstrapping \
                    \and evaluating the configuration." )
     showTrace <- flag False True (long "show-trace"
-                    <> help "Causes Nix to print out a stack trace in case of Nix expression evaluation errors.")
+                    <> help "Causes Nix to print out a stack trace in case of Nix expression evaluation errors. Specify before command.")
     -- TODO --option support (https://github.com/pcapriotti/optparse-applicative/issues/284)
     userNixArgs <- many (T.pack <$> strOption (long "nix-arg" <> metavar "ARG" <> help "Pass an extra argument to nix. Example: --nix-arg --option --nix-arg substitute --nix-arg false"))
     prebuiltComposeFile <- optional $ strOption
diff --git a/src/haskell/lib/Arion/Images.hs b/src/haskell/lib/Arion/Images.hs
--- a/src/haskell/lib/Arion/Images.hs
+++ b/src/haskell/lib/Arion/Images.hs
@@ -25,7 +25,8 @@
     isNew i =
       -- On docker, the image name is unmodified
       (imageName i <> ":" <> imageTag i) `notElem` loaded
-      -- -- On podman, you automatically get a localhost prefix
+      -- On podman, you used to automatically get a localhost prefix
+      -- however, since NixOS 22.05, this expected to be part of the name instead
         && ("localhost/" <> imageName i <> ":" <> imageTag i) `notElem` loaded
 
   traverse_ loadImage . filter isNew $ requestedImages
diff --git a/src/haskell/lib/Arion/Services.hs b/src/haskell/lib/Arion/Services.hs
--- a/src/haskell/lib/Arion/Services.hs
+++ b/src/haskell/lib/Arion/Services.hs
@@ -9,6 +9,7 @@
 import Protolude hiding (to)
 
 import qualified Data.Aeson as Aeson
+import qualified Data.Aeson.Key as AK
 import           Arion.Aeson (decodeFile)
 
 import Control.Lens
@@ -20,4 +21,4 @@
 
   v <- decodeFile fp
 
-  pure ((v :: Aeson.Value) ^.. key "x-arion" . key "serviceInfo" . key service . key "defaultExec" . _Array . traverse . _String)
+  pure ((v :: Aeson.Value) ^.. key "x-arion" . key "serviceInfo" . key (AK.fromText service) . key "defaultExec" . _Array . traverse . _String)
diff --git a/src/haskell/testdata/Arion/NixSpec/arion-compose.json b/src/haskell/testdata/Arion/NixSpec/arion-compose.json
--- a/src/haskell/testdata/Arion/NixSpec/arion-compose.json
+++ b/src/haskell/testdata/Arion/NixSpec/arion-compose.json
@@ -1,4 +1,9 @@
 {
+    "networks": {
+        "default": {
+            "name": "unit-test-data"
+        }
+    },
     "services": {
         "webserver": {
             "command": [
@@ -9,7 +14,7 @@
                 "PATH": "/usr/bin:/run/current-system/sw/bin/",
                 "container": "docker"
             },
-            "image": "webserver:<HASH>",
+            "image": "localhost/webserver:<HASH>",
             "ports": [
                 "8000:80"
             ],
@@ -32,12 +37,12 @@
         "images": [
             {
                 "imageExe": "<STOREPATH>",
-                "imageName": "webserver",
+                "imageName": "localhost/webserver",
                 "imageTag": "<HASH>"
             }
         ],
         "project": {
-            "name": null
+            "name": "unit-test-data"
         },
         "serviceInfo": {
             "webserver": {
diff --git a/src/haskell/testdata/Arion/NixSpec/arion-compose.nix b/src/haskell/testdata/Arion/NixSpec/arion-compose.nix
--- a/src/haskell/testdata/Arion/NixSpec/arion-compose.nix
+++ b/src/haskell/testdata/Arion/NixSpec/arion-compose.nix
@@ -1,4 +1,5 @@
 {
+  project.name = "unit-test-data";
   services.webserver = { pkgs, ... }: {
     nixos.useSystemd = true;
     nixos.configuration.boot.tmpOnTmpfs = true;
diff --git a/src/nix/eval-composition.nix b/src/nix/eval-composition.nix
--- a/src/nix/eval-composition.nix
+++ b/src/nix/eval-composition.nix
@@ -12,7 +12,6 @@
   inherit (pkgs) lib;
 
   composition = lib.evalModules {
-    check = true;
     modules = builtinModules ++ modules;
   };
 
@@ -24,6 +23,7 @@
     _file = ./eval-composition.nix;
     key = ./eval-composition.nix;
     config._module.args.pkgs = lib.mkIf (pkgs != null) (lib.mkForce pkgs);
+    config._module.args.check = true;
     config.host.nixStorePrefix = hostNixStorePrefix;
     config.host.uid = lib.toInt uid;
   };
@@ -33,5 +33,5 @@
   composition // {
     # throw in lib and pkgs for repl convenience
     inherit lib;
-    inherit (composition.config._module.args) pkgs;
+    inherit (composition._module.args) pkgs;
   }
diff --git a/src/nix/lib.nix b/src/nix/lib.nix
new file mode 100644
--- /dev/null
+++ b/src/nix/lib.nix
@@ -0,0 +1,16 @@
+{ lib }:
+let
+
+  link = url: text:
+    ''link:${url}[${text}]'';
+
+  dockerComposeRef = fragment:
+    ''See ${link "https://docs.docker.com/compose/compose-file/#${fragment}" "Docker Compose#${fragment}"}'';
+
+in
+{
+  inherit
+    dockerComposeRef
+    link
+    ;
+}
diff --git a/src/nix/modules.nix b/src/nix/modules.nix
--- a/src/nix/modules.nix
+++ b/src/nix/modules.nix
@@ -2,6 +2,7 @@
     ./modules/composition/docker-compose.nix
     ./modules/composition/host-environment.nix
     ./modules/composition/images.nix
+    ./modules/composition/networks.nix
     ./modules/composition/service-info.nix
     ./modules/composition/composition.nix
 ]
diff --git a/src/nix/modules/composition/composition.nix b/src/nix/modules/composition/composition.nix
--- a/src/nix/modules/composition/composition.nix
+++ b/src/nix/modules/composition/composition.nix
@@ -8,14 +8,18 @@
 in
 {
   options = {
+    _module.args = mkOption {
+      internal = true;
+    };
     project.name = mkOption {
       description = ''
         Name of the project.
 
         See ${link "https://docs.docker.com/compose/reference/envvars/#compose_project_name" "COMPOSE_PROJECT_NAME"}
+
+        This is not optional, because getting the project name from a directory name tends to produce different results for different repo checkout location names.
       '';
-      type = types.nullOr types.str;
-      default = null;
+      type = types.str;
     };
   };
   config = {
diff --git a/src/nix/modules/composition/networks.nix b/src/nix/modules/composition/networks.nix
new file mode 100644
--- /dev/null
+++ b/src/nix/modules/composition/networks.nix
@@ -0,0 +1,53 @@
+{ config, lib, ... }:
+
+let
+  inherit (lib)
+    mkOption
+    optionalAttrs
+    types
+    ;
+  inherit (import ../../lib.nix { inherit lib; })
+    dockerComposeRef
+    ;
+in
+{
+  options = {
+    networks = mkOption {
+      type = types.lazyAttrsOf (types.submoduleWith {
+        modules = [
+          ../networks/network.nix
+        ];
+      });
+      description = ''
+        ${dockerComposeRef "networks-top-level-element"}
+      '';
+    };
+    enableDefaultNetwork = mkOption {
+      type = types.bool;
+      description = ''
+        Whether to define the default network:
+
+        ```nix
+        networks.default = {
+          name = config.project.name;
+        };
+        ```
+      '';
+      default = true;
+    };
+  };
+
+
+  config = {
+
+    networks = optionalAttrs config.enableDefaultNetwork {
+      default = {
+        name = config.project.name;
+      };
+    };
+
+    docker-compose.raw.networks =
+      lib.mapAttrs (k: v: v.out) config.networks;
+
+  };
+}
diff --git a/src/nix/modules/networks/network.nix b/src/nix/modules/networks/network.nix
new file mode 100644
--- /dev/null
+++ b/src/nix/modules/networks/network.nix
@@ -0,0 +1,131 @@
+{ config, lib, options, ... }:
+
+let
+  inherit (lib)
+    mkOption
+    optionalAttrs
+    types
+    ;
+  inherit (import ../../lib.nix { inherit lib; })
+    dockerComposeRef
+    ;
+in
+{
+  options = {
+    driver = mkOption {
+      description = ''
+        `"none"`, `"host"`, or a platform-specific value.
+        ${dockerComposeRef "driver"}
+      '';
+      type = types.str;
+    };
+
+    driver_opts = mkOption {
+      description = ''
+        ${dockerComposeRef "driver_opts"}
+      '';
+      type = types.lazyAttrsOf types.raw or types.unspecified;
+    };
+
+    attachable = mkOption {
+      description = ''
+        ${dockerComposeRef "attachable"}
+      '';
+      type = types.bool;
+      example = true;
+    };
+
+    enable_ipv6 = mkOption {
+      description = ''
+        Whether we've entered the 21st century yet.
+        
+        ${dockerComposeRef "enable_ipv6"}
+      '';
+      type = types.bool;
+    };
+
+    ipam = mkOption {
+      # TODO model sub-options
+      description = ''
+        Manage IP addresses.
+
+        ${dockerComposeRef "ipam"}
+      '';
+      type = types.raw or types.unspecified;
+    };
+
+    internal = mkOption {
+      description = ''
+        Achieves "external isolation".
+
+        ${dockerComposeRef "internal"}
+      '';
+      defaultText = false;
+      type = types.bool;
+    };
+
+    labels = mkOption {
+      description = ''
+        Metadata.
+
+        ${dockerComposeRef "labels"}
+      '';
+      # no list support, because less expressive wrt overriding
+      type = types.attrsOf types.str;
+    };
+
+    external = mkOption {
+      description = ''
+        When `true`, don't create or destroy the network, but assume that it
+        exists.
+
+        ${dockerComposeRef "external"}
+      '';
+      type = types.bool;
+    };
+
+    name = mkOption {
+      description = ''
+        Set a custom name for the network.
+
+        It shares a namespace with other projects' networks. `name` is used as-is.
+
+        Note the `default` network's default `name` is set to `project.name` by Arion.
+
+        ${dockerComposeRef "name"}
+      '';
+      type = types.str;
+    };
+
+    out = mkOption {
+      internal = true;
+      description = ''
+        This network's contribution to the docker compose yaml file
+        under the `networks.''${name}` key.
+      '';
+      type = lib.types.attrsOf lib.types.raw or lib.types.unspecified;
+    };
+  };
+
+  config = {
+    out =
+      lib.mapAttrs
+        (k: opt: opt.value)
+        (lib.filterAttrs
+          (k: opt: opt.isDefined)
+          {
+            inherit (options)
+              driver
+              driver_opts
+              attachable
+              enable_ipv6
+              ipam
+              internal
+              labels
+              external
+              name
+              ;
+          }
+        );
+  };
+}
diff --git a/src/nix/modules/service/docker-compose-service.nix b/src/nix/modules/service/docker-compose-service.nix
--- a/src/nix/modules/service/docker-compose-service.nix
+++ b/src/nix/modules/service/docker-compose-service.nix
@@ -4,16 +4,17 @@
    the user-facing options service.image, service.volumes, etc.
 
  */
-{ pkgs, lib, config, ... }:
+{ pkgs, lib, config, options, ... }:
 
 let
   inherit (lib) mkOption types;
-  inherit (types) listOf nullOr attrsOf str either int bool;
+  inherit (types) listOf nullOr attrsOf str either int bool submodule enum;
 
-  link = url: text:
-    ''link:${url}[${text}]'';
-  dockerComposeRef = fragment:
-    ''See ${link "https://docs.docker.com/compose/compose-file/#${fragment}" "Docker Compose#${fragment}"}'';
+  inherit (import ../../lib.nix { inherit lib; })
+    link
+    dockerComposeRef
+    ;
+
   dockerComposeKitchenSink = ''
     Analogous to the `docker run` counterpart.
 
@@ -100,10 +101,62 @@
       default = null;
       description = dockerComposeRef "container_name";
     };
-    service.depends_on = mkOption {
-      type = listOf str;
-      default = [];
-      description = dockerComposeRef "depends_on";
+    service.depends_on =
+      let conditionsModule = {
+            options = {
+              condition = mkOption {
+                type = enum ["service_started" "service_healthy" "service_completed_successfully"];
+                description = dockerComposeRef "depends_on";
+                default = "service_started";
+              };
+            };
+          };
+       in mkOption {
+         type = either (listOf str) (attrsOf (submodule conditionsModule));
+         default = [];
+         description = dockerComposeRef "depends_on";
+       };
+    service.healthcheck = mkOption {
+      description = dockerComposeRef "healthcheck";
+      type = submodule ({ config, options, ...}: {
+        options = {
+          _out = mkOption {
+            internal = true;
+            default = lib.optionalAttrs (options.test.highestPrio < 1500) {
+              inherit (config) test interval timeout start_period retries;
+            };
+          };
+          test = mkOption {
+            type = nullOr (listOf str);
+            default = null;
+            example = [ "CMD" "pg_isready" ];
+            description = dockerComposeRef "healthcheck";
+          };
+          interval = mkOption {
+            type = str;
+            default = "30s";
+            example = "1m";
+            description = dockerComposeRef "healthcheck";
+          };
+          timeout = mkOption {
+            type = str;
+            default = "30s";
+            example = "10s";
+            description = dockerComposeRef "healthcheck";
+          };
+          start_period = mkOption {
+            type = str;
+            default = "0s";
+            example = "30s";
+            description = dockerComposeRef "healthcheck";
+          };
+          retries = mkOption {
+            type = int;
+            default = 3;
+            description = dockerComposeRef "healthcheck";
+          };
+        };
+      });
     };
     service.devices = mkOption {
       type = listOf str;
@@ -250,6 +303,8 @@
     inherit (config.service) container_name;
   } // lib.optionalAttrs (config.service.depends_on != []) {
     inherit (config.service) depends_on;
+  } // lib.optionalAttrs (options.service.healthcheck.highestPrio < 1500) {
+    healthcheck = config.service.healthcheck._out;
   } // lib.optionalAttrs (config.service.devices != []) {
     inherit (config.service) devices;
   } // lib.optionalAttrs (config.service.entrypoint != null) {
diff --git a/src/nix/modules/service/image.nix b/src/nix/modules/service/image.nix
--- a/src/nix/modules/service/image.nix
+++ b/src/nix/modules/service/image.nix
@@ -104,8 +104,8 @@
     };
     image.name = mkOption {
       type = str;
-      default = config.service.name;
-      defaultText = lib.literalExample "config.service.name";
+      default = "localhost/" + config.service.name;
+      defaultText = lib.literalExpression or lib.literalExample ''"localhost/" + config.service.name'';
       description = ''
         A human readable name for the docker image.
 
