diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Author name here (c) 2017
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Author name here nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,13 @@
+[![Travis CI Status](https://travis-ci.org/jfischoff/tmp-postgres.svg?branch=master)](http://travis-ci.org/jfischoff/tmp-postgres)
+# tmp-postgres
+
+`tmp-postgres` is a libary for greating a temporary `postgres` instance on a random port for testing.
+
+```haskell
+result <- start []
+case result of
+  Left err -> print err
+  Right tempDB -> do
+     -- Do stuff
+     stop tempDB
+```
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/src/Database/Postgres/Temp.hs b/src/Database/Postgres/Temp.hs
new file mode 100644
--- /dev/null
+++ b/src/Database/Postgres/Temp.hs
@@ -0,0 +1,62 @@
+{-|
+This module provides functions greating a temporary postgres instance on a random port for testing.
+
+ @
+ result <- 'start' []
+ case result of
+   Left err -> print err
+   Right tempDB -> do
+      -- Do stuff
+      'stop' tempDB
+ @
+
+The are few different methods for starting @postgres@ which provide different
+methods of dealing with @stdout@ and @stderr@.
+
+The start methods use a config based on the one used by [pg_tmp](http://ephemeralpg.org/), but can be overriden
+by in different values to the first argument of the start functions.
+
+-}
+{-# LANGUAGE RecordWildCards, LambdaCase, ScopedTypeVariables #-}
+module Database.Postgres.Temp
+  ( -- * Types
+    DB (..)
+  , StartError (..)
+  -- * Starting @postgres@
+  -- $options
+  , start
+  , startAndLogToTmp
+  , startWithHandles
+  -- * Stopping @postgres@
+  , stop
+  ) where
+import Database.Postgres.Temp.Internal
+
+{- $options
+'startWithHandles' is the most general way to start postgres. It allows the user to
+pass in it's own handles for @stdout@ and @stderr@. 'start' and 'startAndLogToTmp'
+both call 'startWithHandles' passing in different handles. 'start' uses the current
+process's @stdout@ and @stderr@ and 'startAndLogToTmp' logs to files in the 'mainDir'.
+
+@postgres@ is started with a default config with the following options:
+
+ @
+   listen_addresses = ''
+   shared_buffers = 12MB
+   fsync = off
+   synchronous_commit = off
+   full_page_writes = off
+   log_min_duration_statement = 0
+   log_connections = on
+   log_disconnections = on
+   unix_socket_directories = {mainDir}
+   client_min_messages = ERROR
+ @
+
+ Any of the options can be overriden by passing in a different value when starting
+
+ @
+   Right db <- 'start' [("log_min_duration_statement", "1000")]
+ @
+
+-}
diff --git a/src/Database/Postgres/Temp/Internal.hs b/src/Database/Postgres/Temp/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Database/Postgres/Temp/Internal.hs
@@ -0,0 +1,194 @@
+{-# LANGUAGE RecordWildCards, LambdaCase, ScopedTypeVariables #-}
+module Database.Postgres.Temp.Internal where
+import System.IO.Temp
+import System.Process
+import System.Process.Internals
+import Control.Concurrent
+import System.IO
+import System.Exit
+import System.Directory
+import Network.Socket
+import Control.Exception
+import Data.Typeable
+
+openFreePort :: IO Int
+openFreePort = bracket (socket AF_INET Stream defaultProtocol) close $ \s -> do
+  localhost <- inet_addr "127.0.0.1"
+  bind s (SockAddrInet aNY_PORT localhost)
+  listen s 1
+  fromIntegral <$> socketPort s
+
+waitForDB :: FilePath -> Int -> IO ()
+waitForDB mainDir port
+  = handle (\(_ :: IOException) -> threadDelay 10000 >> waitForDB mainDir port)
+  $ do bracket
+        (socket AF_UNIX Stream 0)
+        close
+        $ \sock -> connect sock
+                 $ SockAddrUnix
+                 $ mainDir ++ "/.s.PGSQL." ++ show port
+
+data DB = DB
+  { mainDir          :: FilePath
+  -- ^ Temporary directory where the unix socket, logs and data directory live.
+  , connectionString :: String
+  -- ^ PostgreSQL connection string.
+  , pid              :: ProcessHandle
+  -- ^ The process handle for the @postgres@ process.
+  }
+
+-- | start postgres and use the current processes stdout and stderr
+start :: [(String, String)]
+      -- ^ Extra options which override the defaults
+      -> IO (Either StartError DB)
+start options = startWithHandles options stdout stderr
+
+fourth :: (a, b, c, d) -> d
+fourth (_, _, _, x) = x
+
+shellWith :: Handle -> Handle -> String -> CreateProcess
+shellWith stdOut stdErr cmd =
+  (shell cmd)
+    { std_err = UseHandle stdErr
+    , std_out = UseHandle stdOut
+    }
+
+config :: FilePath -> String
+config mainDir = unlines
+  [ "listen_addresses = ''"
+  , "shared_buffers = 12MB"
+  , "fsync = off"
+  , "synchronous_commit = off"
+  , "full_page_writes = off"
+  , "log_min_duration_statement = 0"
+  , "log_connections = on"
+  , "log_disconnections = on"
+  , "unix_socket_directories = '" ++ mainDir ++ "'"
+  , "client_min_messages = ERROR"
+  ]
+
+data StartError
+  = InitDBFailed   ExitCode
+  | CreateDBFailed ExitCode
+  deriving (Show, Eq, Typeable)
+
+instance Exception StartError
+
+throwIfError :: (ExitCode -> StartError) -> ExitCode -> IO ()
+throwIfError f e = case e of
+  ExitSuccess -> return ()
+  _       -> throwIO $ f e
+
+pidString :: ProcessHandle -> IO String
+pidString phandle = withProcessHandle phandle (\case
+        OpenHandle p   -> return $ show p
+        ClosedHandle _ -> return ""
+        )
+
+runProcessWith :: Handle -> Handle -> String -> String -> IO ExitCode
+runProcessWith stdOut stdErr name cmd
+  =   createProcess_ name (shellWith stdOut stdErr cmd)
+  >>= waitForProcess . fourth
+
+-- | Start postgres and pass in handles for stdout and stderr
+startWithHandles :: [(String, String)]
+                 -- ^ Extra options which override the defaults
+                 -> Handle
+                 -- ^ @stdout@
+                 -> Handle
+                 -- ^ @stderr@
+                 -> IO (Either StartError DB)
+startWithHandles options stdOut stdErr = do
+  mainDir <- createTempDirectory "/tmp" "tmp-postgres"
+  startWithHandlesAndDir options mainDir stdOut stdErr
+
+startWithHandlesAndDir :: [(String, String)]
+                       -> FilePath
+                       -> Handle
+                       -> Handle
+                       -> IO (Either StartError DB)
+startWithHandlesAndDir = startWithLogger $ \_ -> return ()
+
+data Event
+  = InitDB
+  | WriteConfig
+  | FreePort
+  | StartPostgres
+  | WaitForDB
+  | CreateDB
+  | Finished
+  deriving (Show, Eq, Enum, Bounded, Ord)
+
+rmDirIgnoreErrors :: FilePath -> IO ()
+rmDirIgnoreErrors mainDir =
+  removeDirectoryRecursive mainDir `catch` (\(_ :: IOException) -> return ())
+
+startWithLogger :: (Event -> IO ())
+                -> [(String, String)]
+                -> FilePath
+                -> Handle
+                -> Handle
+                -> IO (Either StartError DB)
+startWithLogger logger options mainDir stdOut stdErr = try $ flip onException (rmDirIgnoreErrors mainDir) $ do
+  let dataDir = mainDir ++ "/data"
+
+  logger InitDB
+  initDBExitCode <- runProcessWith stdOut stdErr "initDB"
+      ("initDB --nosync -E UNICODE -A trust -D " ++ dataDir)
+  throwIfError InitDBFailed initDBExitCode
+
+  logger WriteConfig
+  writeFile (dataDir ++ "/postgresql.conf") $ config mainDir
+
+  logger FreePort
+  port <- openFreePort
+  -- slight race here, the port might not be free anymore!
+  let connectionString = "postgresql:///test?host=" ++ mainDir ++ "&port=" ++ show port
+  logger StartPostgres
+  let extraOptions = unwords $ map (\(key, value) -> "--" ++ key ++ "=" ++ value) options
+  bracketOnError ( fmap (DB mainDir connectionString . fourth)
+                 $ createProcess_ "postgres"
+                     ( shellWith stdOut stdErr
+                     $ "postgres -D "
+                     ++ dataDir
+                     ++ " -p "
+                     ++ show port
+                     ++ " "
+                     ++ extraOptions
+                     )
+                 )
+                 stop
+                 $ \result -> do
+    logger WaitForDB
+    waitForDB mainDir port
+
+    logger CreateDB
+    throwIfError CreateDBFailed =<<
+      runProcessWith stdOut stdErr "createDB"
+        ( "createDB --host=" ++ mainDir
+        ++ " --port=" ++ show port
+        ++ " test"
+        )
+
+    logger Finished
+    return result
+
+-- | Start postgres and log it's all stdout to {'mainDir'}\/output.txt and {'mainDir'}\/error.txt
+startAndLogToTmp :: [(String, String)]
+                 -- ^ Extra options which override the defaults
+                 -> IO (Either StartError DB)
+startAndLogToTmp options = do
+  mainDir <- createTempDirectory "/tmp" "tmp-postgres"
+
+  stdOutFile <- openFile (mainDir ++ "/" ++ "output.txt") WriteMode
+  stdErrFile <- openFile (mainDir ++ "/" ++ "error.txt") WriteMode
+
+  startWithHandlesAndDir options mainDir stdOutFile stdErrFile
+
+-- | Stop postgres and clean up the temporary database folder.
+stop :: DB -> IO ExitCode
+stop DB {..} = do
+  terminateProcess pid
+  result <- waitForProcess pid
+  removeDirectoryRecursive mainDir
+  return result
diff --git a/test/Database/Postgres/Temp/InternalSpec.hs b/test/Database/Postgres/Temp/InternalSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Database/Postgres/Temp/InternalSpec.hs
@@ -0,0 +1,67 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Database.Postgres.Temp.InternalSpec (main, spec) where
+import Test.Hspec
+import System.IO.Temp
+import Database.Postgres.Temp.Internal
+import Data.Typeable
+import Control.Exception
+import System.IO
+import System.Directory
+import Control.Monad
+import System.Process
+import Database.PostgreSQL.Simple
+import qualified Data.ByteString.Char8 as BSC
+import System.Exit
+
+main :: IO ()
+main = hspec spec
+
+mkDevNull :: IO Handle
+mkDevNull = openFile "/dev/null" WriteMode
+
+data Except = Except
+  deriving (Show, Eq, Typeable)
+
+instance Exception Except
+
+countPostgresProcesses :: IO Int
+countPostgresProcesses = length . lines <$> readProcess "pgrep" ["postgres"] []
+
+spec :: Spec
+spec = describe "Database.Postgres.Temp.Internal" $ do
+  before (createTempDirectory "/tmp" "tmp-postgres") $ after rmDirIgnoreErrors $ describe "startWithLogger/stop" $ do
+    forM_ [minBound .. maxBound] $ \event ->
+      it ("deletes the temp dir and postgres on exception in " ++ show event) $ \mainFilePath -> do
+        -- This is not the best method ... but it works
+        beforePostgresCount <- countPostgresProcesses
+        shouldThrow
+          (startWithLogger (\currentEvent -> when (currentEvent == event) $ throwIO Except) [] mainFilePath stdout stderr)
+          (\Except -> True)
+        doesDirectoryExist mainFilePath `shouldReturn` False
+        countPostgresProcesses `shouldReturn` beforePostgresCount
+
+    it "creates a useful connection string and stop still cleans up" $ \mainFilePath -> do
+      beforePostgresCount <- countPostgresProcesses
+      stdOut <- mkDevNull
+      stdErr <- mkDevNull
+      result <- startWithLogger (\_ -> return ()) [] mainFilePath stdOut stdErr
+      db <- case result of
+              Right x  -> return x
+              Left err -> error $ show err
+      conn <- connectPostgreSQL $ BSC.pack $ connectionString db
+      execute_ conn "create table users (id int)"
+
+      stop db `shouldReturn` ExitSuccess
+      doesDirectoryExist mainFilePath `shouldReturn` False
+      countPostgresProcesses `shouldReturn` beforePostgresCount
+
+    it "can override settings" $ \_ -> do
+      let expectedDuration = "100ms"
+      bracket (start [("log_min_duration_statement", expectedDuration)])
+              (either (\_ -> return ()) (void . stop)) $ \result -> do
+        db <- case result of
+                Right x  -> return x
+                Left err -> error $ show err
+        conn <- connectPostgreSQL $ BSC.pack $ connectionString db
+        [Only actualDuration] <- query_ conn "SHOW log_min_duration_statement"
+        actualDuration `shouldBe` expectedDuration
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
diff --git a/tmp-postgres.cabal b/tmp-postgres.cabal
new file mode 100644
--- /dev/null
+++ b/tmp-postgres.cabal
@@ -0,0 +1,64 @@
+name:                tmp-postgres
+version:             0.1.0.0
+synopsis: Start and stop a temporary postgres for testing
+description:
+ This module provides functions greating a temporary postgres instance on a random port for testing.
+ .
+ @
+  result <- 'start' []
+  case result of
+    Left err -> print err
+    Right tempDB -> do
+       -- Do stuff
+       'stop' tempDB
+ @
+ .
+ The are few different methods for starting @postgres@ which provide different
+ methods of dealing with @stdout@ and @stderr@.
+ .
+ The start methods use a config based on the one used by [pg_tmp](http://ephemeralpg.org/), but can be overriden
+ by in different values to the first argument of the start functions.
+homepage:            https://github.com/jfischoff/tmp-postgres#readme
+license:             BSD3
+license-file:        LICENSE
+author:              Jonathan Fischoff
+maintainer:          jonathangfischoff@gmail.com
+copyright:           2017 Jonathan Fischoff
+category:            Web
+build-type:          Simple
+extra-source-files:  README.md
+cabal-version:       >=1.10
+
+library
+  hs-source-dirs:      src
+  exposed-modules: Database.Postgres.Temp
+                 , Database.Postgres.Temp.Internal
+  build-depends: base >= 4.7 && < 5
+               , temporary
+               , process
+               , unix
+               , directory
+               , network
+  ghc-options: -Wall
+  default-language:    Haskell2010
+
+test-suite tmp-postgres-test
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      test
+  main-is:             Spec.hs
+  other-modules: Database.Postgres.Temp.InternalSpec
+  build-depends:       base
+                     , tmp-postgres
+                     , hspec
+                     , hspec-discover
+                     , temporary
+                     , directory
+                     , process
+                     , postgresql-simple
+                     , bytestring
+  ghc-options:        -Wall -Wno-unused-do-bind -threaded -rtsopts -with-rtsopts=-N
+  default-language:    Haskell2010
+
+source-repository head
+  type:     git
+  location: https://github.com/jfischoff/tmp-postgres
