diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,9 @@
 # ChangeLog for conduit
 
+## 1.3.3
+
+* Add `uncons`, `unconsM`, `unconsEither`, `unconsEitherM`.
+
 ## 1.3.2.1
 
 * Fix isChunksForExactlyE [#445](https://github.com/snoyberg/conduit/issues/445) [#446](https://github.com/snoyberg/conduit/pull/446)
diff --git a/conduit.cabal b/conduit.cabal
--- a/conduit.cabal
+++ b/conduit.cabal
@@ -1,5 +1,5 @@
 Name:                conduit
-Version:             1.3.2.1
+Version:             1.3.3
 Synopsis:            Streaming data processing library.
 description:
     `conduit` is a solution to the streaming data problem, allowing for production,
diff --git a/src/Data/Conduit/Internal.hs b/src/Data/Conduit/Internal.hs
--- a/src/Data/Conduit/Internal.hs
+++ b/src/Data/Conduit/Internal.hs
@@ -14,6 +14,7 @@
                                                 leftover, mapInput, mapInputM,
                                                 mapOutput, mapOutputMaybe,
                                                 transPipe,
-                                                yield, yieldM)
+                                                yield, yieldM,
+                                                unconsM, unconsEitherM)
 import           Data.Conduit.Internal.Pipe
 import           Data.Conduit.Internal.Fusion
diff --git a/src/Data/Conduit/Internal/Conduit.hs b/src/Data/Conduit/Internal/Conduit.hs
--- a/src/Data/Conduit/Internal/Conduit.hs
+++ b/src/Data/Conduit/Internal/Conduit.hs
@@ -38,6 +38,8 @@
     , runConduitRes
     , fuse
     , connect
+    , unconsM
+    , unconsEitherM
       -- ** Composition
     , connectResume
     , connectResumeConduit
@@ -106,7 +108,7 @@
 import Data.Monoid (Monoid (mappend, mempty))
 import Data.Semigroup (Semigroup ((<>)))
 import Control.Monad.Trans.Resource
-import Data.Conduit.Internal.Pipe hiding (yield, mapOutput, leftover, yieldM, await, awaitForever, bracketP)
+import Data.Conduit.Internal.Pipe hiding (yield, mapOutput, leftover, yieldM, await, awaitForever, bracketP, unconsM, unconsEitherM)
 import qualified Data.Conduit.Internal.Pipe as CI
 import Control.Monad (forever)
 import Data.Traversable (Traversable (..))
@@ -719,6 +721,40 @@
         -> ConduitT a Void m r
         -> m r
 connect = ($$)
+
+-- | Split a conduit into head and tail.
+--
+-- Note that you have to 'sealConduitT' it first.
+--
+-- Since 1.3.3
+unconsM :: Monad m
+        => SealedConduitT () o m ()
+        -> m (Maybe (o, SealedConduitT () o m ()))
+unconsM (SealedConduitT p) = go p
+  where
+    -- This function is the same as @Pipe.unconsM@ but it ignores leftovers.
+    go (HaveOutput p o) = pure $ Just (o, SealedConduitT p)
+    go (NeedInput _ c) = go $ c ()
+    go (Done ()) = pure Nothing
+    go (PipeM mp) = mp >>= go
+    go (Leftover p ()) = go p
+
+-- | Split a conduit into head and tail or return its result if it is done.
+--
+-- Note that you have to 'sealConduitT' it first.
+--
+-- Since 1.3.3
+unconsEitherM :: Monad m
+              => SealedConduitT () o m r
+              -> m (Either r (o, SealedConduitT () o m r))
+unconsEitherM (SealedConduitT p) = go p
+  where
+    -- This function is the same as @Pipe.unconsEitherM@ but it ignores leftovers.
+    go (HaveOutput p o) = pure $ Right (o, SealedConduitT p)
+    go (NeedInput _ c) = go $ c ()
+    go (Done r) = pure $ Left r
+    go (PipeM mp) = mp >>= go
+    go (Leftover p ()) = go p
 
 -- | Named function synonym for '.|'
 --
diff --git a/src/Data/Conduit/Internal/Pipe.hs b/src/Data/Conduit/Internal/Pipe.hs
--- a/src/Data/Conduit/Internal/Pipe.hs
+++ b/src/Data/Conduit/Internal/Pipe.hs
@@ -18,6 +18,8 @@
     , yield
     , yieldM
     , leftover
+    , unconsM
+    , unconsEitherM
       -- ** Finalization
     , bracketP
       -- ** Composition
@@ -270,6 +272,34 @@
 leftover = Leftover (Done ())
 {-# INLINE [1] leftover #-}
 {-# RULES "conduit: leftover l >> p" forall l (p :: Pipe l i o u m r). leftover l >> p = Leftover p l #-}
+
+-- | Split a pipe into head and tail.
+--
+-- Since 1.3.3
+unconsM :: Monad m
+        => Pipe Void () o () m ()
+        -> m (Maybe (o, Pipe Void () o () m ()))
+unconsM = go
+  where
+    go (HaveOutput p o) = pure $ Just (o, p)
+    go (NeedInput _ c) = go $ c ()
+    go (Done ()) = pure Nothing
+    go (PipeM mp) = mp >>= go
+    go (Leftover _ i) = absurd i
+
+-- | Split a pipe into head and tail or return its result if it is done.
+--
+-- Since 1.3.3
+unconsEitherM :: Monad m
+              => Pipe Void () o () m r
+              -> m (Either r (o, Pipe Void () o () m r))
+unconsEitherM = go
+  where
+    go (HaveOutput p o) = pure $ Right (o, p)
+    go (NeedInput _ c) = go $ c ()
+    go (Done r) = pure $ Left r
+    go (PipeM mp) = mp >>= go
+    go (Leftover _ i) = absurd i
 
 -- | Bracket a pipe computation between allocation and release of a resource.
 -- We guarantee, via the @MonadResource@ context, that the resource
diff --git a/src/Data/Conduit/List.hs b/src/Data/Conduit/List.hs
--- a/src/Data/Conduit/List.hs
+++ b/src/Data/Conduit/List.hs
@@ -15,8 +15,8 @@
 -- sort of \"black box\", where there is no introspection of the contained
 -- elements. Values such as @ByteString@ and @Text@ will likely need to be
 -- treated specially to deal with their contents properly (@Word8@ and @Char@,
--- respectively). See the "Data.Conduit.Binary" and "Data.Conduit.Text"
--- modules.
+-- respectively). See the @Data.Conduit.Binary@ and @Data.Conduit.Text@
+-- modules in the @conduit-extra@ package.
 module Data.Conduit.List
     ( -- * Sources
       sourceList
@@ -33,6 +33,8 @@
       -- ** Pure
     , fold
     , foldMap
+    , uncons
+    , unconsEither
     , take
     , drop
     , head
@@ -42,6 +44,8 @@
       -- ** Monadic
     , foldMapM
     , foldM
+    , unconsM
+    , unconsEitherM
     , mapM_
       -- * Conduits
       -- ** Pure
@@ -95,9 +99,11 @@
 import Data.Monoid (Monoid, mempty, mappend)
 import qualified Data.Foldable as F
 import Data.Conduit
+import Data.Conduit.Internal.Conduit (unconsM, unconsEitherM)
 import Data.Conduit.Internal.Fusion
 import Data.Conduit.Internal.List.Stream
 import qualified Data.Conduit.Internal as CI
+import Data.Functor.Identity (Identity (runIdentity))
 import Control.Monad (when, (<=<), liftM, void)
 import Control.Monad.Trans.Class (lift)
 
@@ -179,6 +185,26 @@
             Right (a, seed') -> yield a >> go seed'
             Left r -> return r
 STREAMING(unfoldEitherM, unfoldEitherMC, unfoldEitherMS, f seed)
+
+-- | Split a pure conduit into head and tail.
+-- This is equivalent to @runIdentity . unconsM@.
+--
+-- Note that you have to 'sealConduitT' it first.
+--
+-- Since 1.3.3
+uncons :: SealedConduitT () o Identity ()
+       -> Maybe (o, SealedConduitT () o Identity ())
+uncons = runIdentity . unconsM
+
+-- | Split a pure conduit into head and tail or return its result if it is done.
+-- This is equivalent to @runIdentity . unconsEitherM@.
+--
+-- Note that you have to 'sealConduitT' it first.
+--
+-- Since 1.3.3
+unconsEither :: SealedConduitT () o Identity r
+             -> Either r (o, SealedConduitT () o Identity r)
+unconsEither = runIdentity . unconsEitherM
 
 -- | Yield the values from the list.
 --
diff --git a/test/main.hs b/test/main.hs
--- a/test/main.hs
+++ b/test/main.hs
@@ -24,6 +24,7 @@
 import Control.Monad.ST (runST)
 import Data.Monoid
 import qualified Data.IORef as I
+import Data.Tuple (swap)
 import Control.Monad.Trans.Resource (allocate, resourceForkIO)
 import Control.Concurrent (threadDelay, killThread)
 import Control.Monad.IO.Class (liftIO)
@@ -52,7 +53,17 @@
 equivToList f conduit xs =
   f xs == runConduitPure (CL.sourceList xs .| conduit .| CL.consume)
 
+-- | Check that two conduits produce the same outputs and return the same result.
+bisimilarTo :: (Eq a, Eq r) => ConduitT () a Identity r -> ConduitT () a Identity r -> Bool
+left `bisimilarTo` right =
+    C.runConduitPure (toListRes left) == C.runConduitPure (toListRes right)
+  where
+    -- | Sink a conduit into a list and return it alongside the result.
+    -- So it is, essentially, @sinkList@ plus result.
+    toListRes :: Monad m => ConduitT () a m r -> ConduitT () Void m ([a], r)
+    toListRes cond = swap <$> C.fuseBoth cond CL.consume
 
+
 main :: IO ()
 main = hspec $ do
     describe "Combinators" Spec.spec
@@ -165,6 +176,28 @@
             x <- runConduit $ CL.unfoldM (return . f) seed .| CL.consume
             let y = DL.unfoldr f seed
             x `shouldBe` y
+
+    describe "uncons" $ do
+        prop "folds to list" $ \xs ->
+          let src = C.sealConduitT $ CL.sourceList xs in
+          (xs :: [Int]) == DL.unfoldr CL.uncons src
+
+        prop "works with unfold" $ \xs ->
+          let src = CL.sourceList xs in
+          CL.unfold CL.uncons (C.sealConduitT src) `bisimilarTo` (src :: ConduitT () Int Identity ())
+
+    describe "unconsEither" $ do
+        let
+          eitherToMaybe :: Either l a -> Maybe a
+          eitherToMaybe (Left _) = Nothing
+          eitherToMaybe (Right a) = Just a
+        prop "folds outputs to list" $ \xs ->
+          let src = C.sealConduitT $ CL.sourceList xs in
+          (xs :: [Int]) == DL.unfoldr (eitherToMaybe . CL.unconsEither) src
+
+        prop "works with unfoldEither" $ \(xs, r) ->
+          let src = CL.sourceList xs *> pure r in
+          CL.unfoldEither CL.unconsEither (C.sealConduitT src) `bisimilarTo` (src :: ConduitT () Int Identity Int)
 
     describe "Monoid instance for Source" $ do
         it "mappend" $ do
