diff --git a/bibdb.cabal b/bibdb.cabal
--- a/bibdb.cabal
+++ b/bibdb.cabal
@@ -1,5 +1,5 @@
 name:                bibdb
-version:             0.4.2
+version:             0.5.2
 category:            Text
 synopsis:            A database based bibliography manager for BibTeX
 homepage:            https://github.com/cacay/bibdb
@@ -74,10 +74,12 @@
                         bibtex >= 0.1.0.6 && < 0.2,
                         parsec == 3.1.*,
                         curl >= 1.3 && < 2.0,
-                        download-curl >= 0.1.4 && < 0.2
+                        download-curl >= 0.1.4 && < 0.2,
+                        async >= 2.1 && < 3
 
   default-extensions:   PatternGuards,
                         ScopedTypeVariables,
+                        FlexibleContexts
                         MultiParamTypeClasses
 
   other-extensions:     FlexibleInstances
diff --git a/src/Database/ArXiv.hs b/src/Database/ArXiv.hs
--- a/src/Database/ArXiv.hs
+++ b/src/Database/ArXiv.hs
@@ -7,6 +7,9 @@
 -----------------------------------------------------------------------------
 module Database.ArXiv (fetchString) where
 
+import Control.Monad.Except
+import Control.Monad.IO.Class (MonadIO (..))
+
 import qualified Data.ByteString.Char8 as ByteString
 
 import Network.Curl.Download (openURIWithOpts)
@@ -18,7 +21,7 @@
 import Utility.Except
 
 
-fetchString :: BibSize -> SourceKey -> Exception String
+fetchString :: (MonadError String m, MonadIO m) => BibSize -> SourceKey -> m String
 fetchString size key = do
   res <- liftIO $ openURIWithOpts headers (getUrl size key)
   bs <- liftEither res
diff --git a/src/Database/Dblp.hs b/src/Database/Dblp.hs
--- a/src/Database/Dblp.hs
+++ b/src/Database/Dblp.hs
@@ -7,6 +7,9 @@
 -----------------------------------------------------------------------------
 module Database.Dblp (fetchString) where
 
+import Control.Monad.Except
+import Control.Monad.IO.Class (MonadIO (..))
+
 import Network.Curl.Download (openURIString)
 
 import Args (BibSize (..))
@@ -15,7 +18,7 @@
 import Utility.Except
 
 
-fetchString :: BibSize -> SourceKey -> Exception String
+fetchString :: (MonadError String m, MonadIO m) => BibSize -> SourceKey -> m String
 fetchString size key = do
   res <- liftIO $ openURIString (getUrl size key)
   liftEither res
diff --git a/src/Database/Doi.hs b/src/Database/Doi.hs
--- a/src/Database/Doi.hs
+++ b/src/Database/Doi.hs
@@ -7,6 +7,9 @@
 -----------------------------------------------------------------------------
 module Database.Doi (fetchString) where
 
+import Control.Monad.Except
+import Control.Monad.IO.Class (MonadIO (..))
+
 import qualified Data.ByteString.Char8 as ByteString
 
 import Network.Curl.Download (openURIWithOpts)
@@ -18,7 +21,7 @@
 import Utility.Except
 
 
-fetchString :: BibSize -> SourceKey -> Exception String
+fetchString :: (MonadError String m, MonadIO m) => BibSize -> SourceKey -> m String
 fetchString size key = do
   res <- liftIO $ openURIWithOpts headers (getUrl size key)
   bs <- liftEither res
diff --git a/src/Database/Fetch.hs b/src/Database/Fetch.hs
--- a/src/Database/Fetch.hs
+++ b/src/Database/Fetch.hs
@@ -8,6 +8,10 @@
 -----------------------------------------------------------------------------
 module Database.Fetch (fetch, fetchAll) where
 
+import Control.Concurrent.Async
+import Control.Monad.Except
+import Control.Monad.IO.Class (MonadIO (..))
+
 import Args (BibSize)
 import Reference
 
@@ -19,7 +23,7 @@
 import Utility.Except
 
 
-fetch :: BibSize -> Source -> Exception (RefIdent, [BibTeX])
+fetch :: (MonadError String m, MonadIO m) => BibSize -> Source -> m (RefIdent, [BibTeX])
 fetch size source@(Source t key) = do
   liftIO $ putStrLn $ "Fetching " ++ show source
   bibstr <- fetchString size key
@@ -28,7 +32,7 @@
     Right bibtex@(h : _) -> return (bibIdent h, bibtex)
     Right _ -> throwError $ "Error: empty response from server"
   where
-    fetchString :: BibSize -> SourceKey -> Exception String
+    fetchString :: (MonadError String m, MonadIO m) => BibSize -> SourceKey -> m String
     fetchString = case t of
       Doi -> Doi.fetchString
       Dblp -> Dblp.fetchString
@@ -41,9 +45,10 @@
     inriaToHalKey (SourceKey key) = SourceKey ("inria-" ++ key)
 
 
-fetchAll :: BibSize -> [Source] -> Exception ([RefIdent], [BibTeX])
+fetchAll :: (MonadError String m, MonadIO m) => BibSize -> [Source] -> m ([RefIdent], [BibTeX])
 fetchAll size srcs = do
-  results <- mapM (fetch size) srcs
+  maybeResults <- liftIO $ mapConcurrently (runExceptT . fetch size) srcs
+  results <- liftEither $ sequence maybeResults
   let (idents, bibs) = unzip results
   return (idents, concat bibs)
 
diff --git a/src/Database/Hal.hs b/src/Database/Hal.hs
--- a/src/Database/Hal.hs
+++ b/src/Database/Hal.hs
@@ -7,6 +7,9 @@
 -----------------------------------------------------------------------------
 module Database.Hal (fetchString) where
 
+import Control.Monad.Except
+import Control.Monad.IO.Class (MonadIO (..))
+
 import qualified Data.ByteString.Char8 as ByteString
 
 import Network.Curl.Download (openURIWithOpts)
@@ -18,7 +21,7 @@
 import Utility.Except
 
 
-fetchString :: BibSize -> SourceKey -> Exception String
+fetchString :: (MonadError String m, MonadIO m) => BibSize -> SourceKey -> m String
 fetchString size key = do
   res <- liftIO $ openURIWithOpts headers (getUrl size key)
   bs <- liftEither res
diff --git a/src/Main.hs b/src/Main.hs
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -7,9 +7,12 @@
 -----------------------------------------------------------------------------
 module Main (main) where
 
+import Control.Monad (when)
+import Control.Monad.Except
+import Control.Monad.IO.Class (MonadIO (..))
+
 import Data.Function (on)
 import Data.Maybe (fromMaybe)
-import Control.Monad (when)
 import System.Exit (exitFailure, exitSuccess)
 import System.FilePath (replaceExtension)
 
@@ -44,7 +47,7 @@
       Options.<> Options.header "Bibdb bibliography manager"
       )
 
-runJob :: Args.Job -> Exception ()
+runJob :: (MonadError String m, MonadIO m) => Args.Job -> m ()
 runJob job = do
   bib <- liftIO $ BS.readFile (Args.jobSource job)
 
@@ -67,7 +70,7 @@
 
   let renames = zip ids (map Parser.entryIdent entries)
   let final = bibliography renames database
-  let msg = "Automatically generated file. DO NOT MODIFY!\n"
+  let msg = "Automatically generated by bibdb. DO NOT MODIFY!\n"
   liftIO $ writeFile outputFile (msg ++ "\n" ++ renderList final)
 
   where
@@ -75,13 +78,13 @@
     outputFile = fromMaybe def (Args.jobOutput job)
       where def = replaceExtension (Args.jobSource job) "bib"
 
-    save :: Pretty a => String -> [a] -> ExceptT String IO ()
+    save :: (Pretty a, MonadError String m, MonadIO m) => String -> [a] -> m ()
     save extension es | Args.jobKeepIntermediate job =
       let out = replaceExtension outputFile extension
       in liftIO $ writeFile out (renderList es)
     save _ _ = return ()
 
-    printAndExit :: Pretty a => [a] -> ExceptT String IO ()
+    printAndExit :: (Pretty a, MonadError String m, MonadIO m) => [a] -> m ()
     printAndExit es = do
       liftIO $ putStrLn $ renderList es
       liftIO exitSuccess
@@ -92,13 +95,14 @@
 
 -- | Check that all elements of a list are distinct. Uses the given
 -- function to extract the key to compare on.
-checkDuplicatesOn :: forall key e . (Ord key, Pretty key, Located e)
+checkDuplicatesOn :: forall key e m . (Ord key, Pretty key, Located e, MonadError String m)
                   => (e -> key)     -- ^ Extract a key to compare on
                   -> [e]            -- ^ List of inputs
-                  -> Exception ()
-checkDuplicatesOn key es = case map duplicateError (duplicates es) of
-  [] -> return ()
-  errs -> throwError $ render $ vcat errs
+                  -> m ()
+checkDuplicatesOn key es =
+  case map duplicateError (duplicates es) of
+    [] -> return ()
+    errs -> throwError $ render $ vcat errs
   where
     -- Find duplicates
     duplicates :: [e] -> [[e]]
diff --git a/src/Utility/Except.hs b/src/Utility/Except.hs
--- a/src/Utility/Except.hs
+++ b/src/Utility/Except.hs
@@ -6,19 +6,13 @@
 -- Stability   : experimental
 -----------------------------------------------------------------------------
 module Utility.Except
-  ( module Control.Monad.Except
-  , MonadIO (..)
-  , Exception
-  , liftEither
+  ( liftEither
   ) where
-import Control.Monad.Except
-import Control.Monad.IO.Class (MonadIO (..))
 
-
-type Exception = ExceptT String IO
+import Control.Monad.Except
 
 
-liftEither :: Monad m => Either e a -> ExceptT e m a
+liftEither :: (MonadError e m) => Either e a -> m a
 liftEither (Left e) = throwError e
 liftEither (Right a) = return a
 
