diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,7 @@
+## 1.1.14
+
+* `sinkFileCautious`
+
 ## 1.1.13.3
 
 * `withCheckedProcessCleanup` properly closes opened `Handle`s
diff --git a/Data/Conduit/Binary.hs b/Data/Conduit/Binary.hs
--- a/Data/Conduit/Binary.hs
+++ b/Data/Conduit/Binary.hs
@@ -22,6 +22,7 @@
     , sourceHandleRangeWithBuffer
       -- ** Sinks
     , sinkFile
+    , sinkFileCautious
     , sinkHandle
     , sinkIOHandle
       -- ** Conduits
@@ -80,6 +81,11 @@
 #ifndef ALLOW_UNALIGNED_ACCESS
 import Foreign.Marshal (alloca, copyBytes)
 #endif
+import System.Directory (renameFile)
+import System.FilePath (takeDirectory, takeFileName, (<.>))
+import System.IO (hClose, openBinaryTempFile)
+import Control.Exception (throwIO, catch)
+import System.IO.Error (isDoesNotExistError)
 
 -- | Stream the contents of a file as binary data.
 --
@@ -244,6 +250,38 @@
          => FilePath
          -> Consumer S.ByteString m ()
 sinkFile fp = sinkIOHandle (IO.openBinaryFile fp IO.WriteMode)
+
+-- | Cautious version of 'sinkFile'. The idea here is to stream the
+-- values to a temporary file in the same directory of the destination
+-- file, and only on successfully writing the entire file, moves it
+-- atomically to the destination path.
+--
+-- In the event of an exception occurring, the temporary file will be
+-- deleted and no move will be made. If the application shuts down
+-- without running exception handling (such as machine failure or a
+-- SIGKILL), the temporary file will remain and the destination file
+-- will be untouched.
+--
+-- @since 1.1.14
+sinkFileCautious
+  :: MonadResource m
+  => FilePath
+  -> ConduitM S.ByteString o m ()
+sinkFileCautious fp =
+    bracketP acquire cleanup inner
+  where
+    acquire = openBinaryTempFile (takeDirectory fp) (takeFileName fp <.> "tmp")
+    cleanup (tmpFP, h) = do
+        hClose h
+        removeFile tmpFP `catch` \e ->
+            if isDoesNotExistError e
+                then return ()
+                else throwIO e
+    inner (tmpFP, h) = do
+        sinkHandle h
+        liftIO $ do
+            hClose h
+            renameFile tmpFP fp
 
 -- | Stream the contents of the input to a file, and also send it along the
 -- pipeline. Similar in concept to the Unix command @tee@.
diff --git a/Data/Conduit/Process.hs b/Data/Conduit/Process.hs
--- a/Data/Conduit/Process.hs
+++ b/Data/Conduit/Process.hs
@@ -3,8 +3,8 @@
 {-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE CPP #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
--- | A full tutorial for this module is available on FP School of Haskell:
--- <https://www.fpcomplete.com/user/snoyberg/library-documentation/data-conduit-process>.
+-- | A full tutorial for this module is available at:
+-- <https://github.com/snoyberg/conduit/blob/master/PROCESS.md>.
 --
 -- Note that this is a very thin layer around the @Data.Streaming.Process@ module. In particular, it:
 --
diff --git a/conduit-extra.cabal b/conduit-extra.cabal
--- a/conduit-extra.cabal
+++ b/conduit-extra.cabal
@@ -1,5 +1,5 @@
 Name:                conduit-extra
-Version:             1.1.13.3
+Version:             1.1.14
 Synopsis:            Batteries included conduit: adapters for common libraries.
 Description:
     The conduit package itself maintains relative small dependencies. The purpose of this package is to collect commonly used utility functions wrapping other library dependencies, without depending on heavier-weight dependencies. The basic idea is that this package should only depend on haskell-platform packages and conduit.
diff --git a/test/Data/Conduit/BinarySpec.hs b/test/Data/Conduit/BinarySpec.hs
--- a/test/Data/Conduit/BinarySpec.hs
+++ b/test/Data/Conduit/BinarySpec.hs
@@ -157,6 +157,22 @@
                 lbs' `shouldBe` lbs
                 fromIntegral len `shouldBe` L.length lbs'
 
+    describe "sinkFileCautious" $ do
+      it' "success" $ do
+        runResourceT $ CB.sourceFile "conduit-extra.cabal" C.$$ CB.sinkFileCautious "tmp"
+        bs1 <- S.readFile "conduit-extra.cabal"
+        bs2 <- S.readFile "tmp"
+        bs2 `shouldBe` bs1
+      it' "failure" $ do
+        let bs1 = "This is the original content"
+        S.writeFile "tmp" bs1
+        runResourceT
+               ( (CB.sourceFile "conduit-extra.cabal" >> error "FIXME")
+            C.$$ CB.sinkFileCautious "tmp")
+               `shouldThrow` anyException
+        bs2 <- S.readFile "tmp"
+        bs2 `shouldBe` bs1
+
     describe "Data.Conduit.Binary.mapM_" $ do
         prop "telling works" $ \bytes ->
             let lbs = L.pack bytes
