diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -2,6 +2,29 @@
 Simple Haskell API for LMDB
 ===========================
 
-This is a simple API for the [Lightning Memory-mapped Database][LMDB].
+This package allows you to store arbitrary Haskell values in and retrieve them
+from a persistent [Lightning Memory-mapped Database][LMDB] on disk.
 
   [LMDB]: https://symas.com/lightning-memory-mapped-database/
+
+LMDB is a high-performance [ACID][]-compliant no-maintenance read-optimized
+key-value store. Any Haskell value with a [`Serialise`][Serialise] instance
+can be stored in an LMDB database, or used as a key to index one.
+
+  [ACID]: https://en.wikipedia.org/wiki/ACID
+  [Serialise]: https://hackage.haskell.org/package/serialise/docs/Codec-Serialise-Tutorial.html#g:3
+
+This package provides a few different APIs for using LMDB:
+
+  * The basic API provides transactional `put` and `get` functions to store
+    and retrieve values from an LMDB database.
+
+  * The extended API provides many functions similar to those in `Data.Map`,
+    e.g. `lookup`, `insert`, `delete`, `foldr`, and so on.
+
+  * The `View` API provides a read-only snapshot of an LMDB database that can
+    be queried from pure code.
+
+  * The `DBRef` API provides a mutable variable similar to `IORef` that is
+    tied to a particular key in an LMDB database.
+
diff --git a/lmdb-simple.cabal b/lmdb-simple.cabal
--- a/lmdb-simple.cabal
+++ b/lmdb-simple.cabal
@@ -1,6 +1,6 @@
 
 name:                lmdb-simple
-version:             0.3.0.0
+version:             0.3.1.0
 
 synopsis:            Simple API for LMDB
 
@@ -42,8 +42,8 @@
 
   build-depends:       base >= 4.7 && < 5
                      , bytestring >= 0.10 && < 0.11
-                     , serialise >= 0.1 && < 0.2
                      , lmdb >= 0.2 && < 0.3
+                     , serialise >= 0.1 && < 0.2
   ghc-options:         -Wall -Wno-name-shadowing -Wno-unused-do-bind
   default-language:    Haskell2010
   default-extensions:  Trustworthy
diff --git a/src/Database/LMDB/Simple.hs b/src/Database/LMDB/Simple.hs
--- a/src/Database/LMDB/Simple.hs
+++ b/src/Database/LMDB/Simple.hs
@@ -35,7 +35,7 @@
 These additional APIs are available:
 
   * "Database.LMDB.Simple.Extra" provides additional functions for querying
-    and modifying LMDB databases within the 'Transaction' monad
+    and modifying LMDB databases from within the 'Transaction' monad
 
   * "Database.LMDB.Simple.View" provides a read-only snapshot of an LMDB
     database that can be accessed from pure code
@@ -77,10 +77,6 @@
   , SubMode
   ) where
 
-import Prelude hiding
-  ( lookup
-  )
-
 import Control.Concurrent
   ( runInBoundThread
   )
@@ -129,7 +125,6 @@
   , isReadOnlyTransaction
   , isReadWriteTransaction
   )
-
 import qualified Database.LMDB.Simple.Internal as Internal
 
 import Foreign.C
diff --git a/src/Database/LMDB/Simple/DBRef.hs b/src/Database/LMDB/Simple/DBRef.hs
--- a/src/Database/LMDB/Simple/DBRef.hs
+++ b/src/Database/LMDB/Simple/DBRef.hs
@@ -13,32 +13,15 @@
   ) where
 
 import Control.Monad
-  ( (>=>)
-  , void
-  )
-
-import Control.Monad.IO.Class
-  ( MonadIO (liftIO)
+  ( void
   )
 
 import Data.ByteString
   ( ByteString
   )
 
-import Data.ByteString.Lazy
-  ( toStrict
-  )
-
-import Data.ByteString.Unsafe
-  ( unsafeUseAsCStringLen
-  )
-
 import Database.LMDB.Raw
   ( MDB_dbi'
-  , MDB_val (..)
-  , mdb_get'
-  , mdb_put'
-  , mdb_del'
   )
 
 import Database.LMDB.Simple
@@ -52,14 +35,10 @@
   , ReadWrite
   , ReadOnly
   , Serialise
-  , serialise
-  , marshalIn
-  , marshalOut
-  , defaultWriteFlags
-  )
-
-import Foreign
-  ( castPtr
+  , serialiseBS
+  , getBS
+  , putBS
+  , deleteBS
   )
 
 -- | A 'DBRef' is a reference to a particular key within an LMDB database. It
@@ -76,32 +55,26 @@
 -- environment.
 newDBRef :: Serialise k
          => Environment mode -> Database k a -> k -> IO (DBRef mode a)
-newDBRef env (Db _ dbi) = return . Ref env dbi . toStrict . serialise
-
-withVal :: ByteString -> (MDB_val -> IO a) -> IO a
-withVal bs f = unsafeUseAsCStringLen bs $ \(ptr, len) ->
-  f $ MDB_val (fromIntegral len) (castPtr ptr)
+newDBRef env (Db _ dbi) = return . Ref env dbi . serialiseBS
 
 -- | Read the current value of a 'DBRef'.
 readDBRef :: Serialise a => DBRef mode a -> IO (Maybe a)
-readDBRef ref@(Ref env dbi key) = transaction env (tx ref)
+readDBRef ref@(Ref env dbi key) = transaction env (tx env ref)
 
-  where tx :: Serialise a => DBRef mode a -> Transaction ReadOnly (Maybe a)
-        tx _ = Txn $ \txn -> withVal key $ mdb_get' txn dbi >=>
-          maybe (return Nothing) (liftIO . fmap Just . marshalIn)
+  where tx :: Serialise a
+           => Environment mode -> DBRef mode a -> Transaction ReadOnly (Maybe a)
+        tx (Env env) _ = getBS (Db env dbi) key
 
 -- | Write a new value into a 'DBRef'.
 writeDBRef :: Serialise a => DBRef ReadWrite a -> Maybe a -> IO ()
-writeDBRef (Ref env dbi key) = transaction env . maybe delKey putKey
+writeDBRef (Ref env dbi key) = transaction env . maybe (delKey env) (putKey env)
 
-  where delKey :: Transaction ReadWrite ()
-        delKey = Txn $ \txn -> withVal key $ \kval ->
-          void $ mdb_del' txn dbi kval Nothing
+  where delKey :: Environment ReadWrite -> Transaction ReadWrite ()
+        delKey (Env env) = void $ deleteBS (Db env dbi) key
 
-        putKey :: Serialise a => a -> Transaction ReadWrite ()
-        putKey value = Txn $ \txn -> withVal key $ \kval ->
-          marshalOut value $ \vval ->  -- FIXME: use mdb_reserve'
-          void $ mdb_put' defaultWriteFlags txn dbi kval vval
+        putKey :: Serialise a
+               => Environment ReadWrite -> a -> Transaction ReadWrite ()
+        putKey (Env env) = putBS (Db env dbi) key
 
 -- | Atomically mutate the contents of a 'DBRef'.
 modifyDBRef_ :: Serialise a => DBRef ReadWrite a -> (Maybe a -> Maybe a) -> IO ()
@@ -110,11 +83,12 @@
 -- | Atomically mutate the contents of a 'DBRef' and return a value.
 modifyDBRef :: Serialise a
             => DBRef ReadWrite a -> (Maybe a -> (Maybe a, b)) -> IO b
-modifyDBRef (Ref env dbi key) = transaction env . tx
+modifyDBRef (Ref env dbi key) = transaction env . tx env
 
-  where tx :: Serialise a => (Maybe a -> (Maybe a, b)) -> Transaction ReadWrite b
-        tx f = Txn $ \txn -> withVal key $ \kval -> mdb_get' txn dbi kval >>=
-          maybe (return Nothing) (fmap Just . marshalIn) >>= \x ->
-          let (x', r) = f x in maybe (mdb_del' txn dbi kval Nothing)
-            (flip marshalOut $ mdb_put' defaultWriteFlags txn dbi kval) x' >>
+  where tx :: Serialise a
+           => Environment mode -> (Maybe a -> (Maybe a, b))
+           -> Transaction ReadWrite b
+        tx (Env env) f = let db = Db env dbi in
+          getBS db key >>= \x -> let (x', r) = f x in
+          maybe (void $ deleteBS db key) (putBS db key) x' >>
           return r
diff --git a/src/Database/LMDB/Simple/Internal.hs b/src/Database/LMDB/Simple/Internal.hs
--- a/src/Database/LMDB/Simple/Internal.hs
+++ b/src/Database/LMDB/Simple/Internal.hs
@@ -14,7 +14,7 @@
   , isReadOnlyEnvironment
   , isReadOnlyTransaction
   , isReadWriteTransaction
-  , serialise
+  , serialiseBS
   , marshalOut
   , marshalIn
   , peekVal
@@ -25,8 +25,12 @@
   , overwriteFlags
   , get
   , get'
+  , getBS
+  , getBS'
   , put
+  , putBS
   , delete
+  , deleteBS
   ) where
 
 import Codec.Serialise
@@ -95,7 +99,9 @@
   , copyBytes
   )
 
-import GHC.Exts (Constraint)
+import GHC.Exts
+  ( Constraint
+  )
 
 data ReadWrite
 data ReadOnly
@@ -166,13 +172,22 @@
 peekVal :: Serialise v => Ptr MDB_val -> IO v
 peekVal = peek >=> marshalIn
 
+serialiseLBS :: Serialise v => v -> BSL.ByteString
+serialiseLBS = serialise
+
+serialiseBS :: Serialise v => v -> BS.ByteString
+serialiseBS = toStrict . serialiseLBS
+
 marshalIn :: Serialise v => MDB_val -> IO v
 marshalIn (MDB_val len ptr) =
   deserialise . fromStrict <$> packCStringLen (castPtr ptr, fromIntegral len)
 
 marshalOut :: Serialise v => v -> (MDB_val -> IO a) -> IO a
-marshalOut value f =
-  unsafeUseAsCStringLen (toStrict $ serialise value) $ \(ptr, len) ->
+marshalOut = marshalOutBS . serialiseBS
+
+marshalOutBS :: BS.ByteString -> (MDB_val -> IO a) -> IO a
+marshalOutBS bs f =
+  unsafeUseAsCStringLen bs $ \(ptr, len) ->
   f $ MDB_val (fromIntegral len) (castPtr ptr)
 
 copyLazyBS :: BSL.ByteString -> Ptr Word8 -> Int -> IO ()
@@ -211,22 +226,36 @@
 
 get :: (Serialise k, Serialise v)
     => Database k v -> k -> Transaction mode (Maybe v)
-get db key = get' db key >>=
-  maybe (return Nothing) (liftIO . fmap Just . marshalIn)
+get db = getBS db . serialiseBS
 
 get' :: Serialise k => Database k v -> k -> Transaction mode (Maybe MDB_val)
-get' (Db _ dbi) key = Txn $ \txn -> marshalOut key $ mdb_get' txn dbi
+get' db = getBS' db . serialiseBS
 
+getBS :: Serialise v
+      => Database k v -> BS.ByteString -> Transaction mode (Maybe v)
+getBS db keyBS = getBS' db keyBS >>=
+  maybe (return Nothing) (liftIO . fmap Just . marshalIn)
+
+getBS' :: Database k v -> BS.ByteString -> Transaction mode (Maybe MDB_val)
+getBS' (Db _ dbi) keyBS = Txn $ \txn -> marshalOutBS keyBS $ mdb_get' txn dbi
+
 put :: (Serialise k, Serialise v)
     => Database k v -> k -> v -> Transaction ReadWrite ()
-put (Db _ dbi) key value = Txn $ \txn ->
-  marshalOut key $ \kval -> do
-  let bs = serialise value
-      sz = fromIntegral (BSL.length bs)
+put db = putBS db . serialiseBS
+
+putBS :: Serialise v
+     => Database k v -> BS.ByteString -> v -> Transaction ReadWrite ()
+putBS (Db _ dbi) keyBS value = Txn $ \txn ->
+  marshalOutBS keyBS $ \kval -> do
+  let valueLBS = serialiseLBS value
+      sz = fromIntegral (BSL.length valueLBS)
   MDB_val len ptr <- mdb_reserve' defaultWriteFlags txn dbi kval sz
   let len' = fromIntegral len
-  assert (len' == sz) $ copyLazyBS bs ptr len'
+  assert (len' == sz) $ copyLazyBS valueLBS ptr len'
 
 delete :: Serialise k => Database k v -> k -> Transaction ReadWrite Bool
-delete (Db _ dbi) key = Txn $ \txn ->
-  marshalOut key $ \kval -> mdb_del' txn dbi kval Nothing
+delete db = deleteBS db . serialiseBS
+
+deleteBS :: Database k v -> BS.ByteString -> Transaction ReadWrite Bool
+deleteBS (Db _ dbi) key = Txn $ \txn ->
+  marshalOutBS key $ \kval -> mdb_del' txn dbi kval Nothing
diff --git a/test/Database/LMDB/Simple/DBRefSpec.hs b/test/Database/LMDB/Simple/DBRefSpec.hs
--- a/test/Database/LMDB/Simple/DBRefSpec.hs
+++ b/test/Database/LMDB/Simple/DBRefSpec.hs
@@ -22,6 +22,10 @@
     (modifyDBRef_ ref (fmap (++ "bar")) >> readDBRef ref)
     `shouldReturn` Just "foobar"
 
-  it "can be made empty again" $ \ref ->
-    (writeDBRef ref Nothing >> readDBRef ref)
+  it "can be emptied with modifyDBRef" $ \ref ->
+    (modifyDBRef_ ref (const Nothing) >> readDBRef ref)
+    `shouldReturn` Nothing
+
+  it "can be emptied with writeDBRef" $ \ref ->
+    (writeDBRef ref (Just "baz") >> writeDBRef ref Nothing >> readDBRef ref)
     `shouldReturn` Nothing
diff --git a/test/Database/LMDB/SimpleSpec.hs b/test/Database/LMDB/SimpleSpec.hs
--- a/test/Database/LMDB/SimpleSpec.hs
+++ b/test/Database/LMDB/SimpleSpec.hs
@@ -29,8 +29,9 @@
 
   describe "transactions" $ do
     it "aborts" $ \(env, db) ->
-      transaction env (put db 0 (Just "zero") >> abort)
-      `shouldThrow` (const True :: Selector AbortedTransaction)
+      ( do transaction env $ put db 0 Nothing
+           transaction env $ put db 0 (Just "zero") >> abort
+      ) `shouldThrow` (const True :: Selector AbortedTransaction)
 
     it "rolls back" $ \(env, db) ->
       readOnlyTransaction env (get db 0)
