diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,13 @@
+# ChangeLog for yesod-static
+
+## 1.6.1.0
+
+* Support reproducible embedded file order [#1684](https://github.com/yesodweb/yesod/issues/1684#issuecomment-652562514)
+
+## 1.6.0.2
+
+* Remove unnecessary deriving of Typeable
+
 ## 1.6.0.1
 
 * Make test suite build with GHC 8.6 [#1561](https://github.com/yesodweb/yesod/pull/1561)
diff --git a/Yesod/EmbeddedStatic/Generators.hs b/Yesod/EmbeddedStatic/Generators.hs
--- a/Yesod/EmbeddedStatic/Generators.hs
+++ b/Yesod/EmbeddedStatic/Generators.hs
@@ -49,6 +49,7 @@
 import System.Exit (ExitCode (ExitSuccess))
 import Control.Concurrent.Async (Concurrently (..))
 import System.IO (hClose)
+import Data.List (sort)
 
 import Yesod.EmbeddedStatic.Types
 
@@ -80,7 +81,7 @@
                      -> FilePath   -- ^ The prefix to add to the filenames
                      -> IO [(Location,FilePath)]
 getRecursiveContents prefix topdir = do
-  names <- getDirectoryContents topdir
+  names <- sort <$> getDirectoryContents topdir
   let properNames = filter (`notElem` [".", ".."]) names
   paths <- forM properNames $ \name -> do
     let path = topdir </> name
diff --git a/Yesod/Static.hs b/Yesod/Static.hs
--- a/Yesod/Static.hs
+++ b/Yesod/Static.hs
@@ -71,7 +71,7 @@
 import Yesod.Core
 import Yesod.Core.Types
 
-import Data.List (intercalate)
+import Data.List (intercalate, sort)
 import Language.Haskell.TH
 import Language.Haskell.TH.Syntax as TH
 
@@ -192,7 +192,7 @@
        -> ([String] -> [String])
        -> StateT (M.Map String String) IO [[String]]
     go fp front = do
-        allContents <- liftIO $ filter notHidden `fmap` getDirectoryContents fp
+        allContents <- liftIO $ (sort . filter notHidden) `fmap` getDirectoryContents fp
         let fullPath :: String -> String
             fullPath f = fp ++ '/' : f
         files <- liftIO $ filterM (doesFileExist . fullPath) allContents
diff --git a/test/GeneratorTestUtil.hs b/test/GeneratorTestUtil.hs
--- a/test/GeneratorTestUtil.hs
+++ b/test/GeneratorTestUtil.hs
@@ -8,6 +8,7 @@
 import Test.HUnit
 import Yesod.EmbeddedStatic.Types as Y
 import qualified Data.ByteString.Lazy as BL
+import RIO (HasCallStack)
 
 -- We test the generators by executing them at compile time
 -- and sticking the result into the GenTestResult.  We then
@@ -28,12 +29,16 @@
 testEntry _ loc _ e  | ebLocation e /= loc =
     [| GenError ("location " ++ $(litE $ stringL $ show $ ebLocation e)) |]
 testEntry _ _ act e = do
-    expected <- runIO act
-    actual <- runIO $ ebProductionContent e
+    expected <- fmap stripCR $ runIO act
+    actual <- fmap stripCR $ runIO $ ebProductionContent e
     if expected == actual
         then [| GenSuccessWithDevel $(ebDevelReload e) |]
-        else [| GenError "production content" |]
+        else [| GenError $ "production content: " ++ $(litE $ stringL $ show (expected, actual)) |]
 
+-- | Remove all carriage returns, for Windows testing
+stripCR :: BL.ByteString -> BL.ByteString
+stripCR = BL.filter (/= 13)
+
 testOneEntry :: Maybe String -> Y.Location -> IO BL.ByteString -> [Entry] -> ExpQ
 testOneEntry name loc ct [e] = testEntry name loc ct e
 testOneEntry _ _ _ _ = [| GenError "not exactly one entry" |]
@@ -48,12 +53,13 @@
         f (name, loc, ct) e = testEntry name loc ct e
 
 -- | Use this at runtime to assert the 'GenTestResult' is OK
-assertGenResult :: (IO BL.ByteString) -- ^ expected development content
+assertGenResult :: HasCallStack
+                => (IO BL.ByteString) -- ^ expected development content
                 -> GenTestResult -- ^ test result created at compile time
                 -> Assertion
 assertGenResult _ (GenError e) = assertFailure ("invalid " ++ e)
 assertGenResult mexpected (GenSuccessWithDevel mactual) = do
-    expected <- mexpected
-    actual <- mactual
+    expected <- fmap stripCR mexpected
+    actual <- fmap stripCR mactual
     when (expected /= actual) $
-        assertFailure "invalid devel content"
+        assertFailure $ "invalid devel content: " ++ show (expected, actual)
diff --git a/yesod-static.cabal b/yesod-static.cabal
--- a/yesod-static.cabal
+++ b/yesod-static.cabal
@@ -1,5 +1,5 @@
 name:            yesod-static
-version:         1.6.0.1
+version:         1.6.1.0
 license:         MIT
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>
@@ -7,7 +7,7 @@
 synopsis:        Static file serving subsite for Yesod Web Framework.
 category:        Web, Yesod
 stability:       Stable
-cabal-version:   >= 1.8
+cabal-version:   >= 1.10
 build-type:      Simple
 homepage:        http://www.yesodweb.com/
 description:     API docs and the README are available at <http://www.stackage.org/package/yesod-static>
@@ -26,7 +26,8 @@
   README.md
 
 library
-    build-depends:   base                  >= 4        && < 5
+    default-language: Haskell2010
+    build-depends:   base                  >= 4.10     && < 5
                    , async
                    , attoparsec            >= 0.10
                    , base64-bytestring     >= 0.1.0.1
@@ -66,9 +67,10 @@
                      Yesod.EmbeddedStatic.Css.Util
 
     ghc-options:     -Wall
-    extensions: TemplateHaskell
+    other-extensions: TemplateHaskell
 
 test-suite tests
+    default-language: Haskell2010
     hs-source-dirs: ., test
     main-is: tests.hs
     type: exitcode-stdio-1.0
@@ -115,9 +117,10 @@
                    , wai
                    , wai-app-static
                    , yesod-core
+                   , rio
 
     ghc-options:     -Wall -threaded
-    extensions: TemplateHaskell
+    other-extensions: TemplateHaskell
 
 source-repository head
   type:     git
