diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,7 @@
+## 0.1.0.3
+
+* Allow uploading directories as well, see [Reddit discussion](http://www.reddit.com/r/haskell/comments/344dig/announcing_stackageupload/cqr6mvv)
+
 ## 0.1.0.2
 
 * Improved README
diff --git a/Stackage/Upload.hs b/Stackage/Upload.hs
--- a/Stackage/Upload.hs
+++ b/Stackage/Upload.hs
@@ -55,11 +55,21 @@
 import           Network.HTTP.Client.TLS               (tlsManagerSettings)
 import           Network.HTTP.Types                    (statusCode)
 import           System.Directory                      (createDirectoryIfMissing,
+                                                        doesDirectoryExist,
+                                                        doesFileExist,
                                                         getAppUserDataDirectory,
+                                                        getDirectoryContents,
                                                         removeFile)
-import           System.FilePath                       ((</>))
-import           System.IO                             (hFlush, hGetEcho,
-                                                        hSetEcho, stdin, stdout)
+import           System.Exit                           (ExitCode (ExitSuccess))
+import           System.FilePath                       (takeExtension, (</>))
+import           System.IO                             (hClose, hFlush,
+                                                        hGetEcho, hSetEcho,
+                                                        stdin, stdout)
+import           System.IO.Temp                        (withSystemTempDirectory)
+import           System.Process                        (StdStream (CreatePipe),
+                                                        createProcess, cwd,
+                                                        proc, std_in,
+                                                        waitForProcess)
 
 -- | Username and password to log into Hackage.
 --
@@ -190,7 +200,7 @@
             , checkStatus = \_ _ _ -> Nothing
             }
     return Uploader
-        { upload_ = \fp -> do
+        { upload_ = \fp0 -> withTarball fp0 $ \fp -> do
             let formData = [partFile "package" fp]
             req2 <- formDataBody formData req1
             let req3 = applyBasicAuth
@@ -222,6 +232,29 @@
                         printBody res
                         error $ "Upload failed on " ++ fp
         }
+
+-- | Given either a file, return it. Given a directory, run @cabal sdist@ and
+-- get the resulting tarball.
+withTarball :: FilePath -> (FilePath -> IO a) -> IO a
+withTarball fp0 inner = do
+    isFile <- doesFileExist fp0
+    if isFile then inner fp0 else withSystemTempDirectory "stackage-upload-tarball" $ \dir -> do
+        isDir <- doesDirectoryExist fp0
+        when (not isDir) $ error $ "Invalid argument: " ++ fp0
+
+        (Just h, Nothing, Nothing, ph) <-
+            createProcess $ (proc "cabal" ["sdist", "--builddir=" ++ dir])
+                { cwd = Just fp0
+                , std_in = CreatePipe
+                }
+        hClose h
+        ec <- waitForProcess ph
+        when (ec /= ExitSuccess) $
+            error $ "Could not create tarball for " ++ fp0
+        contents <- getDirectoryContents dir
+        case filter ((== ".gz") . takeExtension) contents of
+            [x] -> inner (dir </> x)
+            _ -> error $ "Unexpected directory contents after cabal sdist: " ++ show contents
 
 printBody :: Response BodyReader -> IO ()
 printBody res =
diff --git a/app/stackage-upload.hs b/app/stackage-upload.hs
--- a/app/stackage-upload.hs
+++ b/app/stackage-upload.hs
@@ -9,10 +9,10 @@
     (files, ()) <- simpleOptions
         $(simpleVersion version)
         "Secure upload of packages to Hackage"
-        "Secure upload of packages to Hackage"
+        "Specifying a directory will cause cabal sdist to be run in that directory"
         options
         empty
     uploader <- mkUploader defaultUploadSettings
     mapM_ (upload uploader) files
   where
-    options = some (argument str (metavar "TARBALLS..."))
+    options = some (argument str (metavar "TARBALLS/DIRECTORIES..."))
diff --git a/stackage-upload.cabal b/stackage-upload.cabal
--- a/stackage-upload.cabal
+++ b/stackage-upload.cabal
@@ -1,5 +1,5 @@
 name:                stackage-upload
-version:             0.1.0.2
+version:             0.1.0.3
 synopsis:            A more secure version of cabal upload which uses HTTPS
 description:         For more information, see <https://www.stackage.org/package/stackage-upload>
 homepage:            https://github.com/fpco/stackage-upload
@@ -23,6 +23,8 @@
                      , http-types
                      , directory       >= 1.1
                      , filepath        >= 1.2
+                     , process         >= 1
+                     , temporary       >= 1.2
   default-language:    Haskell2010
 
 executable stackage-upload
