diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,6 +1,66 @@
 # Changelog
 
 
+## v2.1.3
+
+**Changes since v2.1.1**
+
+Behavior changes:
+
+* Disable WAL mode for SQLite3 databases, to improve compatibility with
+  some platforms and filesystems.  See
+  [#4876](https://github.com/commercialhaskell/stack/issues/4876).
+
+* By default, do not perform expiry checks in Hackage Security. See
+  [#4928](https://github.com/commercialhaskell/stack/issues/4928).
+
+Other enhancements:
+
+* Do not rerun expected test failures. This is mostly a change that
+  will only affect the Stackage Curator use case, but there is now an
+  additional message letting the user know when a previously-failed
+  test case is being rerun.
+
+* Move configure information for local packages back to .stack-work to
+  improve caching. See
+  [#4893](https://github.com/commercialhaskell/stack/issues/4893).
+
+Bug fixes:
+
+* Fix to allow dependencies on specific versions of local git repositories. See
+  [#4862](https://github.com/commercialhaskell/stack/pull/4862)
+
+* Allow Stack commands to be run in Nix mode without having a project file
+  available. See
+  [#4854](https://github.com/commercialhaskell/stack/issues/4864).
+
+* Removes dependency on gnu-tar for OSX and Linux environment. The
+  `--force-local` option was required only for windows environment.
+
+* Properly wait for the `tar` subprocess to complete before returning, thereby
+  avoiding a SIGTERM screwing up GHC installation. See
+  [#4888](https://github.com/commercialhaskell/stack/issues/4888).
+
+* Use package complete locations from lock files when resolving dependencies
+  in `extra-deps`. See
+  [#4887](https://github.com/commercialhaskell/stack/issues/4887).
+
+* Set the `HASKELL_DIST_DIR` environment to a proper package dist
+  directory so `doctest` is able to load modules autogenerated by Cabal.
+
+* Expose package library when running tests.
+
+* Fix support for non-ASCII module names. See
+  [4938](https://github.com/commercialhaskell/stack/issues/4938)
+
+Other changes:
+
+* Rename `pantry-tmp` package back to `pantry`, now that we have gained
+  maintainership (which had been used by someone else for a candidate-only test
+  that made it look like the name was free but prevented uploading a real
+  package).
+
+
 ## v2.1.1.1
 
 Hackage-only release that removes `stack.yaml` from the sdist.  This is because
@@ -16,6 +76,15 @@
 
 
 ## v2.1.1
+
+The Stack 2 release represents a series of significant changes to how Stack
+works internally. For the vast majority of cases, these changes are backwards
+compatible, in that existing projects will continue to build in the same way
+with Stack 2 as they did with Stack 1. The large version bump is due to the
+fundamental internal changes to cache handling, database storage (using SQLite
+in place of binary files), implicit snapshots (which greatly improve the
+precompiled cache), and moving to Pantry. We have also removed some less used
+features, as listed below.
 
 **Changes since v1.9.3**
 
diff --git a/doc/ChangeLog.md b/doc/ChangeLog.md
--- a/doc/ChangeLog.md
+++ b/doc/ChangeLog.md
@@ -1,6 +1,66 @@
 # Changelog
 
 
+## v2.1.3
+
+**Changes since v2.1.1**
+
+Behavior changes:
+
+* Disable WAL mode for SQLite3 databases, to improve compatibility with
+  some platforms and filesystems.  See
+  [#4876](https://github.com/commercialhaskell/stack/issues/4876).
+
+* By default, do not perform expiry checks in Hackage Security. See
+  [#4928](https://github.com/commercialhaskell/stack/issues/4928).
+
+Other enhancements:
+
+* Do not rerun expected test failures. This is mostly a change that
+  will only affect the Stackage Curator use case, but there is now an
+  additional message letting the user know when a previously-failed
+  test case is being rerun.
+
+* Move configure information for local packages back to .stack-work to
+  improve caching. See
+  [#4893](https://github.com/commercialhaskell/stack/issues/4893).
+
+Bug fixes:
+
+* Fix to allow dependencies on specific versions of local git repositories. See
+  [#4862](https://github.com/commercialhaskell/stack/pull/4862)
+
+* Allow Stack commands to be run in Nix mode without having a project file
+  available. See
+  [#4854](https://github.com/commercialhaskell/stack/issues/4864).
+
+* Removes dependency on gnu-tar for OSX and Linux environment. The
+  `--force-local` option was required only for windows environment.
+
+* Properly wait for the `tar` subprocess to complete before returning, thereby
+  avoiding a SIGTERM screwing up GHC installation. See
+  [#4888](https://github.com/commercialhaskell/stack/issues/4888).
+
+* Use package complete locations from lock files when resolving dependencies
+  in `extra-deps`. See
+  [#4887](https://github.com/commercialhaskell/stack/issues/4887).
+
+* Set the `HASKELL_DIST_DIR` environment to a proper package dist
+  directory so `doctest` is able to load modules autogenerated by Cabal.
+
+* Expose package library when running tests.
+
+* Fix support for non-ASCII module names. See
+  [4938](https://github.com/commercialhaskell/stack/issues/4938)
+
+Other changes:
+
+* Rename `pantry-tmp` package back to `pantry`, now that we have gained
+  maintainership (which had been used by someone else for a candidate-only test
+  that made it look like the name was free but prevented uploading a real
+  package).
+
+
 ## v2.1.1.1
 
 Hackage-only release that removes `stack.yaml` from the sdist.  This is because
@@ -16,6 +76,15 @@
 
 
 ## v2.1.1
+
+The Stack 2 release represents a series of significant changes to how Stack
+works internally. For the vast majority of cases, these changes are backwards
+compatible, in that existing projects will continue to build in the same way
+with Stack 2 as they did with Stack 1. The large version bump is due to the
+fundamental internal changes to cache handling, database storage (using SQLite
+in place of binary files), implicit snapshots (which greatly improve the
+precompiled cache), and moving to Pantry. We have also removed some less used
+features, as listed below.
 
 **Changes since v1.9.3**
 
diff --git a/doc/GUIDE.md b/doc/GUIDE.md
--- a/doc/GUIDE.md
+++ b/doc/GUIDE.md
@@ -410,7 +410,7 @@
 
 ```
 dependencies:
-- base >= 4.7 && 5
+- base >= 4.7 && < 5
 - text
 - filepath
 - containers
diff --git a/doc/README.md b/doc/README.md
--- a/doc/README.md
+++ b/doc/README.md
@@ -38,6 +38,14 @@
 installation instructions in the
 [install and upgrade guide](install_and_upgrade.md).
 
+#### How to upgrade
+
+If you already have `stack` installed, upgrade it to the latest version
+by running:
+
+    stack upgrade
+
+
 #### Quick Start Guide
 
 First you need to [install it (see previous section)](#how-to-install).
diff --git a/doc/docker_integration.md b/doc/docker_integration.md
--- a/doc/docker_integration.md
+++ b/doc/docker_integration.md
@@ -229,8 +229,10 @@
         - "BAR=BAZ QUUX"
 
       # Location of a Docker container-compatible 'stack' executable with the
-      # matching version. This executable must be built on linux-x86_64 and
-      # statically linked.
+      # matching version. This executable must be compatible with the Docker
+      # image in terms of platform (linux-x86_64) and shared libraries
+      # (statically linked is best, otherwise the image needs to have the
+      # same shared libraries installed).
       # Valid values are:
       #   host: use the host's executable.  This is the default when the host's
       #     executable is known to work (e.g., from official linux-x86_64 bindist)
diff --git a/doc/install_and_upgrade.md b/doc/install_and_upgrade.md
--- a/doc/install_and_upgrade.md
+++ b/doc/install_and_upgrade.md
@@ -24,7 +24,7 @@
 Binary packages are signed with this [signing key](SIGNING_KEY.md).
 
 If you are writing a script that needs to download the latest binary, you can
-use URLs like `https://get.haskellstack.org/stable/<PLATFORM>.<EXTENSION>` (e.g. https://get.haskellstack.org/stable/linux-x86_64.tar.gz) that always point to the latest stable release.
+use URLs like `https://get.haskellstack.org/stable/<PLATFORM>.<EXTENSION>` (e.g. https://get.haskellstack.org/stable/linux-x86_64-static.tar.gz) that always point to the latest stable release.
 
 ## Windows
 
@@ -238,17 +238,11 @@
 
 * Download the latest release:
 
-    * [Linux 64-bit, standard](https://get.haskellstack.org/stable/linux-x86_64.tar.gz)
-
-    * [Linux 64-bit, libgmp4](https://get.haskellstack.org/stable/linux-x86_64-gmp4.tar.gz)
-      (if you are on an older 64-bit distribution that only includes libgmp4
-      (libgmp.so.3), such as CentOS/RHEL/Amazon Linux 6.)
+    * [Linux 64-bit, static](https://get.haskellstack.org/stable/linux-x86_64-static.tar.gz)
 
     * [Linux 32-bit, standard](https://get.haskellstack.org/stable/linux-i386.tar.gz)
-
-    * [Linux 32-bit, libgmp4](https://get.haskellstack.org/stable/linux-i386-gmp4.tar.gz)
-      (if you are on an older 32-bit distribution that only includes libgmp4
-      (libgmp.so.3), such as CentOS/RHEL/Amazon Linux 6.)
+      (note: requires libgmp.so.10, and will not work on some older
+      distributions that have libgmp.so.3, such as CentOS 6)
 
     * [Linux ARMv7](https://get.haskellstack.org/stable/linux-arm.tar.gz)
 
diff --git a/doc/yaml_configuration.md b/doc/yaml_configuration.md
--- a/doc/yaml_configuration.md
+++ b/doc/yaml_configuration.md
@@ -337,12 +337,16 @@
     key-threshold: 3 # number of keys required
 
     # ignore expiration date, see https://github.com/commercialhaskell/stack/pull/4614
-    ignore-expiry: no
+    ignore-expiry: true
 ```
 
 If you provide a replacement index which does not mirror Hackage, it
 is likely that you'll end up with significant breakage, such as most
 snapshots failing to work.
+
+Note: since Stack v2.1.3, `ignore-expiry` was changed to `true` by
+default. For more information on this change, see [issue
+#4928](https://github.com/commercialhaskell/stack/issues/4928).
 
 ### system-ghc
 
diff --git a/src/Stack/Build/Cache.hs b/src/Stack/Build/Cache.hs
--- a/src/Stack/Build/Cache.hs
+++ b/src/Stack/Build/Cache.hs
@@ -20,9 +20,9 @@
     , writeBuildCache
     , writeConfigCache
     , writeCabalMod
-    , setTestSuccess
-    , unsetTestSuccess
-    , checkTestSuccess
+    , TestStatus (..)
+    , setTestStatus
+    , getTestStatus
     , writePrecompiledCache
     , readPrecompiledCache
     -- Exported for testing
@@ -41,7 +41,8 @@
 import           Path.IO
 import           Stack.Constants
 import           Stack.Constants.Config
-import           Stack.Storage
+import           Stack.Storage.Project
+import           Stack.Storage.User
 import           Stack.Types.Build
 import           Stack.Types.Cache
 import           Stack.Types.Config
@@ -207,36 +208,42 @@
     key <- flagCacheKey gid
     saveConfigCache key cache
 
-successBS, failureBS :: IsString s => s
+successBS, failureBS, unknownBS :: IsString s => s
 successBS = "success"
 failureBS = "failure"
+unknownBS = "unknown"
 
--- | Mark a test suite as having succeeded
-setTestSuccess :: HasEnvConfig env
-               => Path Abs Dir
-               -> RIO env ()
-setTestSuccess dir = do
-    fp <- testSuccessFile dir
-    writeBinaryFileAtomic fp successBS
+-- | Status of a test suite
+data TestStatus = TSSuccess | TSFailure | TSUnknown
 
--- | Mark a test suite as not having succeeded
-unsetTestSuccess :: HasEnvConfig env
-                 => Path Abs Dir
-                 -> RIO env ()
-unsetTestSuccess dir = do
+-- | Mark test suite status
+setTestStatus :: HasEnvConfig env
+              => Path Abs Dir
+              -> TestStatus
+              -> RIO env ()
+setTestStatus dir status = do
     fp <- testSuccessFile dir
-    writeBinaryFileAtomic fp failureBS
+    writeBinaryFileAtomic fp $
+      case status of
+        TSSuccess -> successBS
+        TSFailure -> failureBS
+        TSUnknown -> unknownBS
 
 -- | Check if the test suite already passed
-checkTestSuccess :: HasEnvConfig env
-                 => Path Abs Dir
-                 -> RIO env Bool
-checkTestSuccess dir = do
+getTestStatus :: HasEnvConfig env
+              => Path Abs Dir
+              -> RIO env TestStatus
+getTestStatus dir = do
   fp <- testSuccessFile dir
   -- we could ensure the file is the right size first,
   -- but we're not expected an attack from the user's filesystem
-  either (const False) (== successBS)
-    <$> tryIO (readFileBinary $ toFilePath fp)
+  eres <- tryIO (readFileBinary $ toFilePath fp)
+  pure $
+    case eres of
+      Right bs
+        | bs == successBS -> TSSuccess
+        | bs == failureBS -> TSFailure
+      _ -> TSUnknown
 
 --------------------------------------
 -- Precompiled Cache
diff --git a/src/Stack/Build/Execute.hs b/src/Stack/Build/Execute.hs
--- a/src/Stack/Build/Execute.hs
+++ b/src/Stack/Build/Execute.hs
@@ -1597,7 +1597,7 @@
         markExeNotInstalled (taskLocation task) taskProvides
         case taskType of
             TTLocalMutable lp -> do
-                when enableTests $ unsetTestSuccess pkgDir
+                when enableTests $ setTestStatus pkgDir TSUnknown
                 caches <- runMemoizedWith $ lpNewBuildCaches lp
                 mapM_ (uncurry (writeBuildCache pkgDir))
                       (Map.toList caches)
@@ -1656,7 +1656,7 @@
                 ec
                   <- withWorkingDir (toFilePath eeTempDir)
                    $ proc "haddock" ["--hyperlinked-source"]
-                   $ \pc -> withProcess
+                   $ \pc -> withProcessWait
                      (setStdout createSource $ setStderr createSource pc) $ \p ->
                        runConcurrently
                          $ Concurrently (runConduit $ getStdout p .| CL.sinkNull)
@@ -1886,12 +1886,19 @@
               else if toRerunTests topts
                   then return True
                   else do
-                      success <- checkTestSuccess pkgDir
-                      if success
-                          then do
-                              unless (null testsToRun) $ announce "skipping already passed test"
-                              return False
-                          else return True
+                    status <- getTestStatus pkgDir
+                    case status of
+                      TSSuccess -> do
+                        unless (null testsToRun) $ announce "skipping already passed test"
+                        return False
+                      TSFailure
+                        | expectFailure -> do
+                            announce "skipping already failed test that's expected to fail"
+                            return False
+                        | otherwise -> do
+                            announce "rerunning previously failed test"
+                            return True
+                      TSUnknown -> return True
 
         when toRun $ do
             buildDir <- distDirFromDir pkgDir
@@ -1920,6 +1927,18 @@
                 tixPath <- liftM (pkgDir </>) $ parseRelFile $ exeName ++ ".tix"
                 exePath <- liftM (buildDir </>) $ parseRelFile $ "build/" ++ testName' ++ "/" ++ exeName
                 exists <- doesFileExist exePath
+                -- in Stack.Package.packageFromPackageDescription we filter out
+                -- package itself of any dependencies so any tests requiring loading
+                -- of their own package library will fail
+                -- so to prevent this we return it back here but unfortunately unconditionally
+                installed <- case Map.lookup pname installedMap of
+                  Just (_, installed) -> pure $ Just installed
+                  Nothing -> do
+                    idMap <- liftIO $ readTVarIO (eeGhcPkgIds ee)
+                    pure $ Map.lookup (taskProvides task) idMap
+                let pkgGhcIdList = case installed of
+                                       Just (Library _ ghcPkgId _) -> [ghcPkgId]
+                                       _ -> []
                 -- doctest relies on template-haskell in QuickCheck-based tests
                 thGhcId <- case find ((== "template-haskell") . pkgName . dpPackageIdent. snd)
                                 (Map.toList $ eeGlobalDumpPkgs ee) of
@@ -1928,7 +1947,10 @@
                 -- env variable GHC_ENVIRONMENT is set for doctest so module names for
                 -- packages with proper dependencies should no longer get ambiguous
                 -- see e.g. https://github.com/doctest/issues/119
+                -- also we set HASKELL_DIST_DIR to a package dist directory so
+                -- doctest will be able to load modules autogenerated by Cabal
                 let setEnv f pc = modifyEnvVars pc $ \envVars ->
+                      Map.insert "HASKELL_DIST_DIR" (T.pack $ toFilePath buildDir) $
                       Map.insert "GHC_ENVIRONMENT" (T.pack f) envVars
                     fp = toFilePath $ eeTempDir ee </> testGhcEnvRelFile
                     snapDBPath = toFilePathNoTrailingSep (bcoSnapDB $ eeBaseConfigOpts ee)
@@ -1939,7 +1961,7 @@
                         "package-db " <> fromString snapDBPath <> "\n" <>
                         "package-db " <> fromString localDBPath <> "\n" <>
                         foldMap (\ghcId -> "package-id " <> RIO.display (unGhcPkgId ghcId) <> "\n")
-                            (thGhcId:M.elems allDepsMap)
+                            (pkgGhcIdList ++ thGhcId:M.elems allDepsMap)
                 writeFileUtf8Builder fp ghcEnv
                 menv <- liftIO $ setEnv fp =<< configProcessContextSettings config EnvSettings
                     { esIncludeLocals = taskLocation task == Local
@@ -2004,7 +2026,7 @@
                                    $ setStdout output
                                    $ setStderr output
                                      pc0
-                            withProcess pc $ \p -> do
+                            withProcessWait pc $ \p -> do
                               case (getStdout p, getStderr p) of
                                 (Nothing, Nothing) -> pure ()
                                 (Just x, Just y) -> concurrently_ x y
@@ -2058,7 +2080,8 @@
                         hClose h
                         S.readFile $ toFilePath logFile
 
-            unless (Map.null errs || expectFailure) $ throwM $ TestSuiteFailure
+            let succeeded = Map.null errs
+            unless (succeeded || expectFailure) $ throwM $ TestSuiteFailure
                 (taskProvides task)
                 errs
                 (case outputType of
@@ -2066,7 +2089,7 @@
                    OTConsole _ -> Nothing)
                 bs
 
-            setTestSuccess pkgDir
+            setTestStatus pkgDir $ if succeeded then TSSuccess else TSFailure
 
 -- | Implements running a package's benchmarks.
 singleBench :: HasEnvConfig env
diff --git a/src/Stack/Config.hs b/src/Stack/Config.hs
--- a/src/Stack/Config.hs
+++ b/src/Stack/Config.hs
@@ -29,7 +29,7 @@
   ,getInNixShell
   ,defaultConfigYaml
   ,getProjectConfig
-  ,loadBuildConfig
+  ,withBuildConfig
   ) where
 
 import           Control.Monad.Extra (firstJustM)
@@ -64,7 +64,8 @@
 import           Stack.Constants
 import           Stack.Build.Haddock (shouldHaddockDeps)
 import           Stack.Lock (lockCachedWanted)
-import           Stack.Storage (initStorage)
+import           Stack.Storage.Project (initProjectStorage)
+import           Stack.Storage.User (initUserStorage)
 import           Stack.SourceMap
 import           Stack.Types.Build
 import           Stack.Types.Compiler
@@ -373,9 +374,9 @@
        hsc
        (maybe HpackBundled HpackCommand $ getFirst configMonoidOverrideHpack)
        clConnectionCount
-       (\configPantryConfig -> initStorage
+       (\configPantryConfig -> initUserStorage
          (configStackRoot </> relFileStorage)
-         (\configStorage -> inner Config {..}))
+         (\configUserStorage -> inner Config {..}))
 
 -- | Get the default location of the local programs directory.
 getDefaultLocalProgramsBase :: MonadThrow m
@@ -448,8 +449,10 @@
 
 -- | Load the build configuration, adds build-specific values to config loaded by @loadConfig@.
 -- values.
-loadBuildConfig :: RIO Config BuildConfig
-loadBuildConfig = do
+withBuildConfig
+  :: RIO BuildConfig a
+  -> RIO Config a
+withBuildConfig inner = do
     config <- ask
 
     -- If provided, turn the AbstractResolver from the command line
@@ -526,13 +529,20 @@
     wanted <- lockCachedWanted stackYamlFP (projectResolver project) $
         fillProjectWanted stackYamlFP config project
 
-    return BuildConfig
-        { bcConfig = config
-        , bcSMWanted = wanted
-        , bcExtraPackageDBs = extraPackageDBs
-        , bcStackYaml = stackYamlFP
-        , bcCurator = projectCurator project
-        }
+    -- Unfortunately redoes getProjectWorkDir, since we don't have a BuildConfig yet
+    workDir <- view workDirL
+    let projectStorageFile = parent stackYamlFP </> workDir </> relFileStorage
+
+    initProjectStorage projectStorageFile $ \projectStorage -> do
+      let bc = BuildConfig
+            { bcConfig = config
+            , bcSMWanted = wanted
+            , bcExtraPackageDBs = extraPackageDBs
+            , bcStackYaml = stackYamlFP
+            , bcCurator = projectCurator project
+            , bcProjectStorage = projectStorage
+            }
+      runRIO bc inner
   where
     getEmptyProject :: Maybe RawSnapshotLocation -> [PackageIdentifierRevision] -> RIO Config Project
     getEmptyProject mresolver extraDeps = do
diff --git a/src/Stack/Docker.hs b/src/Stack/Docker.hs
--- a/src/Stack/Docker.hs
+++ b/src/Stack/Docker.hs
@@ -49,7 +49,7 @@
 import           Stack.Constants
 import           Stack.Constants.Config
 import           Stack.Setup (ensureDockerStackExe)
-import           Stack.Storage (loadDockerImageExeCache,saveDockerImageExeCache)
+import           Stack.Storage.User (loadDockerImageExeCache,saveDockerImageExeCache)
 import           Stack.Types.Version
 import           Stack.Types.Config
 import           Stack.Types.Docker
diff --git a/src/Stack/Lock.hs b/src/Stack/Lock.hs
--- a/src/Stack/Lock.hs
+++ b/src/Stack/Lock.hs
@@ -121,7 +121,7 @@
         loadAndCompleteSnapshotRaw resolver slocCache pkgLocCache
     let compiler = snapshotCompiler snap
         snPkgs = Map.mapWithKey (\n p h -> snapToDepPackage h n p) (snapshotPackages snap)
-    (wanted, prjCompleted) <- fillWanted Map.empty compiler snPkgs
+    (wanted, prjCompleted) <- fillWanted pkgLocCache compiler snPkgs
     let lockLocations = map (\(CompletedPLI r c) -> LockedLocation r c)
         differentSnapLocs (CompletedSL raw complete)
           | raw == toRawSL complete = Nothing
diff --git a/src/Stack/Nix.hs b/src/Stack/Nix.hs
--- a/src/Stack/Nix.hs
+++ b/src/Stack/Nix.hs
@@ -18,13 +18,12 @@
 import           Lens.Micro (set)
 import           Path.IO
 import qualified Paths_stack as Meta
-import           Stack.Config (getInContainer, loadBuildConfig)
+import           Stack.Config (getInContainer, withBuildConfig)
 import           Stack.Config.Nix (nixCompiler)
 import           Stack.Constants (platformVariantEnvVar,inNixShellEnvVar,inContainerEnvVar)
 import           Stack.Types.Config
 import           Stack.Types.Docker
 import           Stack.Types.Nix
-import           Stack.Docker (getProjectRoot)
 import           System.Environment (getArgs,getExecutablePath,lookupEnv)
 import qualified System.FilePath  as F
 import           RIO.Process (processContextL, exec)
@@ -43,18 +42,19 @@
    local (set processContextL envOverride) $ do
      let cmnd = escape exePath
          args' = map escape args
-     projectRoot <- getProjectRoot
-     mshellFile <-
-         traverse (resolveFile projectRoot) $
-         nixInitFile (configNix config)
 
+     mshellFile <- case configProjectRoot config of
+         Just projectRoot ->
+             traverse (resolveFile projectRoot) $ nixInitFile (configNix config)
+         Nothing -> pure Nothing
+
      -- This will never result in double loading the build config, since:
      --
      -- 1. This function explicitly takes a Config, not a HasConfig
      --
      -- 2. This function ends up exiting before running other code
      -- (thus the void return type)
-     compilerVersion <- view wantedCompilerVersionL <$> loadBuildConfig
+     compilerVersion <- withBuildConfig $ view wantedCompilerVersionL
 
      ghc <- either throwIO return $ nixCompiler compilerVersion
      let pkgsInConfig = nixPackages (configNix config)
diff --git a/src/Stack/Options/DotParser.hs b/src/Stack/Options/DotParser.hs
--- a/src/Stack/Options/DotParser.hs
+++ b/src/Stack/Options/DotParser.hs
@@ -20,7 +20,7 @@
   DotOpts <$> includeExternal
           <*> includeBase
           <*> depthLimit
-          <*> fmap (maybe Set.empty Set.fromList . fmap splitNames) prunedPkgs
+          <*> fmap (maybe Set.empty $ Set.fromList . splitNames) prunedPkgs
           <*> targetsParser
           <*> flagsParser
           <*> testTargets
diff --git a/src/Stack/Package.hs b/src/Stack/Package.hs
--- a/src/Stack/Package.hs
+++ b/src/Stack/Package.hs
@@ -27,7 +27,6 @@
   ,applyForceCustomBuild
   ) where
 
-import qualified Data.ByteString.Char8 as B8
 import           Data.List (find, isPrefixOf, unzip)
 import           Data.Maybe (maybe)
 import qualified Data.Map.Strict as M
@@ -1117,7 +1116,8 @@
         ]
       pure (S.empty, [])
     Right iface -> do
-      let moduleNames = fmap (fromString . B8.unpack . fst) . Iface.unList . Iface.dmods . Iface.deps
+      let moduleNames = fmap (fromString . T.unpack . decodeUtf8Lenient . fst) .
+                        Iface.unList . Iface.dmods . Iface.deps
           resolveFileDependency file = do
             resolved <- liftIO (forgivingAbsence (resolveFile dir file)) >>= rejectMissingFile
             when (isNothing resolved) $
diff --git a/src/Stack/Prelude.hs b/src/Stack/Prelude.hs
--- a/src/Stack/Prelude.hs
+++ b/src/Stack/Prelude.hs
@@ -40,7 +40,7 @@
 import qualified Data.Conduit.Binary as CB
 import qualified Data.Conduit.List as CL
 import           Data.Conduit.Process.Typed (withLoggedProcess_, createSource, byteStringInput)
-import           RIO.Process (HasProcessContext (..), ProcessContext, setStdin, closed, getStderr, getStdout, proc, withProcess_, setStdout, setStderr, ProcessConfig, readProcess_, workingDirL)
+import           RIO.Process (HasProcessContext (..), ProcessContext, setStdin, closed, getStderr, getStdout, proc, withProcessWait_, setStdout, setStderr, ProcessConfig, readProcess_, workingDirL, waitExitCode)
 import           Data.Text.Encoding (decodeUtf8With)
 import           Data.Text.Encoding.Error (lenientDecode)
 
@@ -79,9 +79,9 @@
            -- See https://github.com/commercialhaskell/stack/pull/4722
            $ setStdin (byteStringInput "")
              pc0
-    withProcess_ pc $ \p ->
-      runConduit (getStderr p .| sinkStderr) `concurrently`
-      runConduit (getStdout p .| sinkStdout)
+    withProcessWait_ pc $ \p ->
+      (runConduit (getStderr p .| sinkStderr) `concurrently`
+      runConduit (getStdout p .| sinkStdout)) <* waitExitCode p
 
 -- | Consume the stdout of a process feeding strict 'ByteString's to a consumer.
 -- If the process fails, spits out stdout and stderr as error log
diff --git a/src/Stack/Runners.hs b/src/Stack/Runners.hs
--- a/src/Stack/Runners.hs
+++ b/src/Stack/Runners.hs
@@ -29,7 +29,7 @@
 import qualified Stack.Docker as Docker
 import qualified Stack.Nix as Nix
 import           Stack.Setup
-import           Stack.Storage (upgradeChecksSince, logUpgradeCheck)
+import           Stack.Storage.User (upgradeChecksSince, logUpgradeCheck)
 import           Stack.Types.Config
 import           Stack.Types.Docker (dockerEnable)
 import           Stack.Types.Nix (nixEnable)
@@ -54,14 +54,6 @@
     :: RIO EnvConfig a
     -> RIO Config a
 withDefaultEnvConfig = withEnvConfig AllowNoTargets defaultBuildOptsCLI
-
--- | Upgrade a 'Config' environment to a 'BuildConfig' environment by
--- performing further parsing of project-specific configuration. This
--- is intended to be run inside a call to 'withConfig'.
-withBuildConfig :: RIO BuildConfig a -> RIO Config a
-withBuildConfig inner = do
-  bconfig <- loadBuildConfig
-  runRIO bconfig inner
 
 -- | Upgrade a 'Config' environment to an 'EnvConfig' environment by
 -- performing further parsing of project-specific configuration (like
diff --git a/src/Stack/Setup.hs b/src/Stack/Setup.hs
--- a/src/Stack/Setup.hs
+++ b/src/Stack/Setup.hs
@@ -81,7 +81,7 @@
 import              Stack.Prelude hiding (Display (..))
 import              Stack.SourceMap
 import              Stack.Setup.Installed
-import              Stack.Storage (loadCompilerPaths, saveCompilerPaths)
+import              Stack.Storage.User (loadCompilerPaths, saveCompilerPaths)
 import              Stack.Types.Build
 import              Stack.Types.Compiler
 import              Stack.Types.CompilerBuild
@@ -504,10 +504,10 @@
 
   if
     | cabalVersion < mkVersion [1, 19, 2] -> do
-        logWarn $ "Stack no longer supported Cabal versions below 1.19.2,"
-        logWarn $ "but version " <> fromString (versionString cabalVersion) <> "was found."
+        logWarn $ "Stack no longer supports Cabal versions below 1.19.2,"
+        logWarn $ "but version " <> fromString (versionString cabalVersion) <> " was found."
         logWarn "This invocation will most likely fail."
-        logWarn "To fix this, either use a newer version of Stack or a newer resolver"
+        logWarn "To fix this, either use an older version of Stack or a newer resolver"
         logWarn "Acceptable resolvers: lts-3.0/nightly-2015-05-05 or later"
     | cabalVersion >= mkVersion [2, 5] ->
         logWarn $
@@ -1561,7 +1561,7 @@
                 ec <-
                   proc cmd args $ \pc ->
                   if isExtract
-                    then withProcess (setStdout createSource pc) $ \p -> do
+                    then withProcessWait (setStdout createSource pc) $ \p -> do
                         total <- runConduit
                             $ getStdout p
                            .| filterCE (== 10) -- newline characters
diff --git a/src/Stack/Storage.hs b/src/Stack/Storage.hs
deleted file mode 100644
--- a/src/Stack/Storage.hs
+++ /dev/null
@@ -1,570 +0,0 @@
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE GADTs #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE TupleSections #-}
-{-# LANGUAGE TypeFamilies #-}
-{-# OPTIONS_GHC -Wno-unused-top-binds -Wno-identities #-}
-
--- | Work with SQLite database used for caches.
-module Stack.Storage
-    ( initStorage
-    , withStorage
-    , ConfigCacheKey
-    , configCacheKey
-    , loadConfigCache
-    , saveConfigCache
-    , deactiveConfigCache
-    , PrecompiledCacheKey
-    , precompiledCacheKey
-    , loadPrecompiledCache
-    , savePrecompiledCache
-    , loadDockerImageExeCache
-    , saveDockerImageExeCache
-    , loadCompilerPaths
-    , saveCompilerPaths
-    , upgradeChecksSince
-    , logUpgradeCheck
-    ) where
-
-import qualified Data.ByteString as S
-import qualified Data.Set as Set
-import qualified Data.Text as T
-import Data.Time.Clock (UTCTime)
-import Database.Persist.Sql (SqlBackend)
-import Database.Persist.Sqlite
-import Database.Persist.TH
-import Distribution.Text (simpleParse, display)
-import Foreign.C.Types (CTime (..))
-import qualified Pantry.Internal as SQLite
-import Path
-import Path.IO (resolveFile', resolveDir')
-import qualified RIO.FilePath as FP
-import Stack.Prelude hiding (MigrationFailure)
-import Stack.Types.Build
-import Stack.Types.Cache
-import Stack.Types.Compiler
-import Stack.Types.CompilerBuild (CompilerBuild)
-import Stack.Types.Config (HasConfig, configL, configStorage, CompilerPaths (..), GhcPkgExe (..))
-import Stack.Types.GhcPkgId
-import System.Posix.Types (COff (..))
-import System.PosixCompat.Files (getFileStatus, fileSize, modificationTime)
-
-share [ mkPersist sqlSettings
-      , mkDeleteCascade sqlSettings
-      , mkMigrate "migrateAll"
-    ]
-    [persistLowerCase|
-ConfigCacheParent sql="config_cache"
-  directory FilePath "default=(hex(randomblob(16)))"
-  type ConfigCacheType
-  pkgSrc CachePkgSrc
-  active Bool
-  pathEnvVar Text
-  haddock Bool default=0
-  UniqueConfigCacheParent directory type sql="unique_config_cache"
-  deriving Show
-
-ConfigCacheDirOption
-  parent ConfigCacheParentId sql="config_cache_id"
-  index Int
-  value String sql="option"
-  UniqueConfigCacheDirOption parent index
-  deriving Show
-
-ConfigCacheNoDirOption
-  parent ConfigCacheParentId sql="config_cache_id"
-  index Int
-  value String sql="option"
-  UniqueConfigCacheNoDirOption parent index
-  deriving Show
-
-ConfigCacheDep
-  parent ConfigCacheParentId sql="config_cache_id"
-  value GhcPkgId sql="ghc_pkg_id"
-  UniqueConfigCacheDep parent value
-  deriving Show
-
-ConfigCacheComponent
-  parent ConfigCacheParentId sql="config_cache_id"
-  value S.ByteString sql="component"
-  UniqueConfigCacheComponent parent value
-  deriving Show
-
-PrecompiledCacheParent sql="precompiled_cache"
-  platformGhcDir FilePath "default=(hex(randomblob(16)))"
-  compiler Text
-  cabalVersion Text
-  packageKey Text
-  optionsHash ByteString
-  haddock Bool default=0
-  library FilePath Maybe
-  UniquePrecompiledCacheParent platformGhcDir compiler cabalVersion packageKey optionsHash haddock sql="unique_precompiled_cache"
-  deriving Show
-
-PrecompiledCacheSubLib
-  parent PrecompiledCacheParentId sql="precompiled_cache_id"
-  value FilePath sql="sub_lib"
-  UniquePrecompiledCacheSubLib parent value
-  deriving Show
-
-PrecompiledCacheExe
-  parent PrecompiledCacheParentId sql="precompiled_cache_id"
-  value FilePath sql="exe"
-  UniquePrecompiledCacheExe parent value
-  deriving Show
-
-DockerImageExeCache
-  imageHash Text
-  exePath FilePath
-  exeTimestamp UTCTime
-  compatible Bool
-  DockerImageExeCacheUnique imageHash exePath exeTimestamp
-  deriving Show
-
-CompilerCache
-  actualVersion ActualCompiler
-  arch Text
-
-  -- Include ghc executable size and modified time for sanity checking entries
-  ghcPath FilePath
-  ghcSize Int64
-  ghcModified Int64
-
-  ghcPkgPath FilePath
-  runghcPath FilePath
-  haddockPath FilePath
-
-  cabalVersion Text
-  globalDb FilePath
-  globalDbCacheSize Int64
-  globalDbCacheModified Int64
-  info ByteString
-
-  -- This is the ugliest part of this table, simply storing a Show/Read version of the
-  -- data. We could do a better job with normalized data and proper table structure.
-  -- However, recomputing this value in the future if the data representation changes
-  -- is very cheap, so we'll take the easy way out for now.
-  globalDump Text
-
-  UniqueCompilerInfo ghcPath
-
--- Last time certain actions were performed
-LastPerformed
-  action Action
-  timestamp UTCTime
-  UniqueAction action
-|]
-
--- | Initialize the database.
-initStorage ::
-       HasLogFunc env
-    => Path Abs File -- ^ storage file
-    -> (SQLite.Storage -> RIO env a)
-    -> RIO env a
-initStorage = SQLite.initStorage "Stack" migrateAll
-
--- | Run an action in a database transaction
-withStorage ::
-       (HasConfig env, HasLogFunc env)
-    => ReaderT SqlBackend (RIO env) a
-    -> RIO env a
-withStorage inner =
-    flip SQLite.withStorage_ inner =<< view (configL . to configStorage)
-
--- | Key used to retrieve configuration or flag cache
-type ConfigCacheKey = Unique ConfigCacheParent
-
--- | Build key used to retrieve configuration or flag cache
-configCacheKey :: Path Abs Dir -> ConfigCacheType -> ConfigCacheKey
-configCacheKey dir = UniqueConfigCacheParent (toFilePath dir)
-
--- | Internal helper to read the 'ConfigCache'
-readConfigCache ::
-       (HasConfig env, HasLogFunc env)
-    => Entity ConfigCacheParent
-    -> ReaderT SqlBackend (RIO env) ConfigCache
-readConfigCache (Entity parentId ConfigCacheParent {..}) = do
-    let configCachePkgSrc = configCacheParentPkgSrc
-    coDirs <-
-        map (configCacheDirOptionValue . entityVal) <$>
-        selectList
-            [ConfigCacheDirOptionParent ==. parentId]
-            [Asc ConfigCacheDirOptionIndex]
-    coNoDirs <-
-        map (configCacheNoDirOptionValue . entityVal) <$>
-        selectList
-            [ConfigCacheNoDirOptionParent ==. parentId]
-            [Asc ConfigCacheNoDirOptionIndex]
-    let configCacheOpts = ConfigureOpts {..}
-    configCacheDeps <-
-        Set.fromList . map (configCacheDepValue . entityVal) <$>
-        selectList [ConfigCacheDepParent ==. parentId] []
-    configCacheComponents <-
-        Set.fromList . map (configCacheComponentValue . entityVal) <$>
-        selectList [ConfigCacheComponentParent ==. parentId] []
-    let configCachePathEnvVar = configCacheParentPathEnvVar
-    let configCacheHaddock = configCacheParentHaddock
-    return ConfigCache {..}
-
--- | Load 'ConfigCache' from the database.
-loadConfigCache ::
-       (HasConfig env, HasLogFunc env)
-    => ConfigCacheKey
-    -> RIO env (Maybe ConfigCache)
-loadConfigCache key =
-    withStorage $ do
-        mparent <- getBy key
-        case mparent of
-            Nothing -> return Nothing
-            Just parentEntity@(Entity _ ConfigCacheParent {..})
-                | configCacheParentActive ->
-                    Just <$> readConfigCache parentEntity
-                | otherwise -> return Nothing
-
--- | Insert or update 'ConfigCache' to the database.
-saveConfigCache ::
-       (HasConfig env, HasLogFunc env)
-    => ConfigCacheKey
-    -> ConfigCache
-    -> RIO env ()
-saveConfigCache key@(UniqueConfigCacheParent dir type_) new =
-    withStorage $ do
-        mparent <- getBy key
-        (parentId, mold) <-
-            case mparent of
-                Nothing ->
-                    (, Nothing) <$>
-                    insert
-                        ConfigCacheParent
-                            { configCacheParentDirectory = dir
-                            , configCacheParentType = type_
-                            , configCacheParentPkgSrc = configCachePkgSrc new
-                            , configCacheParentActive = True
-                            , configCacheParentPathEnvVar = configCachePathEnvVar new
-                            , configCacheParentHaddock = configCacheHaddock new
-                            }
-                Just parentEntity@(Entity parentId _) -> do
-                    old <- readConfigCache parentEntity
-                    update
-                        parentId
-                        [ ConfigCacheParentPkgSrc =. configCachePkgSrc new
-                        , ConfigCacheParentActive =. True
-                        , ConfigCacheParentPathEnvVar =. configCachePathEnvVar new
-                        ]
-                    return (parentId, Just old)
-        updateList
-            ConfigCacheDirOption
-            ConfigCacheDirOptionParent
-            parentId
-            ConfigCacheDirOptionIndex
-            (maybe [] (coDirs . configCacheOpts) mold)
-            (coDirs $ configCacheOpts new)
-        updateList
-            ConfigCacheNoDirOption
-            ConfigCacheNoDirOptionParent
-            parentId
-            ConfigCacheNoDirOptionIndex
-            (maybe [] (coNoDirs . configCacheOpts) mold)
-            (coNoDirs $ configCacheOpts new)
-        updateSet
-            ConfigCacheDep
-            ConfigCacheDepParent
-            parentId
-            ConfigCacheDepValue
-            (maybe Set.empty configCacheDeps mold)
-            (configCacheDeps new)
-        updateSet
-            ConfigCacheComponent
-            ConfigCacheComponentParent
-            parentId
-            ConfigCacheComponentValue
-            (maybe Set.empty configCacheComponents mold)
-            (configCacheComponents new)
-
--- | Mark 'ConfigCache' as inactive in the database.
--- We use a flag instead of deleting the records since, in most cases, the same
--- cache will be written again within in a few seconds (after
--- `cabal configure`), so this avoids unnecessary database churn.
-deactiveConfigCache :: HasConfig env => ConfigCacheKey -> RIO env ()
-deactiveConfigCache (UniqueConfigCacheParent dir type_) =
-    withStorage $
-    updateWhere
-        [ConfigCacheParentDirectory ==. dir, ConfigCacheParentType ==. type_]
-        [ConfigCacheParentActive =. False]
-
--- | Key used to retrieve the precompiled cache
-type PrecompiledCacheKey = Unique PrecompiledCacheParent
-
--- | Build key used to retrieve the precompiled cache
-precompiledCacheKey ::
-       Path Rel Dir
-    -> ActualCompiler
-    -> Version
-    -> Text
-    -> ByteString
-    -> Bool
-    -> PrecompiledCacheKey
-precompiledCacheKey platformGhcDir compiler cabalVersion =
-    UniquePrecompiledCacheParent
-        (toFilePath platformGhcDir)
-        (compilerVersionText compiler)
-        (T.pack $ versionString cabalVersion)
-
--- | Internal helper to read the 'PrecompiledCache' from the database
-readPrecompiledCache ::
-       (HasConfig env, HasLogFunc env)
-    => PrecompiledCacheKey
-    -> ReaderT SqlBackend (RIO env) (Maybe ( PrecompiledCacheParentId
-                                           , PrecompiledCache Rel))
-readPrecompiledCache key = do
-    mparent <- getBy key
-    forM mparent $ \(Entity parentId PrecompiledCacheParent {..}) -> do
-        pcLibrary <- mapM parseRelFile precompiledCacheParentLibrary
-        pcSubLibs <-
-            mapM (parseRelFile . precompiledCacheSubLibValue . entityVal) =<<
-            selectList [PrecompiledCacheSubLibParent ==. parentId] []
-        pcExes <-
-            mapM (parseRelFile . precompiledCacheExeValue . entityVal) =<<
-            selectList [PrecompiledCacheExeParent ==. parentId] []
-        return (parentId, PrecompiledCache {..})
-
--- | Load 'PrecompiledCache' from the database.
-loadPrecompiledCache ::
-       (HasConfig env, HasLogFunc env)
-    => PrecompiledCacheKey
-    -> RIO env (Maybe (PrecompiledCache Rel))
-loadPrecompiledCache key = withStorage $ fmap snd <$> readPrecompiledCache key
-
--- | Insert or update 'PrecompiledCache' to the database.
-savePrecompiledCache ::
-       (HasConfig env, HasLogFunc env)
-    => PrecompiledCacheKey
-    -> PrecompiledCache Rel
-    -> RIO env ()
-savePrecompiledCache key@(UniquePrecompiledCacheParent precompiledCacheParentPlatformGhcDir precompiledCacheParentCompiler precompiledCacheParentCabalVersion precompiledCacheParentPackageKey precompiledCacheParentOptionsHash precompiledCacheParentHaddock) new =
-    withStorage $ do
-        let precompiledCacheParentLibrary = fmap toFilePath (pcLibrary new)
-        mIdOld <- readPrecompiledCache key
-        (parentId, mold) <-
-            case mIdOld of
-                Nothing -> (, Nothing) <$> insert PrecompiledCacheParent {..}
-                Just (parentId, old) -> do
-                    update
-                        parentId
-                        [ PrecompiledCacheParentLibrary =.
-                          precompiledCacheParentLibrary
-                        ]
-                    return (parentId, Just old)
-        updateSet
-            PrecompiledCacheSubLib
-            PrecompiledCacheSubLibParent
-            parentId
-            PrecompiledCacheSubLibValue
-            (maybe Set.empty (toFilePathSet . pcSubLibs) mold)
-            (toFilePathSet $ pcSubLibs new)
-        updateSet
-            PrecompiledCacheExe
-            PrecompiledCacheExeParent
-            parentId
-            PrecompiledCacheExeValue
-            (maybe Set.empty (toFilePathSet . pcExes) mold)
-            (toFilePathSet $ pcExes new)
-  where
-    toFilePathSet = Set.fromList . map toFilePath
-
--- | Get the record of whether an executable is compatible with a Docker image
-loadDockerImageExeCache ::
-       (HasConfig env, HasLogFunc env)
-    => Text
-    -> Path Abs File
-    -> UTCTime
-    -> RIO env (Maybe Bool)
-loadDockerImageExeCache imageId exePath exeTimestamp =
-    withStorage $
-    fmap (dockerImageExeCacheCompatible . entityVal) <$>
-    getBy (DockerImageExeCacheUnique imageId (toFilePath exePath) exeTimestamp)
-
--- | Sest the record of whether an executable is compatible with a Docker image
-saveDockerImageExeCache ::
-       (HasConfig env, HasLogFunc env)
-    => Text
-    -> Path Abs File
-    -> UTCTime
-    -> Bool
-    -> RIO env ()
-saveDockerImageExeCache imageId exePath exeTimestamp compatible =
-    void $
-    withStorage $
-    upsert
-        (DockerImageExeCache
-             imageId
-             (toFilePath exePath)
-             exeTimestamp
-             compatible)
-        []
-
--- | Efficiently update a set of values stored in a database table
-updateSet ::
-       ( PersistEntityBackend record ~ BaseBackend backend
-       , PersistField parentid
-       , PersistField value
-       , Ord value
-       , PersistEntity record
-       , MonadIO m
-       , PersistQueryWrite backend
-       )
-    => (parentid -> value -> record)
-    -> EntityField record parentid
-    -> parentid
-    -> EntityField record value
-    -> Set value
-    -> Set value
-    -> ReaderT backend m ()
-updateSet recordCons parentFieldCons parentId valueFieldCons old new =
-    when (old /= new) $ do
-        deleteWhere
-            [ parentFieldCons ==. parentId
-            , valueFieldCons <-. Set.toList (Set.difference old new)
-            ]
-        insertMany_ $
-            map (recordCons parentId) $ Set.toList (Set.difference new old)
-
--- | Efficiently update a list of values stored in a database table.
-updateList ::
-       ( PersistEntityBackend record ~ BaseBackend backend
-       , PersistField parentid
-       , Ord value
-       , PersistEntity record
-       , MonadIO m
-       , PersistQueryWrite backend
-       )
-    => (parentid -> Int -> value -> record)
-    -> EntityField record parentid
-    -> parentid
-    -> EntityField record Int
-    -> [value]
-    -> [value]
-    -> ReaderT backend m ()
-updateList recordCons parentFieldCons parentId indexFieldCons old new =
-    when (old /= new) $ do
-        let oldSet = Set.fromList (zip [0 ..] old)
-            newSet = Set.fromList (zip [0 ..] new)
-        deleteWhere
-            [ parentFieldCons ==. parentId
-            , indexFieldCons <-.
-              map fst (Set.toList $ Set.difference oldSet newSet)
-            ]
-        insertMany_ $
-            map (uncurry $ recordCons parentId) $
-            Set.toList (Set.difference newSet oldSet)
-
--- | Type-restricted version of 'fromIntegral' to ensure we're making
--- the value bigger, not smaller.
-sizeToInt64 :: COff -> Int64
-sizeToInt64 (COff i) = fromIntegral i -- fromIntegral added for 32-bit systems
-
--- | Type-restricted version of 'fromIntegral' to ensure we're making
--- the value bigger, not smaller.
-timeToInt64 :: CTime -> Int64
-timeToInt64 (CTime i) = fromIntegral i -- fromIntegral added for 32-bit systems
-
--- | Load compiler information, if available, and confirm that the
--- referenced files are unchanged. May throw exceptions!
-loadCompilerPaths
-  :: HasConfig env
-  => Path Abs File -- ^ compiler executable
-  -> CompilerBuild
-  -> Bool -- ^ sandboxed?
-  -> RIO env (Maybe CompilerPaths)
-loadCompilerPaths compiler build sandboxed = do
-  mres <- withStorage $ getBy $ UniqueCompilerInfo $ toFilePath compiler
-  for mres $ \(Entity _ CompilerCache {..}) -> do
-    compilerStatus <- liftIO $ getFileStatus $ toFilePath compiler
-    when
-      (compilerCacheGhcSize /= sizeToInt64 (fileSize compilerStatus) ||
-       compilerCacheGhcModified /= timeToInt64 (modificationTime compilerStatus))
-      (throwString "Compiler file metadata mismatch, ignoring cache")
-    globalDbStatus <- liftIO $ getFileStatus $ compilerCacheGlobalDb FP.</> "package.cache"
-    when
-      (compilerCacheGlobalDbCacheSize /= sizeToInt64 (fileSize globalDbStatus) ||
-       compilerCacheGlobalDbCacheModified /= timeToInt64 (modificationTime globalDbStatus))
-      (throwString "Global package cache file metadata mismatch, ignoring cache")
-
-    -- We could use parseAbsFile instead of resolveFile' below to
-    -- bypass some system calls, at the cost of some really wonky
-    -- error messages in case someone screws up their GHC installation
-    pkgexe <- resolveFile' compilerCacheGhcPkgPath
-    runghc <- resolveFile' compilerCacheRunghcPath
-    haddock <- resolveFile' compilerCacheHaddockPath
-    globaldb <- resolveDir' compilerCacheGlobalDb
-
-    cabalVersion <- parseVersionThrowing $ T.unpack compilerCacheCabalVersion
-    globalDump <-
-      case readMaybe $ T.unpack compilerCacheGlobalDump of
-        Nothing -> throwString "Global dump did not parse correctly"
-        Just globalDump -> pure globalDump
-    arch <-
-      case simpleParse $ T.unpack compilerCacheArch of
-        Nothing -> throwString $ "Invalid arch: " ++ show compilerCacheArch
-        Just arch -> pure arch
-
-    pure CompilerPaths
-      { cpCompiler = compiler
-      , cpCompilerVersion = compilerCacheActualVersion
-      , cpArch = arch
-      , cpBuild = build
-      , cpPkg = GhcPkgExe pkgexe
-      , cpInterpreter = runghc
-      , cpHaddock = haddock
-      , cpSandboxed = sandboxed
-      , cpCabalVersion = cabalVersion
-      , cpGlobalDB = globaldb
-      , cpGhcInfo = compilerCacheInfo
-      , cpGlobalDump = globalDump
-      }
-
--- | Save compiler information. May throw exceptions!
-saveCompilerPaths
-  :: HasConfig env
-  => CompilerPaths
-  -> RIO env ()
-saveCompilerPaths CompilerPaths {..} = withStorage $ do
-  deleteBy $ UniqueCompilerInfo $ toFilePath cpCompiler
-  compilerStatus <- liftIO $ getFileStatus $ toFilePath cpCompiler
-  globalDbStatus <- liftIO $ getFileStatus $ toFilePath $ cpGlobalDB </> $(mkRelFile "package.cache")
-  let GhcPkgExe pkgexe = cpPkg
-  insert_ CompilerCache
-    { compilerCacheActualVersion = cpCompilerVersion
-    , compilerCacheGhcPath = toFilePath cpCompiler
-    , compilerCacheGhcSize = sizeToInt64 $ fileSize compilerStatus
-    , compilerCacheGhcModified = timeToInt64 $ modificationTime compilerStatus
-    , compilerCacheGhcPkgPath = toFilePath pkgexe
-    , compilerCacheRunghcPath = toFilePath cpInterpreter
-    , compilerCacheHaddockPath = toFilePath cpHaddock
-    , compilerCacheCabalVersion = T.pack $ versionString cpCabalVersion
-    , compilerCacheGlobalDb = toFilePath cpGlobalDB
-    , compilerCacheGlobalDbCacheSize = sizeToInt64 $ fileSize globalDbStatus
-    , compilerCacheGlobalDbCacheModified = timeToInt64 $ modificationTime globalDbStatus
-    , compilerCacheInfo = cpGhcInfo
-    , compilerCacheGlobalDump = tshow cpGlobalDump
-    , compilerCacheArch = T.pack $ Distribution.Text.display cpArch
-    }
-
--- | How many upgrade checks have occurred since the given timestamp?
-upgradeChecksSince :: HasConfig env => UTCTime -> RIO env Int
-upgradeChecksSince since = withStorage $ count
-  [ LastPerformedAction ==. UpgradeCheck
-  , LastPerformedTimestamp >=. since
-  ]
-
--- | Log in the database that an upgrade check occurred at the given time.
-logUpgradeCheck :: HasConfig env => UTCTime -> RIO env ()
-logUpgradeCheck time = withStorage $ void $ upsert
-  (LastPerformed UpgradeCheck time)
-  [LastPerformedTimestamp =. time]
diff --git a/src/Stack/Storage/Project.hs b/src/Stack/Storage/Project.hs
new file mode 100644
--- /dev/null
+++ b/src/Stack/Storage/Project.hs
@@ -0,0 +1,215 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# OPTIONS_GHC -Wno-unused-top-binds -Wno-identities #-}
+
+-- | Work with SQLite database used for caches across a single project.
+module Stack.Storage.Project
+    ( initProjectStorage
+    , ConfigCacheKey
+    , configCacheKey
+    , loadConfigCache
+    , saveConfigCache
+    , deactiveConfigCache
+    ) where
+
+import qualified Data.ByteString as S
+import qualified Data.Set as Set
+import Database.Persist.Sql (SqlBackend)
+import Database.Persist.Sqlite
+import Database.Persist.TH
+import qualified Pantry.Internal as SQLite
+import Path
+import Stack.Prelude hiding (MigrationFailure)
+import Stack.Storage.Util
+import Stack.Types.Build
+import Stack.Types.Cache
+import Stack.Types.Config (HasBuildConfig, buildConfigL, bcProjectStorage, ProjectStorage (..))
+import Stack.Types.GhcPkgId
+
+share [ mkPersist sqlSettings
+      , mkDeleteCascade sqlSettings
+      , mkMigrate "migrateAll"
+    ]
+    [persistLowerCase|
+ConfigCacheParent sql="config_cache"
+  directory FilePath "default=(hex(randomblob(16)))"
+  type ConfigCacheType
+  pkgSrc CachePkgSrc
+  active Bool
+  pathEnvVar Text
+  haddock Bool default=0
+  UniqueConfigCacheParent directory type sql="unique_config_cache"
+  deriving Show
+
+ConfigCacheDirOption
+  parent ConfigCacheParentId sql="config_cache_id"
+  index Int
+  value String sql="option"
+  UniqueConfigCacheDirOption parent index
+  deriving Show
+
+ConfigCacheNoDirOption
+  parent ConfigCacheParentId sql="config_cache_id"
+  index Int
+  value String sql="option"
+  UniqueConfigCacheNoDirOption parent index
+  deriving Show
+
+ConfigCacheDep
+  parent ConfigCacheParentId sql="config_cache_id"
+  value GhcPkgId sql="ghc_pkg_id"
+  UniqueConfigCacheDep parent value
+  deriving Show
+
+ConfigCacheComponent
+  parent ConfigCacheParentId sql="config_cache_id"
+  value S.ByteString sql="component"
+  UniqueConfigCacheComponent parent value
+  deriving Show
+|]
+
+-- | Initialize the database.
+initProjectStorage ::
+       HasLogFunc env
+    => Path Abs File -- ^ storage file
+    -> (ProjectStorage -> RIO env a)
+    -> RIO env a
+initProjectStorage fp f = SQLite.initStorage "Stack" migrateAll fp $ f . ProjectStorage
+
+-- | Run an action in a database transaction
+withProjectStorage ::
+       (HasBuildConfig env, HasLogFunc env)
+    => ReaderT SqlBackend (RIO env) a
+    -> RIO env a
+withProjectStorage inner =
+    flip SQLite.withStorage_ inner =<< view (buildConfigL . to bcProjectStorage . to unProjectStorage)
+
+-- | Key used to retrieve configuration or flag cache
+type ConfigCacheKey = Unique ConfigCacheParent
+
+-- | Build key used to retrieve configuration or flag cache
+configCacheKey :: Path Abs Dir -> ConfigCacheType -> ConfigCacheKey
+configCacheKey dir = UniqueConfigCacheParent (toFilePath dir)
+
+-- | Internal helper to read the 'ConfigCache'
+readConfigCache ::
+       (HasBuildConfig env, HasLogFunc env)
+    => Entity ConfigCacheParent
+    -> ReaderT SqlBackend (RIO env) ConfigCache
+readConfigCache (Entity parentId ConfigCacheParent {..}) = do
+    let configCachePkgSrc = configCacheParentPkgSrc
+    coDirs <-
+        map (configCacheDirOptionValue . entityVal) <$>
+        selectList
+            [ConfigCacheDirOptionParent ==. parentId]
+            [Asc ConfigCacheDirOptionIndex]
+    coNoDirs <-
+        map (configCacheNoDirOptionValue . entityVal) <$>
+        selectList
+            [ConfigCacheNoDirOptionParent ==. parentId]
+            [Asc ConfigCacheNoDirOptionIndex]
+    let configCacheOpts = ConfigureOpts {..}
+    configCacheDeps <-
+        Set.fromList . map (configCacheDepValue . entityVal) <$>
+        selectList [ConfigCacheDepParent ==. parentId] []
+    configCacheComponents <-
+        Set.fromList . map (configCacheComponentValue . entityVal) <$>
+        selectList [ConfigCacheComponentParent ==. parentId] []
+    let configCachePathEnvVar = configCacheParentPathEnvVar
+    let configCacheHaddock = configCacheParentHaddock
+    return ConfigCache {..}
+
+-- | Load 'ConfigCache' from the database.
+loadConfigCache ::
+       (HasBuildConfig env, HasLogFunc env)
+    => ConfigCacheKey
+    -> RIO env (Maybe ConfigCache)
+loadConfigCache key =
+    withProjectStorage $ do
+        mparent <- getBy key
+        case mparent of
+            Nothing -> return Nothing
+            Just parentEntity@(Entity _ ConfigCacheParent {..})
+                | configCacheParentActive ->
+                    Just <$> readConfigCache parentEntity
+                | otherwise -> return Nothing
+
+-- | Insert or update 'ConfigCache' to the database.
+saveConfigCache ::
+       (HasBuildConfig env, HasLogFunc env)
+    => ConfigCacheKey
+    -> ConfigCache
+    -> RIO env ()
+saveConfigCache key@(UniqueConfigCacheParent dir type_) new =
+    withProjectStorage $ do
+        mparent <- getBy key
+        (parentId, mold) <-
+            case mparent of
+                Nothing ->
+                    (, Nothing) <$>
+                    insert
+                        ConfigCacheParent
+                            { configCacheParentDirectory = dir
+                            , configCacheParentType = type_
+                            , configCacheParentPkgSrc = configCachePkgSrc new
+                            , configCacheParentActive = True
+                            , configCacheParentPathEnvVar = configCachePathEnvVar new
+                            , configCacheParentHaddock = configCacheHaddock new
+                            }
+                Just parentEntity@(Entity parentId _) -> do
+                    old <- readConfigCache parentEntity
+                    update
+                        parentId
+                        [ ConfigCacheParentPkgSrc =. configCachePkgSrc new
+                        , ConfigCacheParentActive =. True
+                        , ConfigCacheParentPathEnvVar =. configCachePathEnvVar new
+                        ]
+                    return (parentId, Just old)
+        updateList
+            ConfigCacheDirOption
+            ConfigCacheDirOptionParent
+            parentId
+            ConfigCacheDirOptionIndex
+            (maybe [] (coDirs . configCacheOpts) mold)
+            (coDirs $ configCacheOpts new)
+        updateList
+            ConfigCacheNoDirOption
+            ConfigCacheNoDirOptionParent
+            parentId
+            ConfigCacheNoDirOptionIndex
+            (maybe [] (coNoDirs . configCacheOpts) mold)
+            (coNoDirs $ configCacheOpts new)
+        updateSet
+            ConfigCacheDep
+            ConfigCacheDepParent
+            parentId
+            ConfigCacheDepValue
+            (maybe Set.empty configCacheDeps mold)
+            (configCacheDeps new)
+        updateSet
+            ConfigCacheComponent
+            ConfigCacheComponentParent
+            parentId
+            ConfigCacheComponentValue
+            (maybe Set.empty configCacheComponents mold)
+            (configCacheComponents new)
+
+-- | Mark 'ConfigCache' as inactive in the database.
+-- We use a flag instead of deleting the records since, in most cases, the same
+-- cache will be written again within in a few seconds (after
+-- `cabal configure`), so this avoids unnecessary database churn.
+deactiveConfigCache :: HasBuildConfig env => ConfigCacheKey -> RIO env ()
+deactiveConfigCache (UniqueConfigCacheParent dir type_) =
+    withProjectStorage $
+    updateWhere
+        [ConfigCacheParentDirectory ==. dir, ConfigCacheParentType ==. type_]
+        [ConfigCacheParentActive =. False]
diff --git a/src/Stack/Storage/User.hs b/src/Stack/Storage/User.hs
new file mode 100644
--- /dev/null
+++ b/src/Stack/Storage/User.hs
@@ -0,0 +1,351 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# OPTIONS_GHC -Wno-unused-top-binds -Wno-identities #-}
+
+-- | Work with SQLite database used for caches across an entire user account.
+module Stack.Storage.User
+    ( initUserStorage
+    , PrecompiledCacheKey
+    , precompiledCacheKey
+    , loadPrecompiledCache
+    , savePrecompiledCache
+    , loadDockerImageExeCache
+    , saveDockerImageExeCache
+    , loadCompilerPaths
+    , saveCompilerPaths
+    , upgradeChecksSince
+    , logUpgradeCheck
+    ) where
+
+import qualified Data.Set as Set
+import qualified Data.Text as T
+import Data.Time.Clock (UTCTime)
+import Database.Persist.Sql (SqlBackend)
+import Database.Persist.Sqlite
+import Database.Persist.TH
+import Distribution.Text (simpleParse, display)
+import Foreign.C.Types (CTime (..))
+import qualified Pantry.Internal as SQLite
+import Path
+import Path.IO (resolveFile', resolveDir')
+import qualified RIO.FilePath as FP
+import Stack.Prelude hiding (MigrationFailure)
+import Stack.Storage.Util
+import Stack.Types.Build
+import Stack.Types.Cache
+import Stack.Types.Compiler
+import Stack.Types.CompilerBuild (CompilerBuild)
+import Stack.Types.Config (HasConfig, configL, configUserStorage, CompilerPaths (..), GhcPkgExe (..), UserStorage (..))
+import System.Posix.Types (COff (..))
+import System.PosixCompat.Files (getFileStatus, fileSize, modificationTime)
+
+share [ mkPersist sqlSettings
+      , mkDeleteCascade sqlSettings
+      , mkMigrate "migrateAll"
+    ]
+    [persistLowerCase|
+PrecompiledCacheParent sql="precompiled_cache"
+  platformGhcDir FilePath "default=(hex(randomblob(16)))"
+  compiler Text
+  cabalVersion Text
+  packageKey Text
+  optionsHash ByteString
+  haddock Bool default=0
+  library FilePath Maybe
+  UniquePrecompiledCacheParent platformGhcDir compiler cabalVersion packageKey optionsHash haddock sql="unique_precompiled_cache"
+  deriving Show
+
+PrecompiledCacheSubLib
+  parent PrecompiledCacheParentId sql="precompiled_cache_id"
+  value FilePath sql="sub_lib"
+  UniquePrecompiledCacheSubLib parent value
+  deriving Show
+
+PrecompiledCacheExe
+  parent PrecompiledCacheParentId sql="precompiled_cache_id"
+  value FilePath sql="exe"
+  UniquePrecompiledCacheExe parent value
+  deriving Show
+
+DockerImageExeCache
+  imageHash Text
+  exePath FilePath
+  exeTimestamp UTCTime
+  compatible Bool
+  DockerImageExeCacheUnique imageHash exePath exeTimestamp
+  deriving Show
+
+CompilerCache
+  actualVersion ActualCompiler
+  arch Text
+
+  -- Include ghc executable size and modified time for sanity checking entries
+  ghcPath FilePath
+  ghcSize Int64
+  ghcModified Int64
+
+  ghcPkgPath FilePath
+  runghcPath FilePath
+  haddockPath FilePath
+
+  cabalVersion Text
+  globalDb FilePath
+  globalDbCacheSize Int64
+  globalDbCacheModified Int64
+  info ByteString
+
+  -- This is the ugliest part of this table, simply storing a Show/Read version of the
+  -- data. We could do a better job with normalized data and proper table structure.
+  -- However, recomputing this value in the future if the data representation changes
+  -- is very cheap, so we'll take the easy way out for now.
+  globalDump Text
+
+  UniqueCompilerInfo ghcPath
+
+-- Last time certain actions were performed
+LastPerformed
+  action Action
+  timestamp UTCTime
+  UniqueAction action
+|]
+
+-- | Initialize the database.
+initUserStorage ::
+       HasLogFunc env
+    => Path Abs File -- ^ storage file
+    -> (UserStorage -> RIO env a)
+    -> RIO env a
+initUserStorage fp f = SQLite.initStorage "Stack" migrateAll fp $ f . UserStorage
+
+-- | Run an action in a database transaction
+withUserStorage ::
+       (HasConfig env, HasLogFunc env)
+    => ReaderT SqlBackend (RIO env) a
+    -> RIO env a
+withUserStorage inner =
+    flip SQLite.withStorage_ inner =<< view (configL . to configUserStorage . to unUserStorage)
+
+-- | Key used to retrieve the precompiled cache
+type PrecompiledCacheKey = Unique PrecompiledCacheParent
+
+-- | Build key used to retrieve the precompiled cache
+precompiledCacheKey ::
+       Path Rel Dir
+    -> ActualCompiler
+    -> Version
+    -> Text
+    -> ByteString
+    -> Bool
+    -> PrecompiledCacheKey
+precompiledCacheKey platformGhcDir compiler cabalVersion =
+    UniquePrecompiledCacheParent
+        (toFilePath platformGhcDir)
+        (compilerVersionText compiler)
+        (T.pack $ versionString cabalVersion)
+
+-- | Internal helper to read the 'PrecompiledCache' from the database
+readPrecompiledCache ::
+       (HasConfig env, HasLogFunc env)
+    => PrecompiledCacheKey
+    -> ReaderT SqlBackend (RIO env) (Maybe ( PrecompiledCacheParentId
+                                           , PrecompiledCache Rel))
+readPrecompiledCache key = do
+    mparent <- getBy key
+    forM mparent $ \(Entity parentId PrecompiledCacheParent {..}) -> do
+        pcLibrary <- mapM parseRelFile precompiledCacheParentLibrary
+        pcSubLibs <-
+            mapM (parseRelFile . precompiledCacheSubLibValue . entityVal) =<<
+            selectList [PrecompiledCacheSubLibParent ==. parentId] []
+        pcExes <-
+            mapM (parseRelFile . precompiledCacheExeValue . entityVal) =<<
+            selectList [PrecompiledCacheExeParent ==. parentId] []
+        return (parentId, PrecompiledCache {..})
+
+-- | Load 'PrecompiledCache' from the database.
+loadPrecompiledCache ::
+       (HasConfig env, HasLogFunc env)
+    => PrecompiledCacheKey
+    -> RIO env (Maybe (PrecompiledCache Rel))
+loadPrecompiledCache key = withUserStorage $ fmap snd <$> readPrecompiledCache key
+
+-- | Insert or update 'PrecompiledCache' to the database.
+savePrecompiledCache ::
+       (HasConfig env, HasLogFunc env)
+    => PrecompiledCacheKey
+    -> PrecompiledCache Rel
+    -> RIO env ()
+savePrecompiledCache key@(UniquePrecompiledCacheParent precompiledCacheParentPlatformGhcDir precompiledCacheParentCompiler precompiledCacheParentCabalVersion precompiledCacheParentPackageKey precompiledCacheParentOptionsHash precompiledCacheParentHaddock) new =
+    withUserStorage $ do
+        let precompiledCacheParentLibrary = fmap toFilePath (pcLibrary new)
+        mIdOld <- readPrecompiledCache key
+        (parentId, mold) <-
+            case mIdOld of
+                Nothing -> (, Nothing) <$> insert PrecompiledCacheParent {..}
+                Just (parentId, old) -> do
+                    update
+                        parentId
+                        [ PrecompiledCacheParentLibrary =.
+                          precompiledCacheParentLibrary
+                        ]
+                    return (parentId, Just old)
+        updateSet
+            PrecompiledCacheSubLib
+            PrecompiledCacheSubLibParent
+            parentId
+            PrecompiledCacheSubLibValue
+            (maybe Set.empty (toFilePathSet . pcSubLibs) mold)
+            (toFilePathSet $ pcSubLibs new)
+        updateSet
+            PrecompiledCacheExe
+            PrecompiledCacheExeParent
+            parentId
+            PrecompiledCacheExeValue
+            (maybe Set.empty (toFilePathSet . pcExes) mold)
+            (toFilePathSet $ pcExes new)
+  where
+    toFilePathSet = Set.fromList . map toFilePath
+
+-- | Get the record of whether an executable is compatible with a Docker image
+loadDockerImageExeCache ::
+       (HasConfig env, HasLogFunc env)
+    => Text
+    -> Path Abs File
+    -> UTCTime
+    -> RIO env (Maybe Bool)
+loadDockerImageExeCache imageId exePath exeTimestamp =
+    withUserStorage $
+    fmap (dockerImageExeCacheCompatible . entityVal) <$>
+    getBy (DockerImageExeCacheUnique imageId (toFilePath exePath) exeTimestamp)
+
+-- | Sest the record of whether an executable is compatible with a Docker image
+saveDockerImageExeCache ::
+       (HasConfig env, HasLogFunc env)
+    => Text
+    -> Path Abs File
+    -> UTCTime
+    -> Bool
+    -> RIO env ()
+saveDockerImageExeCache imageId exePath exeTimestamp compatible =
+    void $
+    withUserStorage $
+    upsert
+        (DockerImageExeCache
+             imageId
+             (toFilePath exePath)
+             exeTimestamp
+             compatible)
+        []
+
+-- | Type-restricted version of 'fromIntegral' to ensure we're making
+-- the value bigger, not smaller.
+sizeToInt64 :: COff -> Int64
+sizeToInt64 (COff i) = fromIntegral i -- fromIntegral added for 32-bit systems
+
+-- | Type-restricted version of 'fromIntegral' to ensure we're making
+-- the value bigger, not smaller.
+timeToInt64 :: CTime -> Int64
+timeToInt64 (CTime i) = fromIntegral i -- fromIntegral added for 32-bit systems
+
+-- | Load compiler information, if available, and confirm that the
+-- referenced files are unchanged. May throw exceptions!
+loadCompilerPaths
+  :: HasConfig env
+  => Path Abs File -- ^ compiler executable
+  -> CompilerBuild
+  -> Bool -- ^ sandboxed?
+  -> RIO env (Maybe CompilerPaths)
+loadCompilerPaths compiler build sandboxed = do
+  mres <- withUserStorage $ getBy $ UniqueCompilerInfo $ toFilePath compiler
+  for mres $ \(Entity _ CompilerCache {..}) -> do
+    compilerStatus <- liftIO $ getFileStatus $ toFilePath compiler
+    when
+      (compilerCacheGhcSize /= sizeToInt64 (fileSize compilerStatus) ||
+       compilerCacheGhcModified /= timeToInt64 (modificationTime compilerStatus))
+      (throwString "Compiler file metadata mismatch, ignoring cache")
+    globalDbStatus <- liftIO $ getFileStatus $ compilerCacheGlobalDb FP.</> "package.cache"
+    when
+      (compilerCacheGlobalDbCacheSize /= sizeToInt64 (fileSize globalDbStatus) ||
+       compilerCacheGlobalDbCacheModified /= timeToInt64 (modificationTime globalDbStatus))
+      (throwString "Global package cache file metadata mismatch, ignoring cache")
+
+    -- We could use parseAbsFile instead of resolveFile' below to
+    -- bypass some system calls, at the cost of some really wonky
+    -- error messages in case someone screws up their GHC installation
+    pkgexe <- resolveFile' compilerCacheGhcPkgPath
+    runghc <- resolveFile' compilerCacheRunghcPath
+    haddock <- resolveFile' compilerCacheHaddockPath
+    globaldb <- resolveDir' compilerCacheGlobalDb
+
+    cabalVersion <- parseVersionThrowing $ T.unpack compilerCacheCabalVersion
+    globalDump <-
+      case readMaybe $ T.unpack compilerCacheGlobalDump of
+        Nothing -> throwString "Global dump did not parse correctly"
+        Just globalDump -> pure globalDump
+    arch <-
+      case simpleParse $ T.unpack compilerCacheArch of
+        Nothing -> throwString $ "Invalid arch: " ++ show compilerCacheArch
+        Just arch -> pure arch
+
+    pure CompilerPaths
+      { cpCompiler = compiler
+      , cpCompilerVersion = compilerCacheActualVersion
+      , cpArch = arch
+      , cpBuild = build
+      , cpPkg = GhcPkgExe pkgexe
+      , cpInterpreter = runghc
+      , cpHaddock = haddock
+      , cpSandboxed = sandboxed
+      , cpCabalVersion = cabalVersion
+      , cpGlobalDB = globaldb
+      , cpGhcInfo = compilerCacheInfo
+      , cpGlobalDump = globalDump
+      }
+
+-- | Save compiler information. May throw exceptions!
+saveCompilerPaths
+  :: HasConfig env
+  => CompilerPaths
+  -> RIO env ()
+saveCompilerPaths CompilerPaths {..} = withUserStorage $ do
+  deleteBy $ UniqueCompilerInfo $ toFilePath cpCompiler
+  compilerStatus <- liftIO $ getFileStatus $ toFilePath cpCompiler
+  globalDbStatus <- liftIO $ getFileStatus $ toFilePath $ cpGlobalDB </> $(mkRelFile "package.cache")
+  let GhcPkgExe pkgexe = cpPkg
+  insert_ CompilerCache
+    { compilerCacheActualVersion = cpCompilerVersion
+    , compilerCacheGhcPath = toFilePath cpCompiler
+    , compilerCacheGhcSize = sizeToInt64 $ fileSize compilerStatus
+    , compilerCacheGhcModified = timeToInt64 $ modificationTime compilerStatus
+    , compilerCacheGhcPkgPath = toFilePath pkgexe
+    , compilerCacheRunghcPath = toFilePath cpInterpreter
+    , compilerCacheHaddockPath = toFilePath cpHaddock
+    , compilerCacheCabalVersion = T.pack $ versionString cpCabalVersion
+    , compilerCacheGlobalDb = toFilePath cpGlobalDB
+    , compilerCacheGlobalDbCacheSize = sizeToInt64 $ fileSize globalDbStatus
+    , compilerCacheGlobalDbCacheModified = timeToInt64 $ modificationTime globalDbStatus
+    , compilerCacheInfo = cpGhcInfo
+    , compilerCacheGlobalDump = tshow cpGlobalDump
+    , compilerCacheArch = T.pack $ Distribution.Text.display cpArch
+    }
+
+-- | How many upgrade checks have occurred since the given timestamp?
+upgradeChecksSince :: HasConfig env => UTCTime -> RIO env Int
+upgradeChecksSince since = withUserStorage $ count
+  [ LastPerformedAction ==. UpgradeCheck
+  , LastPerformedTimestamp >=. since
+  ]
+
+-- | Log in the database that an upgrade check occurred at the given time.
+logUpgradeCheck :: HasConfig env => UTCTime -> RIO env ()
+logUpgradeCheck time = withUserStorage $ void $ upsert
+  (LastPerformed UpgradeCheck time)
+  [LastPerformedTimestamp =. time]
diff --git a/src/Stack/Storage/Util.hs b/src/Stack/Storage/Util.hs
new file mode 100644
--- /dev/null
+++ b/src/Stack/Storage/Util.hs
@@ -0,0 +1,69 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE TypeFamilies #-}
+-- | Utils for the other Stack.Storage modules
+module Stack.Storage.Util
+    ( updateList
+    , updateSet
+    ) where
+
+import qualified Data.Set as Set
+import Database.Persist
+import Stack.Prelude hiding (MigrationFailure)
+
+-- | Efficiently update a set of values stored in a database table
+updateSet ::
+       ( PersistEntityBackend record ~ BaseBackend backend
+       , PersistField parentid
+       , PersistField value
+       , Ord value
+       , PersistEntity record
+       , MonadIO m
+       , PersistQueryWrite backend
+       )
+    => (parentid -> value -> record)
+    -> EntityField record parentid
+    -> parentid
+    -> EntityField record value
+    -> Set value
+    -> Set value
+    -> ReaderT backend m ()
+updateSet recordCons parentFieldCons parentId valueFieldCons old new =
+    when (old /= new) $ do
+        deleteWhere
+            [ parentFieldCons ==. parentId
+            , valueFieldCons <-. Set.toList (Set.difference old new)
+            ]
+        insertMany_ $
+            map (recordCons parentId) $ Set.toList (Set.difference new old)
+
+-- | Efficiently update a list of values stored in a database table.
+updateList ::
+       ( PersistEntityBackend record ~ BaseBackend backend
+       , PersistField parentid
+       , Ord value
+       , PersistEntity record
+       , MonadIO m
+       , PersistQueryWrite backend
+       )
+    => (parentid -> Int -> value -> record)
+    -> EntityField record parentid
+    -> parentid
+    -> EntityField record Int
+    -> [value]
+    -> [value]
+    -> ReaderT backend m ()
+updateList recordCons parentFieldCons parentId indexFieldCons old new =
+    when (old /= new) $ do
+        let oldSet = Set.fromList (zip [0 ..] old)
+            newSet = Set.fromList (zip [0 ..] new)
+        deleteWhere
+            [ parentFieldCons ==. parentId
+            , indexFieldCons <-.
+              map fst (Set.toList $ Set.difference oldSet newSet)
+            ]
+        insertMany_ $
+            map (uncurry $ recordCons parentId) $
+            Set.toList (Set.difference newSet oldSet)
diff --git a/src/Stack/Types/Config.hs b/src/Stack/Types/Config.hs
--- a/src/Stack/Types/Config.hs
+++ b/src/Stack/Types/Config.hs
@@ -46,6 +46,9 @@
   ,stackYamlL
   ,projectRootL
   ,HasBuildConfig(..)
+  -- ** Storage databases
+  ,UserStorage(..)
+  ,ProjectStorage(..)
   -- ** GHCVariant & HasGHCVariant
   ,GHCVariant(..)
   ,ghcVariantName
@@ -365,14 +368,24 @@
          ,configStackRoot           :: !(Path Abs Dir)
          ,configResolver            :: !(Maybe AbstractResolver)
          -- ^ Any resolver override from the command line
-         ,configStorage             :: !Storage
-         -- ^ Database connection pool for Stack database
+         ,configUserStorage         :: !UserStorage
+         -- ^ Database connection pool for user Stack database
          ,configHideSourcePaths     :: !Bool
          -- ^ Enable GHC hiding source paths?
          ,configRecommendUpgrade    :: !Bool
          -- ^ Recommend a Stack upgrade?
          }
 
+-- | A bit of type safety to ensure we're talking to the right database.
+newtype UserStorage = UserStorage
+  { unUserStorage :: Storage
+  }
+
+-- | A bit of type safety to ensure we're talking to the right database.
+newtype ProjectStorage = ProjectStorage
+  { unProjectStorage :: Storage
+  }
+
 -- | The project root directory, if in a project.
 configProjectRoot :: Config -> Maybe (Path Abs Dir)
 configProjectRoot c =
@@ -611,6 +624,8 @@
       -- Note: if the STACK_YAML environment variable is used, this may be
       -- different from projectRootL </> "stack.yaml" if a different file
       -- name is used.
+    , bcProjectStorage :: !ProjectStorage
+    -- ^ Database connection pool for project Stack database
     , bcCurator :: !(Maybe Curator)
     }
 
@@ -1750,14 +1765,10 @@
 explicitSetupDeps name = do
     m <- view $ configL.to configExplicitSetupDeps
     return $
-        -- Yes there are far cleverer ways to write this. I honestly consider
-        -- the explicit pattern matching much easier to parse at a glance.
-        case Map.lookup (Just name) m of
-            Just b -> b
-            Nothing ->
-                case Map.lookup Nothing m of
-                    Just b -> b
-                    Nothing -> False -- default value
+      Map.findWithDefault
+        (Map.findWithDefault False Nothing m)
+        (Just name)
+        m
 
 -- | Data passed into Docker container for the Docker entrypoint's use
 newtype DockerEntrypoint = DockerEntrypoint
diff --git a/src/test/Stack/ConfigSpec.hs b/src/test/Stack/ConfigSpec.hs
--- a/src/test/Stack/ConfigSpec.hs
+++ b/src/test/Stack/ConfigSpec.hs
@@ -191,7 +191,7 @@
       createDirectory childDir
       setCurrentDirectory childDir
       loadConfig' $ \config -> liftIO $ do
-        bc <- runRIO config loadBuildConfig
+        bc <- runRIO config $ withBuildConfig ask
         view projectRootL bc `shouldBe` parentDir
 
     it "respects the STACK_YAML env variable" $ inTempDir $ do
@@ -200,7 +200,7 @@
         writeFile stackYamlFp sampleConfig
         writeFile (toFilePath dir ++ "/package.yaml") "name: foo"
         withEnvVar "STACK_YAML" stackYamlFp $ loadConfig' $ \config -> liftIO $ do
-          BuildConfig{..} <- runRIO config loadBuildConfig
+          BuildConfig{..} <- runRIO config $ withBuildConfig ask
           bcStackYaml `shouldBe` dir </> stackDotYaml
           parent bcStackYaml `shouldBe` dir
 
@@ -214,7 +214,7 @@
         writeFile (toFilePath yamlAbs) "resolver: ghc-7.8"
         writeFile (toFilePath packageYaml) "name: foo"
         withEnvVar "STACK_YAML" (toFilePath yamlRel) $ loadConfig' $ \config -> liftIO $ do
-            BuildConfig{..} <- runRIO config loadBuildConfig
+            BuildConfig{..} <- runRIO config $ withBuildConfig ask
             bcStackYaml `shouldBe` yamlAbs
 
   describe "defaultConfigYaml" $
diff --git a/stack.cabal b/stack.cabal
--- a/stack.cabal
+++ b/stack.cabal
@@ -1,681 +1,688 @@
 cabal-version: 2.0
-
--- This file has been generated from package.yaml by hpack version 0.31.2.
---
--- see: https://github.com/sol/hpack
---
--- hash: b9d0860d1a25f89644f763eb2ea51d189b05684934421cbda622bea1b3addeb9
-
-name:           stack
-version:        2.1.1.1
-synopsis:       The Haskell Tool Stack
-description:    Please see the documentation at <https://docs.haskellstack.org>
-                for usage information.
-                .
-                If building a 'stack' executable for distribution, please download the
-                source code from <https://github.com/commercialhaskell/stack/releases>
-                and build it using Stack itself in order to ensure identical behaviour
-                to official binaries.  This package on Hackage is provided for convenience
-                and bootstrapping purposes.
-                .
-                Note that the API for the library is not currently stable, and may
-                change significantly, even between minor releases. It is
-                currently only intended for use by the executable.
-category:       Development
-homepage:       http://haskellstack.org
-bug-reports:    https://github.com/commercialhaskell/stack/issues
-author:         Commercial Haskell SIG
-maintainer:     manny@fpcomplete.com
-license:        BSD3
-license-file:   LICENSE
-build-type:     Custom
-extra-source-files:
-    CONTRIBUTING.md
-    ChangeLog.md
-    README.md
-    doc/azure_ci.md
-    doc/build_command.md
-    doc/build_overview.md
-    doc/ChangeLog.md
-    doc/CONTRIBUTING.md
-    doc/coverage.md
-    doc/custom_snapshot.md
-    doc/dependency_visualization.md
-    doc/developing_on_windows.md
-    doc/docker_integration.md
-    doc/faq.md
-    doc/ghci.md
-    doc/ghcjs.md
-    doc/GUIDE.md
-    doc/install_and_upgrade.md
-    doc/lock_files.md
-    doc/nix_integration.md
-    doc/nonstandard_project_init.md
-    doc/pantry.md
-    doc/README.md
-    doc/shell_autocompletion.md
-    doc/SIGNING_KEY.md
-    doc/stack_yaml_vs_cabal_package_file.md
-    doc/travis_ci.md
-    doc/yaml_configuration.md
-    src/setup-shim/StackSetupShim.hs
-    test/package-dump/ghc-7.10.txt
-    test/package-dump/ghc-7.8.4-osx.txt
-    test/package-dump/ghc-7.8.txt
-    test/package-dump/ghc-head.txt
-    src/test/Stack/Untar/test1.tar.gz
-    src/test/Stack/Untar/test2.tar.gz
-
-source-repository head
-  type: git
-  location: https://github.com/commercialhaskell/stack
-
-custom-setup
-  setup-depends:
-      Cabal
-    , base >=4.10 && <5
-    , filepath
-
-flag disable-git-info
-  description: Disable compile-time inclusion of current git info in stack
-  manual: True
-  default: False
-
-flag hide-dependency-versions
-  description: Hides dependency versions from "stack --version", used only by building with stack.yaml
-  manual: True
-  default: False
-
-flag integration-tests
-  description: Run the integration test suite
-  manual: True
-  default: False
-
-flag static
-  description: Pass -static/-pthread to ghc when linking the stack binary.
-  manual: True
-  default: False
-
-flag supported-build
-  description: If false, causes "stack --version" to issue a warning about the build being unsupported.  True only if building with stack.yaml
-  manual: True
-  default: False
-
-library
-  exposed-modules:
-      Control.Concurrent.Execute
-      Data.Attoparsec.Args
-      Data.Attoparsec.Combinators
-      Data.Attoparsec.Interpreter
-      Data.Monoid.Map
-      Network.HTTP.StackClient
-      Options.Applicative.Args
-      Options.Applicative.Builder.Extra
-      Options.Applicative.Complicated
-      Path.CheckInstall
-      Path.Extra
-      Path.Find
-      Stack.Build
-      Stack.Build.Cache
-      Stack.Build.ConstructPlan
-      Stack.Build.Execute
-      Stack.Build.Haddock
-      Stack.Build.Installed
-      Stack.Build.Source
-      Stack.Build.Target
-      Stack.BuildPlan
-      Stack.Clean
-      Stack.Config
-      Stack.Config.Build
-      Stack.Config.Docker
-      Stack.Config.Nix
-      Stack.ConfigCmd
-      Stack.Constants
-      Stack.Constants.Config
-      Stack.Coverage
-      Stack.DefaultColorWhen
-      Stack.Docker
-      Stack.Dot
-      Stack.FileWatch
-      Stack.Freeze
-      Stack.GhcPkg
-      Stack.Ghci
-      Stack.Ghci.Script
-      Stack.Hoogle
-      Stack.IDE
-      Stack.Init
-      Stack.Ls
-      Stack.Lock
-      Stack.New
-      Stack.Nix
-      Stack.Options.BenchParser
-      Stack.Options.BuildMonoidParser
-      Stack.Options.BuildParser
-      Stack.Options.CleanParser
-      Stack.Options.ConfigParser
-      Stack.Options.Completion
-      Stack.Options.DockerParser
-      Stack.Options.DotParser
-      Stack.Options.ExecParser
-      Stack.Options.FreezeParser
-      Stack.Options.GhcBuildParser
-      Stack.Options.GhciParser
-      Stack.Options.GhcVariantParser
-      Stack.Options.GlobalParser
-      Stack.Options.HaddockParser
-      Stack.Options.HpcReportParser
-      Stack.Options.LogLevelParser
-      Stack.Options.NewParser
-      Stack.Options.NixParser
-      Stack.Options.PackageParser
-      Stack.Options.ResolverParser
-      Stack.Options.ScriptParser
-      Stack.Options.SDistParser
-      Stack.Options.TestParser
-      Stack.Options.Utils
-      Stack.Package
-      Stack.PackageDump
-      Stack.Path
-      Stack.Prelude
-      Stack.Runners
-      Stack.Script
-      Stack.SDist
-      Stack.Setup
-      Stack.Setup.Installed
-      Stack.SetupCmd
-      Stack.SourceMap
-      Stack.Storage
-      Stack.Types.Build
-      Stack.Types.CompilerBuild
-      Stack.Types.Compiler
-      Stack.Types.Config
-      Stack.Types.Config.Build
-      Stack.Types.Docker
-      Stack.Types.GhcPkgId
-      Stack.Types.NamedComponent
-      Stack.Types.Nix
-      Stack.Types.Package
-      Stack.Types.PackageName
-      Stack.Types.Resolver
-      Stack.Types.SourceMap
-      Stack.Types.TemplateName
-      Stack.Types.Version
-      Stack.Types.VersionIntervals
-      Stack.Unpack
-      Stack.Upgrade
-      Stack.Upload
-      System.Info.ShortPathName
-      System.Permissions
-      System.Process.Pager
-      System.Terminal
-      Paths_stack
-  other-modules:
-      Stack.Types.Cache
-  autogen-modules:
-      Paths_stack
-  hs-source-dirs:
-      src/
-  ghc-options: -Wall -fwarn-tabs -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -optP-Wno-nonportable-include-path -fwarn-identities
-  build-depends:
-      Cabal
-    , aeson
-    , annotated-wl-pprint
-    , ansi-terminal
-    , array
-    , async
-    , attoparsec
-    , base >=4.10 && <5
-    , base64-bytestring
-    , bytestring
-    , colour
-    , conduit
-    , conduit-extra
-    , containers
-    , cryptonite
-    , cryptonite-conduit
-    , deepseq
-    , directory
-    , echo
-    , exceptions
-    , extra
-    , file-embed
-    , filelock
-    , filepath
-    , fsnotify
-    , generic-deriving
-    , hackage-security
-    , hashable
-    , hi-file-parser
-    , hpack
-    , hpc
-    , http-client
-    , http-client-tls
-    , http-conduit
-    , http-download
-    , http-types
-    , memory
-    , microlens
-    , mintty
-    , mono-traversable
-    , mtl
-    , mustache
-    , neat-interpolation
-    , network-uri
-    , open-browser
-    , optparse-applicative
-    , pantry-tmp
-    , path
-    , path-io
-    , persistent
-    , persistent-sqlite
-    , persistent-template
-    , pretty
-    , primitive
-    , process
-    , project-template
-    , regex-applicative-text
-    , resource-pool
-    , resourcet
-    , retry
-    , rio
-    , rio-prettyprint
-    , semigroups
-    , split
-    , stm
-    , streaming-commons
-    , tar
-    , template-haskell
-    , temporary
-    , terminal-size
-    , text
-    , text-metrics
-    , th-reify-many
-    , time
-    , tls
-    , transformers
-    , typed-process
-    , unicode-transforms
-    , unix-compat
-    , unliftio
-    , unordered-containers
-    , vector
-    , yaml
-    , zip-archive
-    , zlib
-  if os(windows)
-    cpp-options: -DWINDOWS
-    build-depends:
-        Win32
-  else
-    build-tools:
-        hsc2hs
-    build-depends:
-        unix
-  if os(windows)
-    other-modules:
-        System.Uname
-    hs-source-dirs:
-        src/windows/
-  else
-    other-modules:
-        System.Uname
-    hs-source-dirs:
-        src/unix/
-    c-sources:
-        src/unix/cbits/uname.c
-  default-language: Haskell2010
-
-executable stack
-  main-is: Main.hs
-  other-modules:
-      BuildInfo
-      Build_stack
-      Paths_stack
-  autogen-modules:
-      Build_stack
-      Paths_stack
-  hs-source-dirs:
-      src/main
-  ghc-options: -Wall -fwarn-tabs -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -optP-Wno-nonportable-include-path -threaded -rtsopts
-  build-depends:
-      Cabal
-    , aeson
-    , annotated-wl-pprint
-    , ansi-terminal
-    , array
-    , async
-    , attoparsec
-    , base >=4.10 && <5
-    , base64-bytestring
-    , bytestring
-    , colour
-    , conduit
-    , conduit-extra
-    , containers
-    , cryptonite
-    , cryptonite-conduit
-    , deepseq
-    , directory
-    , echo
-    , exceptions
-    , extra
-    , file-embed
-    , filelock
-    , filepath
-    , fsnotify
-    , generic-deriving
-    , hackage-security
-    , hashable
-    , hi-file-parser
-    , hpack
-    , hpc
-    , http-client
-    , http-client-tls
-    , http-conduit
-    , http-download
-    , http-types
-    , memory
-    , microlens
-    , mintty
-    , mono-traversable
-    , mtl
-    , mustache
-    , neat-interpolation
-    , network-uri
-    , open-browser
-    , optparse-applicative
-    , pantry-tmp
-    , path
-    , path-io
-    , persistent
-    , persistent-sqlite
-    , persistent-template
-    , pretty
-    , primitive
-    , process
-    , project-template
-    , regex-applicative-text
-    , resource-pool
-    , resourcet
-    , retry
-    , rio
-    , rio-prettyprint
-    , semigroups
-    , split
-    , stack
-    , stm
-    , streaming-commons
-    , tar
-    , template-haskell
-    , temporary
-    , terminal-size
-    , text
-    , text-metrics
-    , th-reify-many
-    , time
-    , tls
-    , transformers
-    , typed-process
-    , unicode-transforms
-    , unix-compat
-    , unliftio
-    , unordered-containers
-    , vector
-    , yaml
-    , zip-archive
-    , zlib
-  if os(windows)
-    cpp-options: -DWINDOWS
-    build-depends:
-        Win32
-  else
-    build-tools:
-        hsc2hs
-    build-depends:
-        unix
-  if flag(static)
-    ld-options: -static -pthread
-  if !(flag(disable-git-info))
-    cpp-options: -DUSE_GIT_INFO
-    build-depends:
-        githash
-      , optparse-simple
-  if flag(hide-dependency-versions)
-    cpp-options: -DHIDE_DEP_VERSIONS
-  if flag(supported-build)
-    cpp-options: -DSUPPORTED_BUILD
-  default-language: Haskell2010
-
-executable stack-integration-test
-  main-is: IntegrationSpec.hs
-  other-modules:
-      StackTest
-      Paths_stack
-  hs-source-dirs:
-      test/integration
-      test/integration/lib
-  ghc-options: -Wall -fwarn-tabs -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -optP-Wno-nonportable-include-path -threaded -rtsopts -with-rtsopts=-N
-  build-depends:
-      Cabal
-    , aeson
-    , annotated-wl-pprint
-    , ansi-terminal
-    , array
-    , async
-    , attoparsec
-    , base >=4.10 && <5
-    , base64-bytestring
-    , bytestring
-    , colour
-    , conduit
-    , conduit-extra
-    , containers
-    , cryptonite
-    , cryptonite-conduit
-    , deepseq
-    , directory
-    , echo
-    , exceptions
-    , extra
-    , file-embed
-    , filelock
-    , filepath
-    , fsnotify
-    , generic-deriving
-    , hackage-security
-    , hashable
-    , hi-file-parser
-    , hpack
-    , hpc
-    , hspec
-    , http-client
-    , http-client-tls
-    , http-conduit
-    , http-download
-    , http-types
-    , memory
-    , microlens
-    , mintty
-    , mono-traversable
-    , mtl
-    , mustache
-    , neat-interpolation
-    , network-uri
-    , open-browser
-    , optparse-applicative
-    , optparse-generic
-    , pantry-tmp
-    , path
-    , path-io
-    , persistent
-    , persistent-sqlite
-    , persistent-template
-    , pretty
-    , primitive
-    , process
-    , project-template
-    , regex-applicative-text
-    , resource-pool
-    , resourcet
-    , retry
-    , rio
-    , rio-prettyprint
-    , semigroups
-    , split
-    , stm
-    , streaming-commons
-    , tar
-    , template-haskell
-    , temporary
-    , terminal-size
-    , text
-    , text-metrics
-    , th-reify-many
-    , time
-    , tls
-    , transformers
-    , typed-process
-    , unicode-transforms
-    , unix-compat
-    , unliftio
-    , unordered-containers
-    , vector
-    , yaml
-    , zip-archive
-    , zlib
-  if os(windows)
-    cpp-options: -DWINDOWS
-    build-depends:
-        Win32
-  else
-    build-tools:
-        hsc2hs
-    build-depends:
-        unix
-  if !(flag(integration-tests))
-    buildable: False
-  default-language: Haskell2010
-
-test-suite stack-test
-  type: exitcode-stdio-1.0
-  main-is: Spec.hs
-  other-modules:
-      Stack.ArgsSpec
-      Stack.Build.ExecuteSpec
-      Stack.Build.TargetSpec
-      Stack.Config.DockerSpec
-      Stack.ConfigSpec
-      Stack.DotSpec
-      Stack.Ghci.PortableFakePaths
-      Stack.Ghci.ScriptSpec
-      Stack.GhciSpec
-      Stack.LockSpec
-      Stack.NixSpec
-      Stack.PackageDumpSpec
-      Stack.Types.TemplateNameSpec
-      Stack.UploadSpec
-      Paths_stack
-  hs-source-dirs:
-      src/test
-  ghc-options: -Wall -fwarn-tabs -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -optP-Wno-nonportable-include-path -threaded
-  build-depends:
-      Cabal
-    , QuickCheck
-    , aeson
-    , annotated-wl-pprint
-    , ansi-terminal
-    , array
-    , async
-    , attoparsec
-    , base >=4.10 && <5
-    , base64-bytestring
-    , bytestring
-    , colour
-    , conduit
-    , conduit-extra
-    , containers
-    , cryptonite
-    , cryptonite-conduit
-    , deepseq
-    , directory
-    , echo
-    , exceptions
-    , extra
-    , file-embed
-    , filelock
-    , filepath
-    , fsnotify
-    , generic-deriving
-    , hackage-security
-    , hashable
-    , hi-file-parser
-    , hpack
-    , hpc
-    , hspec
-    , http-client
-    , http-client-tls
-    , http-conduit
-    , http-download
-    , http-types
-    , memory
-    , microlens
-    , mintty
-    , mono-traversable
-    , mtl
-    , mustache
-    , neat-interpolation
-    , network-uri
-    , open-browser
-    , optparse-applicative
-    , pantry-tmp
-    , path
-    , path-io
-    , persistent
-    , persistent-sqlite
-    , persistent-template
-    , pretty
-    , primitive
-    , process
-    , project-template
-    , raw-strings-qq
-    , regex-applicative-text
-    , resource-pool
-    , resourcet
-    , retry
-    , rio
-    , rio-prettyprint
-    , semigroups
-    , smallcheck
-    , split
-    , stack
-    , stm
-    , streaming-commons
-    , tar
-    , template-haskell
-    , temporary
-    , terminal-size
-    , text
-    , text-metrics
-    , th-reify-many
-    , time
-    , tls
-    , transformers
-    , typed-process
-    , unicode-transforms
-    , unix-compat
-    , unliftio
-    , unordered-containers
-    , vector
-    , yaml
-    , zip-archive
-    , zlib
-  if os(windows)
-    cpp-options: -DWINDOWS
-    build-depends:
-        Win32
-  else
-    build-tools:
-        hsc2hs
-    build-depends:
-        unix
-  default-language: Haskell2010
+name: stack
+version: 2.1.3
+license: BSD3
+license-file: LICENSE
+maintainer: manny@fpcomplete.com
+author: Commercial Haskell SIG
+homepage: http://haskellstack.org
+bug-reports: https://github.com/commercialhaskell/stack/issues
+synopsis: The Haskell Tool Stack
+description:
+    Please see the documentation at <https://docs.haskellstack.org>
+    for usage information.
+    .
+    If building a 'stack' executable for distribution, please download the
+    source code from <https://github.com/commercialhaskell/stack/releases>
+    and build it using Stack itself in order to ensure identical behaviour
+    to official binaries.  This package on Hackage is provided for convenience
+    and bootstrapping purposes.
+    .
+    Note that the API for the library is not currently stable, and may
+    change significantly, even between minor releases. It is
+    currently only intended for use by the executable.
+category: Development
+build-type: Custom
+extra-source-files:
+    CONTRIBUTING.md
+    ChangeLog.md
+    README.md
+    doc/azure_ci.md
+    doc/build_command.md
+    doc/build_overview.md
+    doc/ChangeLog.md
+    doc/CONTRIBUTING.md
+    doc/coverage.md
+    doc/custom_snapshot.md
+    doc/dependency_visualization.md
+    doc/developing_on_windows.md
+    doc/docker_integration.md
+    doc/faq.md
+    doc/ghci.md
+    doc/ghcjs.md
+    doc/GUIDE.md
+    doc/install_and_upgrade.md
+    doc/lock_files.md
+    doc/nix_integration.md
+    doc/nonstandard_project_init.md
+    doc/pantry.md
+    doc/README.md
+    doc/shell_autocompletion.md
+    doc/SIGNING_KEY.md
+    doc/stack_yaml_vs_cabal_package_file.md
+    doc/travis_ci.md
+    doc/yaml_configuration.md
+    src/setup-shim/StackSetupShim.hs
+    test/package-dump/ghc-7.10.txt
+    test/package-dump/ghc-7.8.4-osx.txt
+    test/package-dump/ghc-7.8.txt
+    test/package-dump/ghc-head.txt
+    src/test/Stack/Untar/test1.tar.gz
+    src/test/Stack/Untar/test2.tar.gz
+
+source-repository head
+    type: git
+    location: https://github.com/commercialhaskell/stack
+
+custom-setup
+    setup-depends: Cabal >=2.4.0.1,
+                   base >=4.10 && <5,
+                   filepath >=1.4.1.2
+
+flag disable-git-info
+    description:
+        Disable compile-time inclusion of current git info in stack
+    default: False
+    manual: True
+
+flag hide-dependency-versions
+    description:
+        Hides dependency versions from 'stack --version', used only by building Stack and the default 'stack.yaml'.  Note to packagers/distributors: DO NOT OVERRIDE THIS FLAG IF YOU ARE BUILDING 'stack' ANY OTHER WAY (e.g. using cabal or from Hackage), as it makes debugging support requests more difficult.
+    default: False
+    manual: True
+
+flag integration-tests
+    description:
+        Run the integration test suite
+    default: False
+    manual: True
+
+flag static
+    description:
+        Pass -static/-pthread to ghc when linking the stack binary.
+    default: False
+    manual: True
+
+flag supported-build
+    description:
+        If false, causes 'stack --version' to issue a warning about the build being unsupported.  Should be True only if building with Stack and the default 'stack.yaml'.  Note to packagers/distributors: DO NOT OVERRIDE THIS FLAG IF YOU ARE BUILDING 'stack' ANY OTHER WAY (e.g. using cabal or from Hackage), as it makes debugging support requests more difficult.
+    default: False
+    manual: True
+
+library
+    exposed-modules:
+        Control.Concurrent.Execute
+        Data.Attoparsec.Args
+        Data.Attoparsec.Combinators
+        Data.Attoparsec.Interpreter
+        Data.Monoid.Map
+        Network.HTTP.StackClient
+        Options.Applicative.Args
+        Options.Applicative.Builder.Extra
+        Options.Applicative.Complicated
+        Path.CheckInstall
+        Path.Extra
+        Path.Find
+        Stack.Build
+        Stack.Build.Cache
+        Stack.Build.ConstructPlan
+        Stack.Build.Execute
+        Stack.Build.Haddock
+        Stack.Build.Installed
+        Stack.Build.Source
+        Stack.Build.Target
+        Stack.BuildPlan
+        Stack.Clean
+        Stack.Config
+        Stack.Config.Build
+        Stack.Config.Docker
+        Stack.Config.Nix
+        Stack.ConfigCmd
+        Stack.Constants
+        Stack.Constants.Config
+        Stack.Coverage
+        Stack.DefaultColorWhen
+        Stack.Docker
+        Stack.Dot
+        Stack.FileWatch
+        Stack.Freeze
+        Stack.GhcPkg
+        Stack.Ghci
+        Stack.Ghci.Script
+        Stack.Hoogle
+        Stack.IDE
+        Stack.Init
+        Stack.Ls
+        Stack.Lock
+        Stack.New
+        Stack.Nix
+        Stack.Options.BenchParser
+        Stack.Options.BuildMonoidParser
+        Stack.Options.BuildParser
+        Stack.Options.CleanParser
+        Stack.Options.ConfigParser
+        Stack.Options.Completion
+        Stack.Options.DockerParser
+        Stack.Options.DotParser
+        Stack.Options.ExecParser
+        Stack.Options.FreezeParser
+        Stack.Options.GhcBuildParser
+        Stack.Options.GhciParser
+        Stack.Options.GhcVariantParser
+        Stack.Options.GlobalParser
+        Stack.Options.HaddockParser
+        Stack.Options.HpcReportParser
+        Stack.Options.LogLevelParser
+        Stack.Options.NewParser
+        Stack.Options.NixParser
+        Stack.Options.PackageParser
+        Stack.Options.ResolverParser
+        Stack.Options.ScriptParser
+        Stack.Options.SDistParser
+        Stack.Options.TestParser
+        Stack.Options.Utils
+        Stack.Package
+        Stack.PackageDump
+        Stack.Path
+        Stack.Prelude
+        Stack.Runners
+        Stack.Script
+        Stack.SDist
+        Stack.Setup
+        Stack.Setup.Installed
+        Stack.SetupCmd
+        Stack.SourceMap
+        Stack.Storage.Project
+        Stack.Storage.User
+        Stack.Storage.Util
+        Stack.Types.Build
+        Stack.Types.CompilerBuild
+        Stack.Types.Compiler
+        Stack.Types.Config
+        Stack.Types.Config.Build
+        Stack.Types.Docker
+        Stack.Types.GhcPkgId
+        Stack.Types.NamedComponent
+        Stack.Types.Nix
+        Stack.Types.Package
+        Stack.Types.PackageName
+        Stack.Types.Resolver
+        Stack.Types.SourceMap
+        Stack.Types.TemplateName
+        Stack.Types.Version
+        Stack.Types.VersionIntervals
+        Stack.Unpack
+        Stack.Upgrade
+        Stack.Upload
+        System.Info.ShortPathName
+        System.Permissions
+        System.Process.Pager
+        System.Terminal
+        Paths_stack
+    hs-source-dirs: src/
+    other-modules:
+        Stack.Types.Cache
+    autogen-modules:
+        Paths_stack
+    default-language: Haskell2010
+    ghc-options: -Wall -fwarn-tabs -fwarn-incomplete-uni-patterns
+                 -fwarn-incomplete-record-updates -optP-Wno-nonportable-include-path
+                 -fwarn-identities
+    build-depends:
+        Cabal >=2.4.0.1,
+        aeson >=1.2.4.0,
+        annotated-wl-pprint >=0.7.0,
+        ansi-terminal >=0.9,
+        array >=0.5.2.0,
+        async >=2.1.1.1,
+        attoparsec >=0.13.2.2,
+        base >=4.10 && <5,
+        base64-bytestring >=1.0.0.1,
+        bytestring >=0.10.8.2,
+        colour >=2.3.4,
+        conduit >=1.3.0.3,
+        conduit-extra >=1.3.0,
+        containers >=0.5.10.2,
+        cryptonite >=0.25,
+        cryptonite-conduit >=0.2.2,
+        deepseq >=1.4.3.0,
+        directory >=1.3.0.2,
+        echo >=0.1.3,
+        exceptions >=0.8.3,
+        extra >=1.6.9,
+        file-embed >=0.0.10.1,
+        filelock >=0.1.1.2,
+        filepath >=1.4.1.2,
+        fsnotify >=0.3.0.1,
+        generic-deriving >=1.12.2,
+        hackage-security >=0.5.3.0,
+        hashable >=1.2.7.0,
+        hi-file-parser >=0.1.0.0,
+        hpack >=0.31.2,
+        hpc >=0.6.0.3,
+        http-client >=0.5.13.1,
+        http-client-tls >=0.3.5.3,
+        http-conduit >=2.3.2,
+        http-download >=0.1.0.0,
+        http-types >=0.12.1,
+        memory >=0.14.16,
+        microlens >=0.4.8.3,
+        mintty >=0.1.2,
+        mono-traversable >=1.0.9.0,
+        mtl >=2.2.2,
+        mustache >=2.3.0,
+        neat-interpolation >=0.3.2.1,
+        network-uri >=2.6.1.0,
+        open-browser >=0.2.1.0,
+        optparse-applicative >=0.14.2.0,
+        pantry >=0.1.1.0,
+        path >=0.6.1,
+        path-io >=1.3.3,
+        persistent >=2.9.2,
+        persistent-sqlite >=2.9.3,
+        persistent-template >=2.5.4,
+        pretty >=1.1.3.3,
+        primitive >=0.6.4.0,
+        process >=1.6.3.0,
+        project-template >=0.2.0.1,
+        regex-applicative-text >=0.1.0.1,
+        resource-pool >=0.2.3.2,
+        resourcet >=1.2.1,
+        retry >=0.7.6.3,
+        rio >=0.1.10.0,
+        rio-prettyprint >=0.1.0.0,
+        semigroups >=0.18.5,
+        split >=0.2.3.3,
+        stm >=2.4.5.0,
+        streaming-commons >=0.1.19,
+        tar >=0.5.1.0,
+        template-haskell >=2.12.0.0,
+        temporary >=1.2.1.1,
+        terminal-size >=0.3.2.1,
+        text >=1.2.3.0,
+        text-metrics >=0.3.0,
+        th-reify-many >=0.1.8,
+        time >=1.8.0.2,
+        tls >=1.4.1,
+        transformers >=0.5.2.0,
+        typed-process >=0.2.6.0,
+        unicode-transforms >=0.3.4,
+        unix-compat >=0.5.0.1,
+        unliftio >=0.2.8.0,
+        unordered-containers >=0.2.9.0,
+        vector >=0.12.0.1,
+        yaml >=0.10.4.0,
+        zip-archive >=0.3.3,
+        zlib >=0.6.2
+    
+    if os(windows)
+        cpp-options: -DWINDOWS
+        build-depends:
+            Win32 -any
+    else
+        build-tools: hsc2hs -any
+        build-depends:
+            unix >=2.7.2.2
+    
+    if os(windows)
+        hs-source-dirs: src/windows/
+        other-modules:
+            System.Uname
+    else
+        c-sources:
+            src/unix/cbits/uname.c
+        hs-source-dirs: src/unix/
+        other-modules:
+            System.Uname
+
+executable stack
+    main-is: Main.hs
+    hs-source-dirs: src/main
+    other-modules:
+        BuildInfo
+        Build_stack
+        Paths_stack
+    autogen-modules:
+        Build_stack
+        Paths_stack
+    default-language: Haskell2010
+    ghc-options: -Wall -fwarn-tabs -fwarn-incomplete-uni-patterns
+                 -fwarn-incomplete-record-updates -optP-Wno-nonportable-include-path
+                 -threaded -rtsopts
+    build-depends:
+        Cabal >=2.4.0.1,
+        aeson >=1.2.4.0,
+        annotated-wl-pprint >=0.7.0,
+        ansi-terminal >=0.9,
+        array >=0.5.2.0,
+        async >=2.1.1.1,
+        attoparsec >=0.13.2.2,
+        base >=4.10 && <5,
+        base64-bytestring >=1.0.0.1,
+        bytestring >=0.10.8.2,
+        colour >=2.3.4,
+        conduit >=1.3.0.3,
+        conduit-extra >=1.3.0,
+        containers >=0.5.10.2,
+        cryptonite >=0.25,
+        cryptonite-conduit >=0.2.2,
+        deepseq >=1.4.3.0,
+        directory >=1.3.0.2,
+        echo >=0.1.3,
+        exceptions >=0.8.3,
+        extra >=1.6.9,
+        file-embed >=0.0.10.1,
+        filelock >=0.1.1.2,
+        filepath >=1.4.1.2,
+        fsnotify >=0.3.0.1,
+        generic-deriving >=1.12.2,
+        hackage-security >=0.5.3.0,
+        hashable >=1.2.7.0,
+        hi-file-parser >=0.1.0.0,
+        hpack >=0.31.2,
+        hpc >=0.6.0.3,
+        http-client >=0.5.13.1,
+        http-client-tls >=0.3.5.3,
+        http-conduit >=2.3.2,
+        http-download >=0.1.0.0,
+        http-types >=0.12.1,
+        memory >=0.14.16,
+        microlens >=0.4.8.3,
+        mintty >=0.1.2,
+        mono-traversable >=1.0.9.0,
+        mtl >=2.2.2,
+        mustache >=2.3.0,
+        neat-interpolation >=0.3.2.1,
+        network-uri >=2.6.1.0,
+        open-browser >=0.2.1.0,
+        optparse-applicative >=0.14.2.0,
+        pantry >=0.1.1.0,
+        path >=0.6.1,
+        path-io >=1.3.3,
+        persistent >=2.9.2,
+        persistent-sqlite >=2.9.3,
+        persistent-template >=2.5.4,
+        pretty >=1.1.3.3,
+        primitive >=0.6.4.0,
+        process >=1.6.3.0,
+        project-template >=0.2.0.1,
+        regex-applicative-text >=0.1.0.1,
+        resource-pool >=0.2.3.2,
+        resourcet >=1.2.1,
+        retry >=0.7.6.3,
+        rio >=0.1.10.0,
+        rio-prettyprint >=0.1.0.0,
+        semigroups >=0.18.5,
+        split >=0.2.3.3,
+        stack -any,
+        stm >=2.4.5.0,
+        streaming-commons >=0.1.19,
+        tar >=0.5.1.0,
+        template-haskell >=2.12.0.0,
+        temporary >=1.2.1.1,
+        terminal-size >=0.3.2.1,
+        text >=1.2.3.0,
+        text-metrics >=0.3.0,
+        th-reify-many >=0.1.8,
+        time >=1.8.0.2,
+        tls >=1.4.1,
+        transformers >=0.5.2.0,
+        typed-process >=0.2.6.0,
+        unicode-transforms >=0.3.4,
+        unix-compat >=0.5.0.1,
+        unliftio >=0.2.8.0,
+        unordered-containers >=0.2.9.0,
+        vector >=0.12.0.1,
+        yaml >=0.10.4.0,
+        zip-archive >=0.3.3,
+        zlib >=0.6.2
+    
+    if os(windows)
+        cpp-options: -DWINDOWS
+        build-depends:
+            Win32 -any
+    else
+        build-tools: hsc2hs -any
+        build-depends:
+            unix >=2.7.2.2
+    
+    if flag(static)
+        ld-options: -static -pthread
+    
+    if !flag(disable-git-info)
+        cpp-options: -DUSE_GIT_INFO
+        build-depends:
+            githash >=0.1.3.0,
+            optparse-simple >=0.1.0
+    
+    if flag(hide-dependency-versions)
+        cpp-options: -DHIDE_DEP_VERSIONS
+    
+    if flag(supported-build)
+        cpp-options: -DSUPPORTED_BUILD
+
+executable stack-integration-test
+    main-is: IntegrationSpec.hs
+    hs-source-dirs: test/integration test/integration/lib
+    other-modules:
+        StackTest
+        Paths_stack
+    default-language: Haskell2010
+    ghc-options: -Wall -fwarn-tabs -fwarn-incomplete-uni-patterns
+                 -fwarn-incomplete-record-updates -optP-Wno-nonportable-include-path
+                 -threaded -rtsopts -with-rtsopts=-N
+    build-depends:
+        Cabal >=2.4.0.1,
+        aeson >=1.2.4.0,
+        annotated-wl-pprint >=0.7.0,
+        ansi-terminal >=0.9,
+        array >=0.5.2.0,
+        async >=2.1.1.1,
+        attoparsec >=0.13.2.2,
+        base >=4.10 && <5,
+        base64-bytestring >=1.0.0.1,
+        bytestring >=0.10.8.2,
+        colour >=2.3.4,
+        conduit >=1.3.0.3,
+        conduit-extra >=1.3.0,
+        containers >=0.5.10.2,
+        cryptonite >=0.25,
+        cryptonite-conduit >=0.2.2,
+        deepseq >=1.4.3.0,
+        directory >=1.3.0.2,
+        echo >=0.1.3,
+        exceptions >=0.8.3,
+        extra >=1.6.9,
+        file-embed >=0.0.10.1,
+        filelock >=0.1.1.2,
+        filepath >=1.4.1.2,
+        fsnotify >=0.3.0.1,
+        generic-deriving >=1.12.2,
+        hackage-security >=0.5.3.0,
+        hashable >=1.2.7.0,
+        hi-file-parser >=0.1.0.0,
+        hpack >=0.31.2,
+        hpc >=0.6.0.3,
+        hspec >=2.4.8,
+        http-client >=0.5.13.1,
+        http-client-tls >=0.3.5.3,
+        http-conduit >=2.3.2,
+        http-download >=0.1.0.0,
+        http-types >=0.12.1,
+        memory >=0.14.16,
+        microlens >=0.4.8.3,
+        mintty >=0.1.2,
+        mono-traversable >=1.0.9.0,
+        mtl >=2.2.2,
+        mustache >=2.3.0,
+        neat-interpolation >=0.3.2.1,
+        network-uri >=2.6.1.0,
+        open-browser >=0.2.1.0,
+        optparse-applicative >=0.14.2.0,
+        optparse-generic >=1.3.0,
+        pantry >=0.1.1.0,
+        path >=0.6.1,
+        path-io >=1.3.3,
+        persistent >=2.9.2,
+        persistent-sqlite >=2.9.3,
+        persistent-template >=2.5.4,
+        pretty >=1.1.3.3,
+        primitive >=0.6.4.0,
+        process >=1.6.3.0,
+        project-template >=0.2.0.1,
+        regex-applicative-text >=0.1.0.1,
+        resource-pool >=0.2.3.2,
+        resourcet >=1.2.1,
+        retry >=0.7.6.3,
+        rio >=0.1.10.0,
+        rio-prettyprint >=0.1.0.0,
+        semigroups >=0.18.5,
+        split >=0.2.3.3,
+        stm >=2.4.5.0,
+        streaming-commons >=0.1.19,
+        tar >=0.5.1.0,
+        template-haskell >=2.12.0.0,
+        temporary >=1.2.1.1,
+        terminal-size >=0.3.2.1,
+        text >=1.2.3.0,
+        text-metrics >=0.3.0,
+        th-reify-many >=0.1.8,
+        time >=1.8.0.2,
+        tls >=1.4.1,
+        transformers >=0.5.2.0,
+        typed-process >=0.2.6.0,
+        unicode-transforms >=0.3.4,
+        unix-compat >=0.5.0.1,
+        unliftio >=0.2.8.0,
+        unordered-containers >=0.2.9.0,
+        vector >=0.12.0.1,
+        yaml >=0.10.4.0,
+        zip-archive >=0.3.3,
+        zlib >=0.6.2
+    
+    if os(windows)
+        cpp-options: -DWINDOWS
+        build-depends:
+            Win32 -any
+    else
+        build-tools: hsc2hs -any
+        build-depends:
+            unix >=2.7.2.2
+    
+    if !flag(integration-tests)
+        buildable: False
+
+test-suite stack-test
+    type: exitcode-stdio-1.0
+    main-is: Spec.hs
+    hs-source-dirs: src/test
+    other-modules:
+        Stack.ArgsSpec
+        Stack.Build.ExecuteSpec
+        Stack.Build.TargetSpec
+        Stack.Config.DockerSpec
+        Stack.ConfigSpec
+        Stack.DotSpec
+        Stack.Ghci.PortableFakePaths
+        Stack.Ghci.ScriptSpec
+        Stack.GhciSpec
+        Stack.LockSpec
+        Stack.NixSpec
+        Stack.PackageDumpSpec
+        Stack.Types.TemplateNameSpec
+        Stack.UploadSpec
+        Paths_stack
+    default-language: Haskell2010
+    ghc-options: -Wall -fwarn-tabs -fwarn-incomplete-uni-patterns
+                 -fwarn-incomplete-record-updates -optP-Wno-nonportable-include-path
+                 -threaded
+    build-depends:
+        Cabal >=2.4.0.1,
+        QuickCheck >=2.10.1,
+        aeson >=1.2.4.0,
+        annotated-wl-pprint >=0.7.0,
+        ansi-terminal >=0.9,
+        array >=0.5.2.0,
+        async >=2.1.1.1,
+        attoparsec >=0.13.2.2,
+        base >=4.10 && <5,
+        base64-bytestring >=1.0.0.1,
+        bytestring >=0.10.8.2,
+        colour >=2.3.4,
+        conduit >=1.3.0.3,
+        conduit-extra >=1.3.0,
+        containers >=0.5.10.2,
+        cryptonite >=0.25,
+        cryptonite-conduit >=0.2.2,
+        deepseq >=1.4.3.0,
+        directory >=1.3.0.2,
+        echo >=0.1.3,
+        exceptions >=0.8.3,
+        extra >=1.6.9,
+        file-embed >=0.0.10.1,
+        filelock >=0.1.1.2,
+        filepath >=1.4.1.2,
+        fsnotify >=0.3.0.1,
+        generic-deriving >=1.12.2,
+        hackage-security >=0.5.3.0,
+        hashable >=1.2.7.0,
+        hi-file-parser >=0.1.0.0,
+        hpack >=0.31.2,
+        hpc >=0.6.0.3,
+        hspec >=2.4.8,
+        http-client >=0.5.13.1,
+        http-client-tls >=0.3.5.3,
+        http-conduit >=2.3.2,
+        http-download >=0.1.0.0,
+        http-types >=0.12.1,
+        memory >=0.14.16,
+        microlens >=0.4.8.3,
+        mintty >=0.1.2,
+        mono-traversable >=1.0.9.0,
+        mtl >=2.2.2,
+        mustache >=2.3.0,
+        neat-interpolation >=0.3.2.1,
+        network-uri >=2.6.1.0,
+        open-browser >=0.2.1.0,
+        optparse-applicative >=0.14.2.0,
+        pantry >=0.1.1.0,
+        path >=0.6.1,
+        path-io >=1.3.3,
+        persistent >=2.9.2,
+        persistent-sqlite >=2.9.3,
+        persistent-template >=2.5.4,
+        pretty >=1.1.3.3,
+        primitive >=0.6.4.0,
+        process >=1.6.3.0,
+        project-template >=0.2.0.1,
+        raw-strings-qq >=1.1,
+        regex-applicative-text >=0.1.0.1,
+        resource-pool >=0.2.3.2,
+        resourcet >=1.2.1,
+        retry >=0.7.6.3,
+        rio >=0.1.10.0,
+        rio-prettyprint >=0.1.0.0,
+        semigroups >=0.18.5,
+        smallcheck >=1.1.5,
+        split >=0.2.3.3,
+        stack -any,
+        stm >=2.4.5.0,
+        streaming-commons >=0.1.19,
+        tar >=0.5.1.0,
+        template-haskell >=2.12.0.0,
+        temporary >=1.2.1.1,
+        terminal-size >=0.3.2.1,
+        text >=1.2.3.0,
+        text-metrics >=0.3.0,
+        th-reify-many >=0.1.8,
+        time >=1.8.0.2,
+        tls >=1.4.1,
+        transformers >=0.5.2.0,
+        typed-process >=0.2.6.0,
+        unicode-transforms >=0.3.4,
+        unix-compat >=0.5.0.1,
+        unliftio >=0.2.8.0,
+        unordered-containers >=0.2.9.0,
+        vector >=0.12.0.1,
+        yaml >=0.10.4.0,
+        zip-archive >=0.3.3,
+        zlib >=0.6.2
+    
+    if os(windows)
+        cpp-options: -DWINDOWS
+        build-depends:
+            Win32 -any
+    else
+        build-tools: hsc2hs -any
+        build-depends:
+            unix >=2.7.2.2
diff --git a/test/integration/lib/StackTest.hs b/test/integration/lib/StackTest.hs
--- a/test/integration/lib/StackTest.hs
+++ b/test/integration/lib/StackTest.hs
@@ -1,3 +1,5 @@
+{-#LANGUAGE ScopedTypeVariables#-}
+
 module StackTest where
 
 import Control.Monad
@@ -58,6 +60,18 @@
 stack args = do
     ec <- stack' args
     unless (ec == ExitSuccess) $ error $ "Exited with exit code: " ++ show ec
+
+-- Temporary workaround for Windows to ignore exceptions arising out
+-- of Windows when we do stack clean. More info here: https://github.com/commercialhaskell/stack/issues/4936
+stackCleanFull :: HasCallStack => IO ()
+stackCleanFull = stackIgnoreException ["clean", "--full"]
+
+-- Temporary workaround for Windows to ignore exceptions arising out
+-- of Windows when we do stack clean. More info here: https://github.com/commercialhaskell/stack/issues/4936
+stackIgnoreException :: HasCallStack => [String] -> IO ()
+stackIgnoreException args = if isWindows
+                            then void (stack' args) `catch` (\(_e :: IOException) -> return ())
+                            else stack args
 
 stackErr :: HasCallStack => [String] -> IO ()
 stackErr args = do
