diff --git a/Database/Persist/Sqlite.hs b/Database/Persist/Sqlite.hs
new file mode 100644
--- /dev/null
+++ b/Database/Persist/Sqlite.hs
@@ -0,0 +1,107 @@
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE PackageImports #-}
+{-# LANGUAGE FlexibleContexts #-}
+-- | A sqlite backend for persistent.
+module Database.Persist.Sqlite
+    ( SqliteReader
+    , persistSqlite
+    , runSqlite
+    , withSqlite
+      -- * Re-exports
+    , Database
+    , open
+    , close
+    , Int64
+    , module Database.Persist.Helper
+    , persist
+    ) where
+
+import Database.Persist (PersistValue (..))
+import Database.Persist.Helper
+import Control.Monad.Trans.Reader
+import Language.Haskell.TH.Syntax hiding (lift)
+import Control.Monad.IO.Class (MonadIO (..))
+import Data.List (intercalate)
+import "MonadCatchIO-transformers" Control.Monad.CatchIO
+import Database.Sqlite
+import Database.Persist.Quasi
+import Database.Persist.GenericSql
+
+-- | Generate data types and instances for the given entity definitions. Can
+-- deal directly with the output of the 'persist' quasi-quoter.
+persistSqlite :: [EntityDef] -> Q [Dec]
+persistSqlite = fmap concat . mapM derivePersistSqliteReader
+
+-- | A ReaderT monad transformer holding a sqlite database connection.
+type SqliteReader = ReaderT Database
+
+-- | Handles opening and closing of the database connection automatically.
+withSqlite :: MonadCatchIO m => String -> (Database -> m a) -> m a
+withSqlite s f = bracket (liftIO $ open s) (liftIO . close) f
+
+-- | Run a series of database actions within a single transactions. On any
+-- exception, the transaction is rolled back.
+runSqlite :: MonadCatchIO m => SqliteReader m a -> Database -> m a
+runSqlite r conn = do
+    Done <- liftIO begin
+    res <- onException (runReaderT r conn) $ liftIO rollback
+    Done <- liftIO commit
+    return res
+  where
+    begin = bracket (prepare conn "BEGIN") finalize step
+    commit = bracket (prepare conn "COMMIT") finalize step
+    rollback = bracket (prepare conn "ROLLBACK") finalize step
+
+withStmt :: MonadCatchIO m
+         => String
+         -> [PersistValue]
+         -> (RowPopper (SqliteReader m) -> SqliteReader m a)
+         -> SqliteReader m a
+withStmt sql vals f = do
+    conn <- ask
+    bracket (liftIO $ prepare conn sql) (liftIO . finalize) $ \stmt -> do
+        liftIO $ bind stmt vals
+        f $ go stmt
+  where
+    go stmt = liftIO $ do
+        x <- step stmt
+        case x of
+            Done -> return Nothing
+            Row -> do
+                cols <- liftIO $ columns stmt
+                return $ Just cols
+
+execute :: MonadCatchIO m => String -> [PersistValue] -> SqliteReader m ()
+execute sql vals = do
+    conn <- ask
+    bracket (liftIO $ prepare conn sql) (liftIO . finalize) $ \stmt -> do
+        liftIO $ bind stmt vals
+        Done <- liftIO $ step stmt
+        return ()
+
+insert :: MonadCatchIO m
+       => String -> [String] -> [PersistValue] -> SqliteReader m Int64
+insert t cols vals = do
+    let sql = "INSERT INTO " ++ t ++
+              "(" ++ intercalate "," cols ++ ") VALUES(" ++
+              intercalate "," (map (const "?") cols) ++ ")"
+    execute sql vals
+    withStmt "SELECT last_insert_rowid()" [] $ \pop -> do
+        Just [PersistInt64 i] <- pop
+        return i
+
+tableExists :: MonadCatchIO m => String -> SqliteReader m Bool
+tableExists t = withStmt sql [PersistString t] $ \pop -> do
+    Just [PersistInt64 i] <- pop
+    return $ i == 1
+  where
+    sql = "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name=?"
+
+derivePersistSqliteReader :: EntityDef -> Q [Dec]
+derivePersistSqliteReader t = do
+    let wrap = ConT ''ReaderT `AppT` ConT ''Database
+    gs <- [|GenericSql withStmt execute insert tableExists "INTEGER PRIMARY KEY"|]
+    deriveGenericSql wrap gs t
diff --git a/Database/Sqlite.hs b/Database/Sqlite.hs
new file mode 100644
--- /dev/null
+++ b/Database/Sqlite.hs
@@ -0,0 +1,413 @@
+{-# LANGUAGE ForeignFunctionInterface, DeriveDataTypeable #-}
+-- | A port of the direct-sqlite package for dealing directly with
+-- 'PersistValue's.
+module Database.Sqlite  (
+                         Database,
+                         Statement,
+                         Error(..),
+                         StepResult(Row,
+                                    Done),
+                         open,
+                         close,
+                         prepare,
+                         step,
+                         reset,
+                         finalize,
+                         bindBlob,
+                         bindDouble,
+                         bindInt,
+                         bindInt64,
+                         bindNull,
+                         bindText,
+                         bind,
+                         column,
+                         columns
+                        )
+    where
+
+import Prelude hiding (error)
+import qualified Prelude
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Internal as BSI
+import qualified Data.ByteString.UTF8 as UTF8
+import Foreign
+import Foreign.C
+import Database.Persist (PersistValue (..))
+import Control.Concurrent.MVar
+
+newtype Database = Database (Ptr ())
+-- | The MVar is only used for insuring the statement is not double-finalized.
+-- It won't stop you from using a statement after it's been finalized.
+data Statement = Statement (Ptr ()) (MVar Bool)
+
+data Error = ErrorOK
+           | ErrorError
+           | ErrorInternal
+           | ErrorPermission
+           | ErrorAbort
+           | ErrorBusy
+           | ErrorLocked
+           | ErrorNoMemory
+           | ErrorReadOnly
+           | ErrorInterrupt
+           | ErrorIO
+           | ErrorNotFound
+           | ErrorCorrupt
+           | ErrorFull
+           | ErrorCan'tOpen
+           | ErrorProtocol
+           | ErrorEmpty
+           | ErrorSchema
+           | ErrorTooBig
+           | ErrorConstraint
+           | ErrorMismatch
+           | ErrorMisuse
+           | ErrorNoLargeFileSupport
+           | ErrorAuthorization
+           | ErrorFormat
+           | ErrorRange
+           | ErrorNotADatabase
+           | ErrorRow
+           | ErrorDone
+             deriving (Eq, Show)
+
+data StepResult = Row | Done deriving (Eq, Show)
+
+data ColumnType = IntegerColumn
+                | FloatColumn
+                | TextColumn
+                | BlobColumn
+                | NullColumn
+                  deriving (Eq, Show)
+
+decodeError :: Int -> Error
+decodeError 0 = ErrorOK
+decodeError 1 = ErrorError
+decodeError 2 = ErrorInternal
+decodeError 3 = ErrorPermission
+decodeError 4 = ErrorAbort
+decodeError 5 = ErrorBusy
+decodeError 6 = ErrorLocked
+decodeError 7 = ErrorNoMemory
+decodeError 8 = ErrorReadOnly
+decodeError 9 = ErrorInterrupt
+decodeError 10 = ErrorIO
+decodeError 11 = ErrorNotFound
+decodeError 12 = ErrorCorrupt
+decodeError 13 = ErrorFull
+decodeError 14 = ErrorCan'tOpen
+decodeError 15 = ErrorProtocol
+decodeError 16 = ErrorEmpty
+decodeError 17 = ErrorSchema
+decodeError 18 = ErrorTooBig
+decodeError 19 = ErrorConstraint
+decodeError 20 = ErrorMismatch
+decodeError 21 = ErrorMisuse
+decodeError 22 = ErrorNoLargeFileSupport
+decodeError 23 = ErrorAuthorization
+decodeError 24 = ErrorFormat
+decodeError 25 = ErrorRange
+decodeError 26 = ErrorNotADatabase
+decodeError 100 = ErrorRow
+decodeError 101 = ErrorDone
+decodeError i = Prelude.error $ "decodeError " ++ show i
+
+decodeColumnType :: Int -> ColumnType
+decodeColumnType 1 = IntegerColumn
+decodeColumnType 2 = FloatColumn
+decodeColumnType 3 = TextColumn
+decodeColumnType 4 = BlobColumn
+decodeColumnType 5 = NullColumn
+decodeColumnType i = Prelude.error $ "decodeColumnType " ++ show i
+
+foreign import ccall "sqlite3_errmsg"
+  errmsgC :: Ptr () -> IO CString
+errmsg :: Database -> IO String
+errmsg (Database database) = do
+  message <- errmsgC database
+  byteString <- BS.packCString message
+  return $ UTF8.toString byteString
+
+sqlError :: Maybe Database -> String -> Error -> IO a
+sqlError maybeDatabase functionName error = do
+  details <- case maybeDatabase of
+               Just database -> do
+                 details <- errmsg database
+                 return $ ": " ++ details
+               Nothing -> return "."
+  fail $ "SQLite3 returned " ++ (show error)
+         ++ " while attempting to perform " ++ functionName
+         ++ details
+
+foreign import ccall "sqlite3_open"
+  openC :: CString -> Ptr (Ptr ()) -> IO Int
+openError :: String -> IO (Either Database Error)
+openError path' = do
+  BS.useAsCString (UTF8.fromString path')
+                  (\path -> do
+                     alloca (\database -> do
+                               error' <- openC path database
+                               error <- return $ decodeError error'
+                               case error of
+                                 ErrorOK -> do
+                                            database' <- peek database
+                                            return $ Left $ Database database'
+                                 _ -> return $ Right error))
+open :: String -> IO Database
+open path = do
+  databaseOrError <- openError path
+  case databaseOrError of
+    Left database -> return database
+    Right error -> sqlError Nothing ("open " ++ show path) error
+
+foreign import ccall "sqlite3_close"
+  closeC :: Ptr () -> IO Int
+closeError :: Database -> IO Error
+closeError (Database database) = do
+  error <- closeC database
+  return $ decodeError error
+close :: Database -> IO ()
+close database = do
+  error <- closeError database
+  case error of
+    ErrorOK -> return ()
+    _ -> sqlError (Just database) "close" error
+
+foreign import ccall "sqlite3_prepare_v2"
+  prepareC :: Ptr () -> CString -> Int -> Ptr (Ptr ()) -> Ptr (Ptr ()) -> IO Int
+prepareError :: Database -> String -> IO (Either Statement Error)
+prepareError (Database database) text' = do
+  BS.useAsCString (UTF8.fromString text')
+                  (\text -> do
+                     alloca (\statement -> do
+                               error' <- prepareC database text (-1) statement nullPtr
+                               error <- return $ decodeError error'
+                               case error of
+                                 ErrorOK -> do
+                                            statement' <- peek statement
+                                            mvar <- newMVar True
+                                            return $ Left $ Statement statement' mvar
+                                 _ -> return $ Right error))
+prepare :: Database -> String -> IO Statement
+prepare database text = do
+  statementOrError <- prepareError database text
+  case statementOrError of
+    Left statement -> return statement
+    Right error -> sqlError (Just database) ("prepare " ++ (show text)) error
+
+foreign import ccall "sqlite3_step"
+  stepC :: Ptr () -> IO Int
+stepError :: Statement -> IO Error
+stepError (Statement statement _) = do
+  error <- stepC statement
+  return $ decodeError error
+step :: Statement -> IO StepResult
+step statement = do
+  error <- stepError statement
+  case error of
+    ErrorRow -> return Row
+    ErrorDone -> return Done
+    _ -> sqlError Nothing "step" error
+
+foreign import ccall "sqlite3_reset"
+  resetC :: Ptr () -> IO Int
+resetError :: Statement -> IO Error
+resetError (Statement statement _) = do
+  error <- resetC statement
+  return $ decodeError error
+reset :: Statement -> IO ()
+reset statement = do
+  error <- resetError statement
+  case error of
+    ErrorOK -> return ()
+    _ -> sqlError Nothing "reset" error
+
+foreign import ccall "sqlite3_finalize"
+  finalizeC :: Ptr () -> IO Int
+finalizeError :: Statement -> IO Error
+finalizeError (Statement statement mvar) = modifyMVar mvar go
+  where
+    go False = return (False, ErrorOK)
+    go True = do
+      error <- finalizeC statement
+      return (False, decodeError error)
+finalize :: Statement -> IO ()
+finalize statement = do
+  error <- finalizeError statement
+  case error of
+    ErrorOK -> return ()
+    _ -> return () -- sqlError Nothing "finalize" error
+
+foreign import ccall "sqlite3_bind_blob"
+  bindBlobC :: Ptr () -> Int -> Ptr () -> Int -> Ptr () -> IO Int
+bindBlobError :: Statement -> Int -> BS.ByteString -> IO Error
+bindBlobError (Statement statement _) parameterIndex byteString = do
+  size <- return $ BS.length byteString
+  BS.useAsCString byteString
+                  (\dataC -> do
+                     error <- bindBlobC statement parameterIndex (castPtr dataC) size
+                                        (intPtrToPtr (-1))
+                     return $ decodeError error)
+bindBlob :: Statement -> Int -> BS.ByteString -> IO ()
+bindBlob statement parameterIndex byteString = do
+  error <- bindBlobError statement parameterIndex byteString
+  case error of
+    ErrorOK -> return ()
+    _ -> sqlError Nothing "bind blob" error
+
+foreign import ccall "sqlite3_bind_double"
+  bindDoubleC :: Ptr () -> Int -> Double -> IO Int
+bindDoubleError :: Statement -> Int -> Double -> IO Error
+bindDoubleError (Statement statement _) parameterIndex datum = do
+  error <- bindDoubleC statement parameterIndex datum
+  return $ decodeError error
+bindDouble :: Statement -> Int -> Double -> IO ()
+bindDouble statement parameterIndex datum = do
+  error <- bindDoubleError statement parameterIndex datum
+  case error of
+    ErrorOK -> return ()
+    _ -> sqlError Nothing "bind double" error
+
+foreign import ccall "sqlite3_bind_int"
+  bindIntC :: Ptr () -> Int -> Int -> IO Int
+bindIntError :: Statement -> Int -> Int -> IO Error
+bindIntError (Statement statement _) parameterIndex datum = do
+  error <- bindIntC statement parameterIndex datum
+  return $ decodeError error
+bindInt :: Statement -> Int -> Int -> IO ()
+bindInt statement parameterIndex datum = do
+  error <- bindIntError statement parameterIndex datum
+  case error of
+    ErrorOK -> return ()
+    _ -> sqlError Nothing "bind int" error
+
+foreign import ccall "sqlite3_bind_int64"
+  bindInt64C :: Ptr () -> Int -> Int64 -> IO Int
+bindInt64Error :: Statement -> Int -> Int64 -> IO Error
+bindInt64Error (Statement statement _) parameterIndex datum = do
+  error <- bindInt64C statement parameterIndex datum
+  return $ decodeError error
+bindInt64 :: Statement -> Int -> Int64 -> IO ()
+bindInt64 statement parameterIndex datum = do
+  error <- bindInt64Error statement parameterIndex datum
+  case error of
+    ErrorOK -> return ()
+    _ -> sqlError Nothing "bind int64" error
+
+foreign import ccall "sqlite3_bind_null"
+  bindNullC :: Ptr () -> Int -> IO Int
+bindNullError :: Statement -> Int -> IO Error
+bindNullError (Statement statement _) parameterIndex = do
+  error <- bindNullC statement parameterIndex
+  return $ decodeError error
+bindNull :: Statement -> Int -> IO ()
+bindNull statement parameterIndex = do
+  error <- bindNullError statement parameterIndex
+  case error of
+    ErrorOK -> return ()
+    _ -> sqlError Nothing "bind null" error
+
+foreign import ccall "sqlite3_bind_text"
+  bindTextC :: Ptr () -> Int -> CString -> Int -> Ptr () -> IO Int
+bindTextError :: Statement -> Int -> String -> IO Error
+bindTextError (Statement statement _) parameterIndex text = do
+  byteString <- return $ UTF8.fromString text
+  size <- return $ BS.length byteString
+  BS.useAsCString byteString
+                  (\dataC -> do
+                     error <- bindTextC statement parameterIndex dataC size
+                                        (intPtrToPtr (-1))
+                     return $ decodeError error)
+bindText :: Statement -> Int -> String -> IO ()
+bindText statement parameterIndex text = do
+  error <- bindTextError statement parameterIndex text
+  case error of
+    ErrorOK -> return ()
+    _ -> sqlError Nothing "bind text" error
+
+bind :: Statement -> [PersistValue] -> IO ()
+bind statement sqlData = do
+  mapM_ (\(parameterIndex, datum) -> do
+          case datum of
+            PersistInt64 int64 -> bindInt64 statement parameterIndex int64
+            PersistDouble double -> bindDouble statement parameterIndex double
+            PersistBool b -> bindInt64 statement parameterIndex $
+                                if b then 1 else 0
+            PersistString text -> bindText statement parameterIndex text
+            PersistByteString blob -> bindBlob statement parameterIndex blob
+            PersistNull -> bindNull statement parameterIndex
+            PersistDay d -> bindText statement parameterIndex $ show d
+            PersistTimeOfDay d -> bindText statement parameterIndex $ show d
+            PersistUTCTime d -> bindText statement parameterIndex $ show d)
+       $ zip [1..] sqlData
+  return ()
+
+foreign import ccall "sqlite3_column_type"
+  columnTypeC :: Ptr () -> Int -> IO Int
+columnType :: Statement -> Int -> IO ColumnType
+columnType (Statement statement _) columnIndex = do
+  result <- columnTypeC statement columnIndex
+  return $ decodeColumnType result
+
+foreign import ccall "sqlite3_column_bytes"
+  columnBytesC :: Ptr () -> Int -> IO Int
+
+foreign import ccall "sqlite3_column_blob"
+  columnBlobC :: Ptr () -> Int -> IO (Ptr ())
+columnBlob :: Statement -> Int -> IO BS.ByteString
+columnBlob (Statement statement _) columnIndex = do
+  size <- columnBytesC statement columnIndex
+  BSI.create size (\resultPtr -> do
+                     dataPtr <- columnBlobC statement columnIndex
+                     if dataPtr /= nullPtr
+                        then BSI.memcpy resultPtr (castPtr dataPtr) (fromIntegral size)
+                        else return ())
+
+foreign import ccall "sqlite3_column_int64"
+  columnInt64C :: Ptr () -> Int -> IO Int64
+columnInt64 :: Statement -> Int -> IO Int64
+columnInt64 (Statement statement _) columnIndex = do
+  columnInt64C statement columnIndex
+
+foreign import ccall "sqlite3_column_double"
+  columnDoubleC :: Ptr () -> Int -> IO Double
+columnDouble :: Statement -> Int -> IO Double
+columnDouble (Statement statement _) columnIndex = do
+  columnDoubleC statement columnIndex
+
+foreign import ccall "sqlite3_column_text"
+  columnTextC :: Ptr () -> Int -> IO CString
+columnText :: Statement -> Int -> IO String
+columnText (Statement statement _) columnIndex = do
+  text <- columnTextC statement columnIndex
+  byteString <- BS.packCString text
+  return $ UTF8.toString byteString
+
+foreign import ccall "sqlite3_column_count"
+  columnCountC :: Ptr () -> IO Int
+columnCount :: Statement -> IO Int
+columnCount (Statement statement _) = do
+  columnCountC statement
+
+column :: Statement -> Int -> IO PersistValue
+column statement columnIndex = do
+  theType <- columnType statement columnIndex
+  case theType of
+    IntegerColumn -> do
+                 int64 <- columnInt64 statement columnIndex
+                 return $ PersistInt64 int64
+    FloatColumn -> do
+                 double <- columnDouble statement columnIndex
+                 return $ PersistDouble double
+    TextColumn -> do
+                 text <- columnText statement columnIndex
+                 return $ PersistString text
+    BlobColumn -> do
+                 byteString <- columnBlob statement columnIndex
+                 return $ PersistByteString byteString
+    NullColumn -> return PersistNull
+
+columns :: Statement -> IO [PersistValue]
+columns statement = do
+  count <- columnCount statement
+  mapM (\i -> column statement i) [0..count-1]
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,25 @@
+The following license covers this documentation, and the source code, except
+where otherwise indicated.
+
+Copyright 2010, Michael Snoyman. 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.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "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 HOLDERS 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.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,7 @@
+#!/usr/bin/env runhaskell
+
+> module Main where
+> import Distribution.Simple
+
+> main :: IO ()
+> main = defaultMain
diff --git a/cbits/sqlite3.c b/cbits/sqlite3.c
new file mode 100644
# file too large to diff: cbits/sqlite3.c
diff --git a/persistent-sqlite.cabal b/persistent-sqlite.cabal
new file mode 100644
--- /dev/null
+++ b/persistent-sqlite.cabal
@@ -0,0 +1,38 @@
+name:            persistent-sqlite
+version:         0.0.0
+license:         BSD3
+license-file:    LICENSE
+author:          Michael Snoyman <michael@snoyman.com>
+maintainer:      Michael Snoyman <michael@snoyman.com>
+synopsis:        Backend for the persistent library using sqlite3.
+description:     This package includes a thin sqlite3 wrapper based on the direct-sqlite package, as well as the entire C library, so there are no system dependencies.
+category:        Database
+stability:       Stable
+cabal-version:   >= 1.6
+build-type:      Simple
+homepage:        http://docs.yesodweb.com/persistent/
+
+flag nolib
+  description: Skip building the library
+  default: False
+flag buildtests
+  description: Build the executable to run unit tests
+  default: False
+
+library
+    build-depends:   base >= 4 && < 5,
+                     template-haskell >= 2.4 && < 2.5,
+                     bytestring >= 0.9.1 && < 0.10,
+                     transformers >= 0.2.1 && < 0.3,
+                     MonadCatchIO-transformers >= 0.2.2 && < 0.3,
+                     web-routes-quasi >= 0.4.0 && < 0.5,
+                     utf8-string >= 0.3.4 && < 0.4,
+                     persistent >= 0.0.0 && < 0.1
+    exposed-modules: Database.Sqlite
+                     Database.Persist.Sqlite
+    ghc-options:     -Wall
+    c-sources:       cbits/sqlite3.c
+
+source-repository head
+  type:     git
+  location: git://github.com/snoyberg/persistent.git
