diff --git a/lzma-conduit.cabal b/lzma-conduit.cabal
--- a/lzma-conduit.cabal
+++ b/lzma-conduit.cabal
@@ -1,5 +1,5 @@
 name:                lzma-conduit
-version:             0.4.2
+version:             0.5.2
 synopsis:            Conduit interface for lzma/xz compression.
 description:
   High level bindings to xz-utils.
@@ -30,7 +30,7 @@
     base              >= 3      && < 5,
     bindings-DSL      >= 1.0    && < 1.1,
     bytestring        >= 0.9.1  && < 0.10,
-    conduit           == 0.4.*,
+    conduit           >= 0.4    && < 0.6,
     resourcet         == 0.3.*,
     transformers      >= 0.2    && < 0.4
   ghc-options:
diff --git a/src/Data/Conduit/Lzma.hs b/src/Data/Conduit/Lzma.hs
--- a/src/Data/Conduit/Lzma.hs
+++ b/src/Data/Conduit/Lzma.hs
@@ -3,7 +3,7 @@
 
 module Data.Conduit.Lzma (compress, decompress) where
 
-import Control.Monad (forM_, liftM2)
+import Control.Monad (forM_)
 import Control.Monad.IO.Class (liftIO)
 import Control.Monad.Trans.Class (lift)
 import Control.Monad.Trans.Resource
@@ -74,7 +74,8 @@
   -> Ptr C'lzma_stream
   -> IO C'lzma_ret
 easyEncoder level ptr =
-  c'lzma_easy_encoder ptr (maybe c'LZMA_PRESET_DEFAULT fromIntegral level) c'LZMA_CHECK_CRC64
+  let level' = maybe c'LZMA_PRESET_DEFAULT fromIntegral level
+  in c'lzma_easy_encoder ptr level' c'LZMA_CHECK_CRC64
 
 autoDecoder
   :: Maybe Word64
@@ -88,94 +89,112 @@
   :: (MonadResource m)
   => Maybe Word64 -- ^ Memory limit, in bytes.
   -> Conduit ByteString m ByteString
-decompress memlimit = NeedInput initPush (return ()) where
-  initPush input = do
-    (_, streamPtr) <- lift $ allocate
-      (initStream "lzma_auto_decoder" (autoDecoder memlimit))
-      (\ ptr -> c'lzma_end ptr >> free ptr)
-    codeEnum streamPtr input
+decompress memlimit = do
+  mval <- await
+  case mval of
+    Just input -> do
+      (streamKey, streamPtr) <- lift $ allocate
+        (initStream "lzma_auto_decoder" (autoDecoder memlimit))
+        (\ ptr -> c'lzma_end ptr >> free ptr)
+      codeEnum streamKey streamPtr input
 
+    Nothing -> return ()
+
 -- | Compress a 'ByteString' into a xz container stream.
 compress
   :: (MonadResource m)
   => Maybe Int -- ^ Compression level from [0..9], defaults to 6.
   -> Conduit ByteString m ByteString
-compress level = NeedInput initPush (return ()) where
-  initPush input = do
-    (_, streamPtr) <- lift $ allocate
-      (initStream "lzma_easy_encoder" (easyEncoder level))
-      (\ ptr -> c'lzma_end ptr >> free ptr)
-    codeEnum streamPtr input
+compress level = do
+  mval <- await
+  case mval of
+    Just input -> do
+      (streamKey, streamPtr) <- lift $ allocate
+        (initStream "lzma_easy_encoder" (easyEncoder level))
+        (\ ptr -> c'lzma_end ptr >> free ptr)
+      codeEnum streamKey streamPtr input
 
+    Nothing -> return ()
+
 lzmaConduit
   :: (MonadResource m)
-  => Ptr C'lzma_stream
+  => ReleaseKey
+  -> Ptr C'lzma_stream
   -> Conduit ByteString m ByteString
-lzmaConduit =
-  liftM2 NeedInput codeEnum lzmaClose
+lzmaConduit streamKey streamPtr = do
+  mval <- await
+  case mval of
+    Just val -> codeEnum streamKey streamPtr val
+    Nothing  -> lzmaClose streamKey streamPtr
 
 lzmaClose
   :: (MonadResource m)
-  => Ptr C'lzma_stream
+  => ReleaseKey
+  -> Ptr C'lzma_stream
   -> Conduit ByteString m ByteString
-lzmaClose streamPtr =
-  buildChunks streamPtr c'LZMA_FINISH c'LZMA_OK
+lzmaClose streamKey streamPtr =
+  buildChunks streamKey streamPtr c'LZMA_FINISH c'LZMA_OK
 
 codeEnum
   :: (MonadResource m)
-  => Ptr C'lzma_stream
+  => ReleaseKey
+  -> Ptr C'lzma_stream
   -> ByteString
   -> Conduit B.ByteString m B.ByteString
-codeEnum streamPtr chunk@(PS fptr _ _) = do
+codeEnum streamKey streamPtr chunk@(PS fptr _ _) = do
   liftIO $ do
     -- let the bytestring library calculate the chunk length
     (ptr, len) <- B.unsafeUseAsCStringLen chunk return
     pokeNextIn streamPtr ptr
     pokeAvailIn streamPtr $ fromIntegral len
 
-  buildChunks streamPtr c'LZMA_RUN c'LZMA_OK
+  buildChunks streamKey streamPtr c'LZMA_RUN c'LZMA_OK
   liftIO $ touchForeignPtr fptr
 
 buildChunks
   :: (MonadResource m)
-  => Ptr C'lzma_stream
+  => ReleaseKey
+  -> Ptr C'lzma_stream
   -> C'lzma_action
   -> C'lzma_ret
   -> Conduit B.ByteString m B.ByteString
-buildChunks streamPtr action status = do
+buildChunks streamKey streamPtr action status = do
   availIn <- liftIO $ peekAvailIn streamPtr
   availOut <- liftIO $ peekAvailOut streamPtr
-  codeStep streamPtr action status availIn availOut
+  codeStep streamKey streamPtr action status availIn availOut
 
 codeStep
   :: (MonadResource m)
-  => Ptr C'lzma_stream
+  => ReleaseKey
+  -> Ptr C'lzma_stream
   -> C'lzma_action
   -> C'lzma_ret
   -> CSize
   -> CSize
   -> Conduit B.ByteString m B.ByteString
-codeStep streamPtr action status availIn availOut
+codeStep streamKey streamPtr action status availIn availOut
   -- the inner enumerator has finished and we're done flushing the coder
-  | availOut == bufferSize && status == c'LZMA_STREAM_END =
-      Done Nothing () 
+  | availOut == bufferSize && status == c'LZMA_STREAM_END = do
+      lift $ release streamKey
+      return ()
 
   -- the normal case, we have some results..
   | availOut < bufferSize = do
       x <- liftIO $ getChunk streamPtr availOut
-      HaveOutput (buildChunks streamPtr action status) (return ()) x
+      yield x
+      buildChunks streamKey streamPtr action status
 
   -- the input buffer points into a pinned bytestring, so we need to make sure it's been
   -- fully loaded (availIn == 0) before returning
   | availIn > 0 || action == c'LZMA_FINISH = do
       ret <- liftIO $ c'lzma_code streamPtr action
       if ret == c'LZMA_OK || ret == c'LZMA_STREAM_END
-        then buildChunks streamPtr action ret
+        then buildChunks streamKey streamPtr action ret
         else fail $ "lzma_code failed: " ++ prettyRet ret
 
   -- nothing to do here
   | otherwise =
-      lzmaConduit streamPtr
+      lzmaConduit streamKey streamPtr
 
 getChunk
   :: Ptr C'lzma_stream
@@ -194,4 +213,3 @@
 
   | otherwise =
       return B.empty
-
