diff --git a/antiope-sqs.cabal b/antiope-sqs.cabal
--- a/antiope-sqs.cabal
+++ b/antiope-sqs.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 74ba06bfe1d37c4c34a6da3917aa0e9c374b22d422195ab12413209c50610437
+-- hash: 610f11f14be9dc0bcd0ae1fa042fa11947b032a11fc8d912735aeb73fb2093c8
 
 name:           antiope-sqs
-version:        6.2.0
+version:        6.3.0
 description:    Please see the README on Github at <https://github.com/arbor/antiope#readme>
 category:       Services
 homepage:       https://github.com/arbor/antiope#readme
@@ -40,10 +40,12 @@
     , antiope-messages
     , antiope-s3
     , base >=4.7 && <5
+    , conduit
     , generic-lens
     , lens
     , lens-aeson
     , monad-loops
+    , mtl
     , network-uri
     , text
     , unliftio-core
@@ -70,10 +72,12 @@
     , antiope-s3
     , antiope-sqs
     , base >=4.7 && <5
+    , conduit
     , generic-lens
     , lens
     , lens-aeson
     , monad-loops
+    , mtl
     , network-uri
     , text
     , unliftio-core
diff --git a/src/Antiope/SQS.hs b/src/Antiope/SQS.hs
--- a/src/Antiope/SQS.hs
+++ b/src/Antiope/SQS.hs
@@ -6,15 +6,19 @@
   , ackMessage
   , ackMessages
   , mBody
+  , queueSource
   ) where
 
-import Antiope.Messages    (QueueUrl (QueueUrl), SQSError (DeleteMessageBatchError))
+import Antiope.Messages         (QueueUrl (QueueUrl), SQSError (DeleteMessageBatchError))
 import Control.Lens
-import Control.Monad       (join)
-import Control.Monad.Loops (unfoldWhileM)
-import Data.Maybe          (catMaybes)
-import Data.Text           (pack)
-import Network.AWS         (MonadAWS)
+import Control.Monad            (join)
+import Control.Monad.Loops      (unfoldWhileM)
+import Control.Monad.Trans      (lift)
+import Data.Conduit
+import Data.Conduit.Combinators (yieldMany)
+import Data.Maybe               (catMaybes)
+import Data.Text                (pack)
+import Network.AWS              (MonadAWS)
 import Network.AWS.SQS
 
 import qualified Network.AWS as AWS
@@ -34,12 +38,14 @@
   -> m [Message]
 drainQueue queueUrl = join <$> unfoldWhileM (not . null) (readQueue queueUrl)
 
+-- | Acknowledges a single SQS message
 ackMessage :: MonadAWS m
   => QueueUrl
   -> Message
   -> m (Either SQSError ())
 ackMessage q msg = ackMessages q [msg]
 
+-- | Acknowledges a group of SQS messages
 ackMessages :: MonadAWS m
   => QueueUrl
   -> [Message]
@@ -55,3 +61,12 @@
         [] -> return $ Right ()
         _  -> return $ Left DeleteMessageBatchError
     else return $ Left DeleteMessageBatchError
+
+-- | Reads from an SQS indefinitely, producing messages into a conduit
+queueSource :: MonadAWS m => QueueUrl -> ConduitT () Message m ()
+queueSource (QueueUrl queueUrl) = do
+  m <- lift $ AWS.send $ receiveMessage queueUrl & rmWaitTimeSeconds ?~ 10 & rmMaxNumberOfMessages ?~ 10
+  yieldMany (m ^. rmrsMessages)
+  queueSource (QueueUrl queueUrl)
+
+
