diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Revision history for hasql-effectful
+
+## 0.1.0.0 -- 2023-12-27
+
+* Initial release 
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2023 Nadeem Bitar
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/examples/Main.hs b/examples/Main.hs
new file mode 100644
--- /dev/null
+++ b/examples/Main.hs
@@ -0,0 +1,108 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Main where
+
+import Data.ByteString.Char8 (pack)
+import Data.Functor.Contravariant ((>$<))
+import Data.Int (Int32)
+import Data.Text (Text)
+import Effectful
+import Effectful.Error.Static
+import Effectful.Hasql
+import Hasql.Decoders qualified as D
+import Hasql.Encoders qualified as E
+import Hasql.Pool (Pool, UsageError, acquire)
+import Hasql.Session (Session, statement)
+import Hasql.Statement (Statement (..))
+import Hasql.Transaction qualified as T
+import Hasql.Transaction.Sessions
+import System.Environment (lookupEnv)
+
+data User = User
+  { firstName :: Text,
+    lastName :: Text,
+    userId :: Maybe Int32
+  }
+  deriving stock (Show)
+
+userDecoder :: D.Row User
+userDecoder =
+  User
+    <$> D.column (D.nonNullable D.text)
+    <*> D.column (D.nonNullable D.text)
+    <*> D.column (D.nullable D.int4)
+
+userEncoder :: E.Params User
+userEncoder =
+  (firstName >$< E.param (E.nonNullable E.text))
+    <> (lastName >$< E.param (E.nonNullable E.text))
+
+insertUser_ :: Statement User Int32
+insertUser_ =
+  Statement sql encoder decoder True
+  where
+    sql = "INSERT INTO users (first_name, last_name) VALUES ($1, $2) RETURNING id"
+    encoder = userEncoder
+    decoder = D.singleRow ((D.column . D.nonNullable) D.int4)
+
+findUserById_ :: Statement Int32 (Maybe User)
+findUserById_ =
+  Statement sql encoder decoder True
+  where
+    sql = "SELECT first_name, last_name, id FROM users WHERE id = $1"
+    encoder = E.param $ E.nonNullable E.int4
+    decoder = D.rowMaybe userDecoder
+
+findUserById :: Int32 -> Session (Maybe User)
+findUserById userId = statement userId findUserById_
+
+insertUser :: User -> Session Int32
+insertUser user = transaction Serializable Write $ do
+  T.statement user insertUser_
+
+createUser :: (Hasql :> es, Error UsageError :> es) => User -> Eff es Int32
+createUser user = do
+  runSession $ insertUser user
+
+findUser :: (Hasql :> es, Error UsageError :> es) => Int32 -> Eff es (Maybe User)
+findUser userId = do
+  runSession $ findUserById userId
+
+mkPool :: IO Pool
+mkPool = do
+  pgHost <- lookupEnv "PG_CONNECTION_STRING"
+  case pgHost of
+    Just h -> acquire 3 10 1_800 1_800 (pack h)
+    Nothing -> error "PG_CONNECTION_STRING env is not defined or is invalid"
+
+createTableStatement :: Statement () ()
+createTableStatement = Statement sql mempty D.noResult False
+  where
+    sql = "CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, first_name TEXT, last_name TEXT)"
+
+createTable :: (Hasql :> es, Error UsageError :> es) => Eff es ()
+createTable = do
+  runSession $ statement () createTableStatement
+
+newUser :: User
+newUser = User "Sung-kyung" "Lee" Nothing
+
+sampleApp :: (Hasql :> es, Error UsageError :> es) => Eff es (Maybe User)
+sampleApp = do
+  uId <- createUser newUser
+  findUser uId
+
+runToIO :: Pool -> Eff [Hasql, Error UsageError, IOE] a -> IO a
+runToIO pool = runEff . runErrorWith @UsageError handleUsageError . runHasqlIO pool
+
+handleUsageError :: (IOE :> es) => CallStack -> UsageError -> Eff es a
+handleUsageError callStack err = do
+  liftIO $ putStrLn $ "Usage error" <> show err <> prettyCallStack callStack
+  error "hasql usage error"
+
+main :: IO ()
+main = do
+  pool <- mkPool
+  _ <- runToIO pool createTable
+  u <- runToIO pool sampleApp
+  print u
diff --git a/hasql-effectful.cabal b/hasql-effectful.cabal
new file mode 100644
--- /dev/null
+++ b/hasql-effectful.cabal
@@ -0,0 +1,62 @@
+cabal-version:   3.4
+name:            hasql-effectful
+version:         0.1.0.0
+synopsis:        Effectful bindings for hasql
+description:
+  @<https://hackage.haskell.org/package/effectful Effectful>@ bindings for @<https://hackage.haskell.org/package/hasql hasql>@
+
+category:        Database
+homepage:        https://github.com/shinzui/hasql-effectful
+license:         MIT
+license-file:    LICENSE
+author:          Nadeem Bitar
+maintainer:      nadeem@gmail.com
+build-type:      Simple
+extra-doc-files: CHANGELOG.md
+
+common common
+  ghc-options:        -Wall
+  default-extensions:
+    DataKinds
+    DerivingStrategies
+    LambdaCase
+    TypeFamilies
+
+library
+  import:           common
+  exposed-modules:  Effectful.Hasql
+  build-depends:
+    , base        ^>=4.17   && <5
+    , effectful   >=1.3.0.0 && <3.0.0.0
+    , hasql       ^>=1.6    && <2
+    , hasql-pool  ^>=0.10
+
+  hs-source-dirs:   src
+  default-language: GHC2021
+
+executable hasql-effectful-example
+  import:           common
+  ghc-options:      -threaded -rtsopts -with-rtsopts=-N
+  main-is:          Main.hs
+  build-depends:
+    , base               ^>=4.17
+    , bytestring         ^>=0.11.5
+    , effectful          ^>=2.3.0
+    , hasql              ^>=1.6
+    , hasql-effectful
+    , hasql-pool         ^>=0.10.0
+    , hasql-transaction  ^>=1.0.1
+    , text               ^>=2.0
+
+  hs-source-dirs:   examples
+  default-language: GHC2021
+
+test-suite hasql-effectful-test
+  import:           common
+  default-language: GHC2021
+  type:             exitcode-stdio-1.0
+  hs-source-dirs:   test
+  main-is:          Main.hs
+  build-depends:
+    , base             ^>=4.17
+    , hasql-effectful
diff --git a/src/Effectful/Hasql.hs b/src/Effectful/Hasql.hs
new file mode 100644
--- /dev/null
+++ b/src/Effectful/Hasql.hs
@@ -0,0 +1,41 @@
+module Effectful.Hasql
+  ( -- * Effect
+    Hasql (..),
+    runSession,
+
+    -- * Handlers
+    runHasqlIO,
+    runWithPool,
+  )
+where
+
+import Effectful
+import Effectful.Dispatch.Dynamic
+import Effectful.Error.Static
+import Hasql.Pool (Pool, UsageError, use)
+import Hasql.Session (Session)
+
+-- | Provides the ability to execute actions against a postgresql database
+data Hasql :: Effect where
+  RunSession :: Error UsageError :> es => Session a -> Hasql (Eff es) a
+
+type instance DispatchOf Hasql = Dynamic
+
+runSession :: (HasCallStack, Error UsageError :> es, Hasql :> es) => Session a -> Eff es a
+runSession = send . RunSession
+
+runHasqlIO ::
+  forall es a.
+  ( IOE :> es
+  ) =>
+  Pool ->
+  Eff (Hasql : es) a ->
+  Eff es a
+runHasqlIO pool = interpret $ \env -> \case
+  RunSession session -> do
+    r <- liftIO $ use pool session
+    localSeqUnlift env $ \unlift -> unlift $ do
+      either throwError pure r
+
+runWithPool :: Pool -> Eff [Hasql, Error UsageError, IOE] a -> IO (Either (CallStack, UsageError) a)
+runWithPool pool = runEff . runError @UsageError . runHasqlIO pool
diff --git a/test/Main.hs b/test/Main.hs
new file mode 100644
--- /dev/null
+++ b/test/Main.hs
@@ -0,0 +1,4 @@
+module Main (main) where
+
+main :: IO ()
+main = putStrLn "Test suite not yet implemented."
