diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Hans-Christian Esperer <hc@hcesperer.org> (c) 2015
+
+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/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/Network/Wai/Session/PostgreSQL.hs b/src/Network/Wai/Session/PostgreSQL.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Wai/Session/PostgreSQL.hs
@@ -0,0 +1,99 @@
+module Network.Wai.Session.PostgreSQL
+    ( dbStore
+    , WithPostgreSQLConn (..)
+    , StoreSettings (..)
+    ) where
+
+import Control.Exception.Base
+import Control.Exception
+import Control.Monad
+import Control.Monad.IO.Class
+import Data.Int (Int64)
+import Data.Serialize (encode, decode, Serialize)
+import Data.Time.Clock.POSIX (getPOSIXTime)
+import Database.PostgreSQL.Simple
+import Network.Wai.Session
+
+import qualified Data.ByteString as B
+
+data StoreSettings = StoreSettings
+    { storeSettingsSessionTimeout :: Int64
+    , storeSettingsKeyGen :: IO B.ByteString
+    }
+
+class WithPostgreSQLConn a where
+    withPostgreSQLConn :: a -> (Connection -> IO b) -> IO b
+
+instance WithPostgreSQLConn Connection where
+    withPostgreSQLConn conn = bracket (return conn) (\_ -> return ())
+
+qryCreateTable      = "CREATE TABLE session (id bigserial NOT NULL, session_key character varying NOT NULL, session_created_at bigint NOT NULL, session_last_access bigint NOT NULL, session_value bytea NOT NULL, CONSTRAINT session_pkey PRIMARY KEY (id), CONSTRAINT session_session_key_key UNIQUE (session_key)) WITH (OIDS=FALSE);"
+qryCreateSession    = "INSERT INTO session (session_key, session_created_at, session_last_access, session_value) VALUES (?,?,?,?)"
+qryUpdateSession    = "UPDATE session SET session_value=?,session_last_access=? WHERE session_key=?"
+qryLookupSession    = "SELECT session_value FROM session WHERE session_key=? AND session_last_access>=?"
+qryLookupSession'   = "UPDATE session SET session_last_access=? WHERE session_key=?"
+qryLookupSession''  = "SELECT session_value FROM session WHERE session_key=?"
+
+dbStore :: (WithPostgreSQLConn a, Serialize k, Eq k, Serialize v, MonadIO m) => a -> StoreSettings -> IO (SessionStore m k v)
+dbStore pool stos = do
+    withPostgreSQLConn pool $ \ conn ->
+        unerror $ execute_ conn qryCreateTable
+    return $ dbStore' pool stos
+
+dbStore' :: (WithPostgreSQLConn a, Serialize k, Eq k, Serialize v, MonadIO m) => a -> StoreSettings -> SessionStore m k v
+dbStore' pool stos Nothing = do
+    newKey <- storeSettingsKeyGen stos
+    let map     = [] :: [(k, v)]
+        map'    = "" -- encode map
+    curtime <- round <$> liftIO getPOSIXTime
+    withPostgreSQLConn pool $ \ conn ->
+        void $ execute conn qryCreateSession (newKey, curtime :: Int64, curtime, map' :: B.ByteString)
+    backend pool newKey map
+dbStore' pool stos (Just key) = do
+    let map     = [] :: [(k, v)]
+        map'    = "\"\"" -- encode map
+    curtime <- round <$> liftIO getPOSIXTime
+    res <- withPostgreSQLConn pool $ \ conn ->
+        query conn qryLookupSession (key, curtime - storeSettingsSessionTimeout stos) :: IO [Only B.ByteString]
+    case res of
+        [Only _]    -> backend pool key map
+        _           -> dbStore' pool stos Nothing
+
+backend :: (WithPostgreSQLConn a, Serialize k, Eq k, Serialize v, MonadIO m) => a -> B.ByteString -> [(k, v)] -> IO (Session m k v, IO B.ByteString)
+backend pool key mappe =
+    return ( (
+        (reader pool key mappe)
+      , (writer pool key mappe) )
+     , return key )
+
+reader :: (WithPostgreSQLConn a, Serialize k, Eq k, Serialize v, MonadIO m) => a -> B.ByteString -> [(k, v)] -> k -> m (Maybe v)
+reader pool key mappe k = do
+    curtime <- round <$> liftIO getPOSIXTime
+    res <- liftIO $ withPostgreSQLConn pool $ \conn -> do
+        void $ execute conn qryLookupSession' (curtime :: Int64, key)
+        query conn qryLookupSession'' (Only key)
+    case res of
+        [Only store']    -> case decode (fromBinary store') of
+            Right store     -> return $ k `lookup` store
+            Left error      -> return Nothing
+        []              -> return Nothing
+
+writer :: (WithPostgreSQLConn a, Serialize k, Eq k, Serialize v, MonadIO m) => a -> B.ByteString -> [(k, v)] -> k -> v -> m ()
+writer pool key mappe k v = do
+    curtime <- round <$> liftIO getPOSIXTime
+    [Only store] <- liftIO $ withPostgreSQLConn pool $ \conn ->
+        query conn qryLookupSession'' (Only key)
+    let store'      = case decode (fromBinary store) of
+            Right s             -> s
+            _                   -> []
+        store''     = ((k,v):) . filter ((/=k) . fst) $ store'
+        store'''    = encode store''
+    liftIO $ withPostgreSQLConn pool $ \conn ->
+        void $ execute conn qryUpdateSession (Binary store''', curtime :: Int64, key)
+
+
+ignoreSqlError :: SqlError -> IO ()
+ignoreSqlError _ = pure ()
+
+unerror :: IO a -> IO ()
+unerror action = void action `catch` ignoreSqlError
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,2 @@
+main :: IO ()
+main = putStrLn "Test suite not yet implemented"
diff --git a/wai-session-postgresql.cabal b/wai-session-postgresql.cabal
new file mode 100644
--- /dev/null
+++ b/wai-session-postgresql.cabal
@@ -0,0 +1,42 @@
+name:                wai-session-postgresql
+version:             0.1.0.0
+synopsis:            PostgreSQL backed Wai session store
+description:         Please see README.md
+homepage:            http://github.com/githubuser/postgresql-session#readme
+license:             BSD3
+license-file:        LICENSE
+author:              Hans-Christian Esperer hc@hcesperer.org
+maintainer:          Hans-Christian Esperer hc@hcesperer.org
+homepage:            https://github.com/hce/postgresql-session
+copyright:           2015 Hans-Christian Esperer
+stability:           experimental
+tested-with:         GHC == 7.10.2
+category:            Web
+build-type:          Simple
+cabal-version:       >=1.10
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     Network.Wai.Session.PostgreSQL
+  build-depends:       base >= 4.7 && < 5
+                     , bytestring
+                     , cereal
+                     , postgresql-simple
+                     , time
+                     , transformers
+                     , wai-session
+  default-language:    Haskell2010
+  default-extensions:  OverloadedStrings
+
+test-suite postgresql-session-test
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      test
+  main-is:             Spec.hs
+  build-depends:       base
+                     , postgresql-session
+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N
+  default-language:    Haskell2010
+
+source-repository head
+  type:     git
+  location: https://github.com/githubuser/postgresql-session
