diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2014 Hirotomo Moriwaki
+
+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/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/apiary-memcached.cabal b/apiary-memcached.cabal
new file mode 100644
--- /dev/null
+++ b/apiary-memcached.cabal
@@ -0,0 +1,35 @@
+name:                apiary-memcached
+version:             0.17.0.0
+synopsis:            memcached client for apiary web framework.
+-- description:
+license:             MIT
+license-file:        LICENSE
+author:              HirotomoMoriwaki<philopon.dependence@gmail.com>
+maintainer:          HirotomoMoriwaki<philopon.dependence@gmail.com>
+Homepage:            https://github.com/philopon/apiary
+Bug-reports:         https://github.com/philopon/apiary/issues
+copyright:           (c) 2014 Hirotomo Moriwaki
+category:            Web
+build-type:          Simple
+stability:           experimental
+-- extra-source-files:  
+cabal-version:       >=1.10
+
+library
+  exposed-modules:     Web.Apiary.Memcached
+  other-modules:       
+  build-depends:       base               >=4.6   && <4.8
+                     , apiary             >=0.17  && <0.18
+                     , memcached-binary   >=0.1   && <0.3
+                     , data-default-class >=0.0   && <0.1
+                     , binary             >=0.7   && <0.8
+                     , text               >=1.1   && <1.3
+                     , transformers       >=0.3   && <0.5
+                     , monad-control      >=0.3   && <0.4
+  hs-source-dirs:      src
+  ghc-options:         -O2 -Wall
+  default-language:    Haskell2010
+
+source-repository head
+  type:     git
+  location: git://github.com/philopon/apiary.git
diff --git a/src/Web/Apiary/Memcached.hs b/src/Web/Apiary/Memcached.hs
new file mode 100644
--- /dev/null
+++ b/src/Web/Apiary/Memcached.hs
@@ -0,0 +1,133 @@
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE Rank2Types #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module Web.Apiary.Memcached
+    ( Memcached, CacheConfig(..), MemcachedConfig(..)
+    -- * initializer
+    , initMemcached, initHerokuMemcached
+
+    -- * raw query
+    , memcached
+
+    -- * cache
+    , cache, cacheMaybe
+    ) where
+
+import Web.Apiary
+import Web.Apiary.Heroku
+
+import Control.Applicative
+import Control.Monad.Trans.Maybe
+import Control.Monad.Trans.Control
+
+import Data.Default.Class
+import Data.Apiary.Extension
+import Data.Apiary.Proxy
+import qualified Data.Binary as B
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as T
+import qualified Data.Text.Read as T
+
+import Database.Memcached.Binary.IO
+import qualified Database.Memcached.Binary.Maybe as Maybe
+
+data Memcached = Memcached Connection MemcachedConfig
+
+data CacheConfig = CacheConfig
+    { cacheFlags        :: Key -> Flags
+    , cacheExpiry       :: Expiry
+    , cacheNotHitExpiry :: Expiry
+    }
+
+instance Default CacheConfig where
+    def = CacheConfig (\_ -> 0) 0 0
+
+data MemcachedConfig = MemcachedConfig
+    { connectInfo :: ConnectInfo
+    , cacheConfig :: Maybe CacheConfig
+    }
+
+instance Default MemcachedConfig where
+    def = MemcachedConfig def Nothing
+
+initMemcached :: MonadBaseControl IO m => MemcachedConfig -> Initializer' m Memcached
+initMemcached cfg = initializerBracket' $ \m -> control $ \run -> 
+    withConnection (connectInfo cfg) (\c -> run $ m (Memcached c cfg))
+
+getHerokuConfig :: T.Text -> MemcachedConfig -> Heroku -> MaybeT IO MemcachedConfig
+getHerokuConfig pfx ci exts = do
+    svr <- MaybeT $ getHerokuEnv' (pfx `T.append` "_SERVERS")  exts
+    usr <- liftIO $ getHerokuEnv' (pfx `T.append` "_USERNAME") exts
+    pwd <- liftIO $ getHerokuEnv' (pfx `T.append` "_PASSWORD") exts
+
+    let (hst, prtTxt) = T.breakOnEnd ":" svr
+    prt <- either fail (return . fst) $ T.decimal prtTxt
+
+    let auth = Plain <$> (T.encodeUtf8 <$> usr) <*> (T.encodeUtf8 <$> pwd)
+
+    return ci {connectInfo = (connectInfo ci)
+        { connectHost = T.unpack $ T.init hst
+        , connectPort = PortNumber prt
+        , connectAuth =
+            maybe id (\a -> (a:)) auth $ connectAuth (connectInfo ci)
+        }}
+
+-- | initialize memcached extension using heroku service.
+--
+-- compatile:
+--
+-- * Memcachier
+-- * Memcache cloud
+--
+initHerokuMemcached :: (Has Heroku exts, MonadBaseControl IO m)
+                    => MemcachedConfig -> Initializer m exts (Memcached ': exts)
+initHerokuMemcached cfg = initializerBracket $ \exts m -> control $ \run -> do
+    let hc = getExtension Proxy exts
+    cfg'  <- fmap (maybe cfg id) . runMaybeT $
+        getHerokuConfig "MEMCACHIER"     cfg hc <|>
+        getHerokuConfig "MEMCACHEDCLOUD" cfg hc
+    withConnection (connectInfo cfg') (\c -> run $ m (Memcached c cfg'))
+
+memcached :: (Has Memcached exts, MonadIO m)
+          => (Connection -> IO a) -> ActionT exts m a
+memcached q = do
+    Memcached conn _ <- getExt Proxy
+    liftIO $ q conn
+
+cache :: (MonadIO m, Has Memcached exts)
+      => Key -> ActionT exts m Value -> ActionT exts m Value
+cache key actn = do
+    Memcached conn cfg <- getExt Proxy
+    case cacheConfig cfg of
+        Nothing -> actn
+        Just cc -> liftIO (Maybe.get_ key conn) >>= \case
+            Just cr -> return cr
+            Nothing -> do
+                ar <- actn
+                liftIO $ set (cacheFlags cc key)
+                    (cacheExpiry cc) key ar conn
+                return ar
+
+cacheMaybe :: (MonadIO m, Has Memcached exts)
+           => Key -> ActionT exts m (Maybe Value)
+           -> ActionT exts m (Maybe Value)
+cacheMaybe key actn = do
+    Memcached conn cfg <- getExt Proxy
+    case cacheConfig cfg of
+        Nothing -> actn
+        Just cc -> liftIO (Maybe.get_ key conn) >>= \case
+            Just cr -> return $ B.decode cr
+            Nothing -> actn >>= \case
+                Nothing -> do
+                    liftIO $ set (cacheFlags cc key)
+                        (cacheNotHitExpiry cc) key (B.encode (Nothing :: Maybe Value)) conn
+                    return Nothing
+                Just ar -> do
+                    liftIO $ set (cacheFlags cc key)
+                        (cacheExpiry cc) key (B.encode $ Just ar) conn
+                    return (Just ar)
