diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 Changelog for tmp-postgres
 
+1.15.1.0
+  #119 Add `initdb` cache
+  #134 Expand tilde in Permanent DirectoryType setup.
+
 1.15.0.0
   #137 Remove SocketClass and listen unconditionally on 127.0.0.1, ::1 and a UNIX socket.
   #138 Fix bug where optionsToDefaultConfig would make createdb plan even if one is not needed.
diff --git a/benchmark/Main.hs b/benchmark/Main.hs
--- a/benchmark/Main.hs
+++ b/benchmark/Main.hs
@@ -4,7 +4,7 @@
 import Criterion.Main
 import Data.String
 import Database.Postgres.Temp.Internal
-import Database.Postgres.Temp.Config
+import Database.Postgres.Temp.Internal.Config
 import qualified Database.PostgreSQL.Simple as PG
 
 defaultConfigDefaultInitDb :: Config
@@ -38,16 +38,41 @@
   bracket (PG.connectPostgreSQL theConnectionString) PG.close $
     \conn -> void $ PG.execute_ conn "INSERT INTO foo1 (id) VALUES (1)"
 
+setupCache :: IO (Bool, CompleteDirectoryType)
+setupCache = do
+  defCacheConfig <- createDefaultCacheConfig
+  cacheInfo <- setupInitDbCache defCacheConfig
+  void (withConfig (silentConfig <> toCacheConfig cacheInfo) (const $ pure ()))
+  pure cacheInfo
+
+setupWithCache :: (Config -> Benchmark) -> Benchmark
+setupWithCache f = envWithCleanup setupCache cleanupInitDbCache $ f . (silentConfig <>) . toCacheConfig
+
 main :: IO ()
 main = defaultMain
   [ --bench "with" $ whnfIO $ with $ const $ pure ()
   --, bench "withConfig no --no-sync" $ whnfIO $
   --    withConfig defaultConfigDefaultInitDb $ const $ pure ()
   bench "withConfig silent" $ whnfIO $
-      withConfig silentConfig $ const $ pure ()
-  --  bench "with migrate 10x" $ whnfIO $ replicateM 10 $ withConfig silent $ \db ->
-  --    migrateDb db >> testQuery db
-  --, bench "withNewDb migrate 10x" $ whnfIO $ withConfig silent $ \db -> do
-  --    migrateDb db
-  --    replicateM 10 $ withNewDb db testQuery
+    withConfig silentConfig $ const $ pure ()
+
+  , setupWithCache $ \cacheConfig -> bench "withConfig silent cache" $ whnfIO $
+      withConfig cacheConfig $ const $ pure ()
+
+  , bench "with migrate 10x" $ whnfIO $ replicateM 10 $ withConfig silentConfig $ \db ->
+      migrateDb db >> testQuery db
+
+  , bench "withNewDb migrate 10x" $ whnfIO $ withConfig silentConfig $ \db -> do
+      migrateDb db
+      replicateM 10 $ withNewDb db testQuery
+
+  , setupWithCache $ \cacheConfig -> do
+      bench "with migrate 10x and cache" $ whnfIO $ withConfig cacheConfig $ \_ -> do
+        replicateM 10 $ withConfig cacheConfig $ \db ->
+          migrateDb db >> testQuery db
+
+  , setupWithCache $ \cacheConfig -> bench "withNewDbConfig migrate 10x and cache" $ whnfIO $ withConfig cacheConfig
+    $ \db -> do
+      migrateDb db
+      replicateM 10 $ withNewDb db testQuery
   ]
diff --git a/src/Database/Postgres/Temp.hs b/src/Database/Postgres/Temp.hs
--- a/src/Database/Postgres/Temp.hs
+++ b/src/Database/Postgres/Temp.hs
@@ -52,6 +52,8 @@
   , withRestart
   , withNewDb
   , withNewDbConfig
+  , withDbCacheConfig
+  , withDbCache
   -- * Separate start and stop interface.
   , start
   , startConfig
@@ -61,6 +63,8 @@
   , startNewDb
   , startNewDbConfig
   , stopNewDb
+  , setupInitDbCache
+  , cleanupInitDbCache
   -- * Main resource handle
   , DB
   -- ** 'DB' accessors
diff --git a/src/Database/Postgres/Temp/Internal.hs b/src/Database/Postgres/Temp/Internal.hs
--- a/src/Database/Postgres/Temp/Internal.hs
+++ b/src/Database/Postgres/Temp/Internal.hs
@@ -4,8 +4,10 @@
 identifiers that are used for testing but are not exported.
 -}
 module Database.Postgres.Temp.Internal where
+
 import Database.Postgres.Temp.Internal.Core
 import Database.Postgres.Temp.Internal.Config
+
 import           Control.Exception
 import           Control.Monad (void)
 import           Control.Monad.Trans.Cont
@@ -18,6 +20,7 @@
 import qualified Database.PostgreSQL.Simple.Options as Client
 import           System.Environment
 import           System.Exit (ExitCode(..))
+import           System.Process
 import           System.Random
 import           Text.PrettyPrint.ANSI.Leijen hiding ((<$>))
 
@@ -613,3 +616,116 @@
         { Client.dbname = pure "template1"
         }
   dropDbIfExists template1Options newDbName
+
+-------------------------------------------------------------------------------
+-- initdb cache
+-------------------------------------------------------------------------------
+-- | Configuration for the @initdb@ data directory cache.
+data CacheConfig = CacheConfig
+  { cacheTemporaryDirectory :: FilePath
+  -- ^ Root temporary directory used if 'cacheDirectoryType' is set to
+  -- 'Temporary'. @\/tmp@ is a good default.
+  , cacheDirectoryType      :: DirectoryType
+  -- ^ Used to specify is a 'Permanent' or 'Temporary' directory should be
+  --   used. 'createDefaultCacheConfig' uses 'Permanent' @~\/.tmp-postgres@
+  --   by default.
+  , cacheUseCopyOnWrite     :: Bool
+  -- ^ Some operatoring system versions support flags for @cp@ that allow
+  --   \"copy on write\" which is about 2x faster. 'createDefaultCacheConfig'
+  --   attempts to determine if the @cp@ on the path supports copy on write
+  --   and sets this to 'True' if it does.
+  }
+
+{-|
+'createDefaultCacheConfig' attempts to determine if the @cp@ on the path
+supports \"copy on write\" flags and if it does, sets 'cacheUseCopyOnWrite'
+to 'True'.
+
+It sets 'cacheDirectoryType' to 'Permanent' @~\/.tmp-postgres@ and
+'cacheTemporaryDirectory' to @\/tmp@ (but this is not used when
+'Permanent' is set).
+-}
+createDefaultCacheConfig :: IO CacheConfig
+createDefaultCacheConfig = do
+  let
+#ifdef darwin_HOST_OS
+    cpFlag = "-c"
+#else
+    cpFlag = "--reflink=auto"
+#endif
+  (_, _, errorOutput)<- readProcessWithExitCode "cp" [cpFlag] ""
+  -- if the flags do not exist we get a message like "cp: illegal option"
+  let usage = "usage:" -- macos
+      missingFile = "cp: missing file operand" -- linux
+      cacheUseCopyOnWrite = usage ==  take (length usage) errorOutput
+        || missingFile ==  take (length missingFile) errorOutput
+      cacheDirectoryType = Permanent "~/.tmp-postgres"
+      cacheTemporaryDirectory = "/tmp"
+  pure CacheConfig {..}
+
+-- | Setup the @initdb@ cache folder.
+setupInitDbCache
+  :: CacheConfig
+  -> IO (Bool, CompleteDirectoryType)
+setupInitDbCache CacheConfig {..} =
+  bracketOnError
+    (setupDirectoryType
+      cacheTemporaryDirectory
+      "tmp-postgres-cache"
+      cacheDirectoryType
+    )
+    cleanupDirectoryType $ pure . (cacheUseCopyOnWrite,)
+
+{-|
+Cleanup the cache directory if it was 'Temporary'.
+-}
+cleanupInitDbCache :: (Bool, CompleteDirectoryType) -> IO ()
+cleanupInitDbCache = cleanupDirectoryType . snd
+
+{-|
+Enable @initdb@ data directory caching. This can lead to a 4x speedup.
+
+Exception safe version of 'setupInitDbCache'. Equivalent to
+
+@
+   'withDbCacheConfig' = bracket_ ('setupInitDbCache' config) 'cleanupInitDbCache'
+@
+
+-}
+withDbCacheConfig
+  :: CacheConfig
+  -- ^ Configuration
+  -> ((Bool, CompleteDirectoryType) -> IO a)
+  -- ^ action for which caching is enabled
+  -> IO a
+withDbCacheConfig config =
+  bracket (setupInitDbCache config) cleanupInitDbCache
+
+{-|
+Equivalent to 'withDbCacheConfig' with the 'CacheConfig'
+'createDefaultCacheConfig' makes.
+-}
+withDbCache :: ((Bool, CompleteDirectoryType) -> IO a) -> IO a
+withDbCache action =
+  flip withDbCacheConfig action =<< createDefaultCacheConfig
+
+{-|
+Helper to make a 'Config' out of caching info.
+
+Equivalent to
+
+@
+  toCacheConfig cacheInfo = mempty
+    { plan = mempty
+        { initDbCache = pure $ Just $ fmap toFilePath cacheInfo
+        }
+    }
+@
+
+-}
+toCacheConfig :: (Bool, CompleteDirectoryType) -> Config
+toCacheConfig cacheInfo = mempty
+  { plan = mempty
+      { initDbCache = pure $ pure $ fmap toFilePath cacheInfo
+      }
+  }
diff --git a/src/Database/Postgres/Temp/Internal/Config.hs b/src/Database/Postgres/Temp/Internal/Config.hs
--- a/src/Database/Postgres/Temp/Internal/Config.hs
+++ b/src/Database/Postgres/Temp/Internal/Config.hs
@@ -17,6 +17,7 @@
 import Database.Postgres.Temp.Internal.Core
 
 import           Control.Applicative.Lift
+import           Control.DeepSeq
 import           Control.Exception
 import           Control.Monad (join)
 import           Control.Monad.Trans.Class
@@ -256,7 +257,8 @@
 --
 --   @since 1.12.0.0
 data CompleteDirectoryType = CPermanent FilePath | CTemporary FilePath
-  deriving(Show, Eq, Ord)
+  deriving stock (Show, Eq, Ord, Generic)
+  deriving anyclass (NFData)
 
 -- | Get the file path of a 'CompleteDirectoryType', regardless if it is a
 -- 'CPermanent' or 'CTemporary' type.
@@ -291,8 +293,8 @@
 
 instance Pretty DirectoryType where
   pretty = \case
-    Permanent x -> text "CPermanent" <+> pretty x
-    Temporary   -> text "CTemporary"
+    Permanent x -> text "Permanent" <+> pretty x
+    Temporary   -> text "Temporary"
 
 -- | Takes the last 'Permanent' value.
 instance Semigroup DirectoryType where
@@ -317,7 +319,11 @@
   -> IO CompleteDirectoryType
 setupDirectoryType tempDir pat = \case
   Temporary -> CTemporary <$> createTempDirectory tempDir pat
-  Permanent x  -> pure $ CPermanent x
+  Permanent x  -> CPermanent <$> case x of
+    '~':rest -> do
+      homeDir <- getHomeDirectory
+      pure $ homeDir <> "/" <> rest
+    xs -> pure xs
 
 -- Remove a temporary directory and ignore errors
 -- about it not being there.
@@ -390,6 +396,7 @@
   , connectionTimeout :: Last Int
   -- ^ Max time to spend attempting to connection to @postgres@.
   --   Time is in microseconds.
+  , initDbCache :: Last (Maybe (Bool, FilePath))
   }
   deriving stock (Generic)
   deriving Semigroup via GenericSemigroup Plan
@@ -416,6 +423,8 @@
     <> text "dataDirectoryString:" <+> pretty (getLast dataDirectoryString)
     <> hardline
     <> text "connectionTimeout:" <+> pretty (getLast connectionTimeout)
+    <> hardline
+    <> text "initDbCache:" <+> pretty (getLast initDbCache)
 
 -- | Turn a 'Plan' into a 'CompletePlan'. Fails if any values are missing.
 completePlan :: [(String, String)] -> Plan -> Either [String] CompletePlan
@@ -432,6 +441,8 @@
     dataDirectoryString
   completePlanConnectionTimeout <- getOption "connectionTimeout"
     connectionTimeout
+  completePlanCacheDirectory <- getOption "initDbCache"
+    initDbCache
 
   pure CompletePlan {..}
 
@@ -484,7 +495,7 @@
     <> hardline
     <> text "port:" <+> pretty (getLast port)
     <> hardline
-    <> text "dataDirectory:"
+    <> text "temporaryDirectory:"
     <> softline
     <> pretty (getLast temporaryDirectory)
 
@@ -500,21 +511,22 @@
 --   'Database.Postgres.Temp.startConfig'.
 toPlan
   :: Bool
-  -- ^ Make @initdb@ options
+  -- ^ Make @initdb@ options.
   -> Bool
-  -- ^ Make @createdb@ options
+  -- ^ Make @createdb@ options.
   -> Int
-  -- ^ port
+  -- ^ The port.
   -> FilePath
-  -- ^ Socket directory
+  -- ^ Socket directory.
   -> FilePath
-  -- ^ The @postgres@ data directory
+  -- ^ The @postgres@ data directory.
   -> Plan
 toPlan makeInitDb makeCreateDb port socketDirectory dataDirectoryString = mempty
   { postgresConfigFile = socketDirectoryToConfig socketDirectory
   , dataDirectoryString = pure dataDirectoryString
   , connectionTimeout = pure (60 * 1000000) -- 1 minute
   , logger = pure print
+  , initDbCache = pure Nothing
   , postgresPlan = mempty
       { postgresConfig = standardProcessConfig
           { commandLine = mempty
@@ -546,7 +558,6 @@
             { keyBased = Map.fromList
                 [("--pgdata=", Just dataDirectoryString)]
             }
-
         }
       else Nothing
   }
diff --git a/src/Database/Postgres/Temp/Internal/Core.hs b/src/Database/Postgres/Temp/Internal/Core.hs
--- a/src/Database/Postgres/Temp/Internal/Core.hs
+++ b/src/Database/Postgres/Temp/Internal/Core.hs
@@ -9,11 +9,16 @@
 import           Control.Concurrent (threadDelay)
 import           Control.Concurrent.Async (race_, withAsync)
 import           Control.Exception
-import           Control.Monad (forever, (>=>), unless)
+import           Control.Monad (forever, unless, void)
+import           Crypto.Hash.SHA1 (hash)
 import qualified Data.ByteString.Char8 as BSC
+import qualified Data.ByteString.Base64.URL as Base64
+import           Data.Char
 import           Data.Foldable (for_)
 import           Data.IORef
+import           Data.Maybe
 import           Data.Monoid
+import           Data.List
 import           Data.String
 import           Data.Typeable
 import qualified Database.PostgreSQL.Simple as PG
@@ -80,7 +85,12 @@
   | DeleteDbError PG.SqlError
   | EmptyDataDirectory
   -- ^ This will happen if a 'Database.Postgres.Temp.Config.Plan' is missing a
-  --   'initDbConfig'.
+  --   'Database.Postgres.Temp.Config.initDbConfig'.
+  | CopyCachedInitDbFailed String ExitCode
+  -- ^ This is called if copying a folder cache fails.
+  | FailedToFindDataDirectory String
+  -- ^ Failed to find a data directory when trying to get
+  --   a cached @initdb@ folder.
   deriving (Show, Eq, Typeable)
 
 instance Exception StartError
@@ -99,7 +109,7 @@
   let theConnectionString = Client.toConnectionString options
       startAction = PG.connectPostgreSQL theConnectionString
   try (bracket startAction PG.close mempty) >>= \case
-    Left (_ :: IOError) -> threadDelay 10000 >> waitForDB logger options
+    Left (_ :: IOError) -> threadDelay 1000 >> waitForDB logger options
     Right () -> return ()
 
 -- Only useful if we believe the output is finite
@@ -144,6 +154,12 @@
     <> softline
     <> text (unwords completeProcessConfigCmdLine)
 
+makeCommandLine :: String -> CompleteProcessConfig -> String
+makeCommandLine command CompleteProcessConfig {..} =
+  let envs = unwords $ map (\(x, y) -> x <> "=" <> y) completeProcessConfigEnvVars
+      args = unwords completeProcessConfigCmdLine
+  in envs <> " " <> command <> args
+
 -- | Start a process interactively and return the 'ProcessHandle'
 startProcess
   :: String
@@ -291,7 +307,102 @@
 
       -- Postgres is now ready so return
       return result
+
 -------------------------------------------------------------------------------
+-- initdb cache
+-------------------------------------------------------------------------------
+getInitDbVersion :: IO String
+getInitDbVersion = readProcessWithExitCode "initdb" ["--version"] "" >>= \case
+  (ExitSuccess, outputString, _) -> do
+    let
+      theLastPart = last $ words outputString
+      versionPart = takeWhile (\x -> isDigit x || x == '.' || x == '-') theLastPart
+    pure $ if last versionPart == '.'
+             then init versionPart
+             else versionPart
+
+  (startErrorExitCode, startErrorStdOut, startErrorStdErr) ->
+    throwIO InitDbFailed {..}
+
+-- TODO We need to remove the data directory!
+makeInitDbCommandLine :: CompleteProcessConfig -> String
+makeInitDbCommandLine = makeCommandLine "initdb"
+
+makeArgumentHash :: String -> String
+makeArgumentHash = BSC.unpack . Base64.encode . hash . BSC.pack
+
+splitDataDirectory :: CompleteProcessConfig -> (Maybe String, CompleteProcessConfig)
+splitDataDirectory old =
+  let isDataDirectoryFlag xs = "-D" `isPrefixOf` xs || "--pgdata=" `isPrefixOf` xs
+      (dataDirectoryArgs, otherArgs) =
+        partition isDataDirectoryFlag $ completeProcessConfigCmdLine old
+
+      firstDataDirectoryArg = flip fmap (listToMaybe dataDirectoryArgs) $ \case
+        '-':'D':' ':theDir -> theDir
+        '-':'D':theDir -> theDir
+        '-':'-':'p':'g':'d':'a':'t':'a':'=':theDir -> theDir
+        _ -> error "splitDataDirectory not possible"
+
+      filteredEnvs = filter (not . ("PGDATA"==) . fst) $
+        completeProcessConfigEnvVars old
+
+      clearedConfig = old
+        { completeProcessConfigCmdLine = otherArgs
+        , completeProcessConfigEnvVars = filteredEnvs
+        }
+
+  in (firstDataDirectoryArg, clearedConfig)
+
+makeCachePath :: FilePath -> String -> IO String
+makeCachePath cacheFolder cmdLine = do
+  version <- getInitDbVersion
+  let theHash = makeArgumentHash cmdLine
+  pure $ cacheFolder <> "/" <> version <> "/" <> theHash
+
+addDataDirectory :: String -> CompleteProcessConfig -> CompleteProcessConfig
+addDataDirectory theDataDirectory x = x
+  { completeProcessConfigCmdLine =
+      ("--pgdata=" <> theDataDirectory) : completeProcessConfigCmdLine x
+  }
+
+executeInitDb :: Maybe (Bool, FilePath) -> CompleteProcessConfig -> IO ()
+executeInitDb cache config = do
+  -- helper
+  let runInitDb theConfig = do
+        (res, stdOut, stdErr) <- executeProcessAndTee "initdb" theConfig
+        throwIfNotSuccess (InitDbFailed stdOut stdErr) res
+
+  -- Probably want a MVar to lock this whole operation
+  void $ case cache of
+    Nothing -> runInitDb config
+    Just (copyOnWrite, directoryType) -> do
+      let (mtheDataDirectory, clearedConfig) = splitDataDirectory config
+      theDataDirectory <- maybe
+        (throwIO $ FailedToFindDataDirectory (show $ pretty config))
+        pure
+        mtheDataDirectory
+
+      let theCommandLine = makeInitDbCommandLine clearedConfig
+
+      cachePath <- makeCachePath directoryType theCommandLine
+      let newDataDirectory = cachePath <> "/data"
+      doesDirectoryExist cachePath >>= \case
+        True -> pure ()
+        False -> do
+          createDirectoryIfMissing True cachePath
+          writeFile (cachePath <> "/commandLine.log") theCommandLine
+          runInitDb $ addDataDirectory newDataDirectory clearedConfig
+      -- TODO do a check for macos or linux
+      let
+#ifdef darwin_HOST_OS
+        cpFlags = if copyOnWrite then "cp -Rc " else "cp -R "
+#else
+        cpFlags = if copyOnWrite then "cp -R --reflink=auto " else "cp -R "
+#endif
+        copyCommand = cpFlags <> newDataDirectory <> "/* " <> theDataDirectory
+      throwIfNotSuccess (CopyCachedInitDbFailed copyCommand) =<< system copyCommand
+
+-------------------------------------------------------------------------------
 -- CompletePlan
 -------------------------------------------------------------------------------
 -- | 'CompletePlan' is the low level configuration necessary for creating a database
@@ -308,6 +419,7 @@
   , completePlanConfig            :: String
   , completePlanDataDirectory     :: FilePath
   , completePlanConnectionTimeout :: Int
+  , completePlanCacheDirectory    :: Maybe (Bool, FilePath)
   }
 
 instance Pretty CompletePlan where
@@ -330,6 +442,9 @@
     <>  hardline
     <>  text "completePlanDataDirectory:"
     <+> pretty completePlanDataDirectory
+    <>  hardline
+    <>  text "completePlanCacheDirectory:"
+    <+> pretty completePlanCacheDirectory
 
 -- A simple helper to throw 'ExitCode's when they are 'ExitFailure'.
 throwIfNotSuccess :: Exception e => (ExitCode -> e) -> ExitCode -> IO ()
@@ -352,8 +467,7 @@
 startPlan :: CompletePlan -> IO PostgresProcess
 startPlan plan@CompletePlan {..} = do
   completePlanLogger $ StartPlan $ show $ pretty plan
-  for_ completePlanInitDb $ executeProcessAndTee "initdb" >=>
-    \(res, stdOut, stdErr) -> throwIfNotSuccess (InitDbFailed stdOut stdErr) res
+  for_ completePlanInitDb $ executeInitDb completePlanCacheDirectory
 
   -- Try to give a better error if @initdb@ was not
   -- configured to run.
@@ -370,7 +484,6 @@
     for_ completePlanCreateDb executeCreateDb
 
     pure result
-
 
 -- | Stop the @postgres@ process. See 'stopPostgresProcess' for more details.
 stopPlan :: PostgresProcess -> IO ExitCode
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -6,6 +6,7 @@
 import           Data.Maybe
 import           Data.Monoid
 import           Data.Monoid.Generic
+import           Data.List
 import qualified Data.Set as Set
 import           Data.String
 import qualified Database.PostgreSQL.Simple as PG
@@ -56,6 +57,13 @@
 
   pure $ length $ lines xs
 
+assertConnection :: DB -> IO ()
+assertConnection db = do
+  one <- fmap (PG.fromOnly . head) $
+      withConn db $ \conn -> PG.query_ conn "SELECT 1"
+
+  one `shouldBe` (1 :: Int)
+
 testSuccessfulConfigNoTmp :: ConfigAndAssertion -> IO ()
 testSuccessfulConfigNoTmp ConfigAndAssertion {..} = do
   initialPostgresCount <- countPostgresProcesses
@@ -64,11 +72,7 @@
 
   withConfig' cConfig $ \db -> do
     cAssert db
-    -- check for a valid connection
-    one <- fmap (PG.fromOnly . head) $
-      withConn db $ \conn -> PG.query_ conn "SELECT 1"
-
-    one `shouldBe` (1 :: Int)
+    assertConnection db
 
   countPostgresProcesses `shouldReturn` initialPostgresCount
   countInitdbProcesses `shouldReturn` initialInitdbCount
@@ -86,7 +90,7 @@
 
 testWithTemporaryDirectory :: ConfigAndAssertion -> (ConfigAndAssertion -> IO a) -> IO a
 testWithTemporaryDirectory x f =
-  withTempDirectory "/tmp" "tmp-postgres-spec" $ \directoryPath -> do
+  withTempDirectory "/tmp" "tmp-postgres-spec" $ \directoryPath ->
     f x
       { cConfig = (cConfig x) { temporaryDirectory = pure directoryPath }
       , cAssert = cAssert x <> (\db -> toTemporaryDirectory db `shouldBe` directoryPath)
@@ -331,6 +335,60 @@
        doesDirectoryExist pathToCheck >>= \case
          True -> pure ()
          False -> fail "temporary file was not made permanent"
+
+  it "withDbCacheConfig actually caches the config and cleans up" $
+    withTempDirectory "/tmp" "tmp-postgres-cache-test" $ \dirPath -> do
+      let config = silentConfig { temporaryDirectory = pure dirPath }
+          cacheConfig = CacheConfig
+            { cacheTemporaryDirectory = dirPath
+            , cacheDirectoryType      = Temporary
+            , cacheUseCopyOnWrite     = True
+            }
+      withDbCacheConfig cacheConfig $ \cacheInfo -> do
+        withConfig' (config <> toCacheConfig cacheInfo) $ const $ pure ()
+        -- see if there is a cache
+        tmpFiles <- listDirectory dirPath
+
+        cacheDir <- case filter ("tmp-postgres-cache" `isPrefixOf`) tmpFiles of
+          [x] -> pure x
+          xs -> fail $ "expected single cache dir got: " <> show xs
+
+        listDirectory (dirPath <> "/" <> cacheDir) >>= \case
+          [versionDir] -> listDirectory  (dirPath <> "/" <> cacheDir <> "/" <> versionDir) >>= \case
+            [initDbCacheDir] ->
+              writeFile
+                (  dirPath
+                <> "/"
+                <> cacheDir
+                <> "/"
+                <> versionDir
+                <> "/"
+                <> initDbCacheDir
+                <> "/data/cacheCheck.txt"
+                )
+                "test"
+            xs -> fail $ "expected a single initdb cache directory but got " <> show xs
+          xs -> fail $ "expected a single version directory but got " <> show xs
+
+        -- add a file to look for later
+        withConfig' (config <> toCacheConfig cacheInfo) $ \db -> do
+          -- see if the file is in the data directory
+          let theDataDirectory = toDataDirectory db
+          xs <- listDirectory theDataDirectory
+          xs `shouldContain` ["cacheCheck.txt"]
+
+          assertConnection db
+
+      -- See if cache has been cleaned up
+      tmpFiles <- listDirectory dirPath
+
+      case filter ("tmp-postgres-cache" `isPrefixOf`) tmpFiles of
+        [] -> pure ()
+        xs -> fail $ "unexpected cache dirs. Should be cleaned up. Got: " <> show xs
+
+  it "withDbCache seems to work" $
+    withDbCache $ \cacheInfo ->
+      either throwIO pure =<< withConfig (silentConfig <> toCacheConfig cacheInfo) assertConnection
 
 --
 -- Error Plans. Can't be combined. Just list them out inline since they can't be combined
diff --git a/tmp-postgres.cabal b/tmp-postgres.cabal
--- a/tmp-postgres.cabal
+++ b/tmp-postgres.cabal
@@ -1,5 +1,5 @@
 name:                tmp-postgres
-version:             1.15.0.0
+version:             1.15.1.0
 synopsis: Start and stop a temporary postgres
 description: Start and stop a temporary postgres. See README.md
 homepage:            https://github.com/jfischoff/tmp-postgres#readme
@@ -23,6 +23,9 @@
                  , Database.Postgres.Temp.Internal.Config
   default-extensions:
       ApplicativeDo
+    , BlockArguments
+    , CPP
+    , DeriveAnyClass
     , DeriveFunctor
     , DeriveGeneric
     , DerivingStrategies
@@ -37,10 +40,13 @@
     , TupleSections
     , ViewPatterns
   build-depends: base >= 4.6 && < 5
+               , base64-bytestring
                , ansi-wl-pprint
                , async
                , bytestring
                , containers
+               , cryptohash-sha1
+               , deepseq
                , directory
                , generic-monoid
                , port-utils
@@ -48,6 +54,7 @@
                , postgresql-simple
                , process >= 1.2.0.0
                , random
+               , stm
                , temporary
                , transformers
                , unix
@@ -77,7 +84,8 @@
   ghc-options:        -Wall -threaded -rtsopts -with-rtsopts=-N
   default-language:    Haskell2010
   default-extensions:
-      DeriveDataTypeable
+      BlockArguments
+    , DeriveDataTypeable
     , DeriveGeneric
     , DerivingStrategies
     , DerivingVia
