diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,25 @@
 # ChangeLog for file-embed
 
+## 0.0.16.0
+
+* Add `embedFileRelative`
+
+## 0.0.15.0
+
+* Add `makeRelativeToLocationPredicate`
+
+## 0.0.14.0
+
+* Add `embedFileIfExists`
+
+## 0.0.13.0
+
+* Ensure that directory listings are returned in sorted order for reproducibility [yesodweb/yesod#1684](https://github.com/yesodweb/yesod/issues/1684)
+
+## 0.0.12.0
+
+* Use the `Bytes` literal on newer GHCs to reduce memory usage during compilation [#36](https://github.com/snoyberg/file-embed/pull/36)
+
 ## 0.0.11.2
 
 * Haddock markup fix
diff --git a/Data/FileEmbed.hs b/Data/FileEmbed.hs
--- a/Data/FileEmbed.hs
+++ b/Data/FileEmbed.hs
@@ -19,6 +19,8 @@
 module Data.FileEmbed
     ( -- * Embed at compile time
       embedFile
+    , embedFileRelative
+    , embedFileIfExists
     , embedOneFileOf
     , embedDir
     , embedDirListing
@@ -38,6 +40,7 @@
     , injectFileWith
       -- * Relative path manipulation
     , makeRelativeToProject
+    , makeRelativeToLocationPredicate
       -- * Internal
     , stringToBs
     , bsToExp
@@ -46,11 +49,7 @@
 
 import Language.Haskell.TH.Syntax
     ( Exp (AppE, ListE, LitE, TupE, SigE, VarE)
-#if MIN_VERSION_template_haskell(2,5,0)
-    , Lit (StringL, StringPrimL, IntegerL)
-#else
-    , Lit (StringL, IntegerL)
-#endif
+    , Lit (..)
     , Q
     , runIO
     , qLocation, loc_filename
@@ -58,19 +57,26 @@
     , Quasi(qAddDependentFile)
 #endif
     )
+#if MIN_VERSION_template_haskell(2,16,0)
+import Language.Haskell.TH ( mkBytes, bytesPrimL )
+import qualified Data.ByteString.Internal as B
+#endif
 import System.Directory (doesDirectoryExist, doesFileExist,
                          getDirectoryContents, canonicalizePath)
-import Control.Exception (throw, ErrorCall(..))
-import Control.Monad (filterM)
+import Control.Exception (throw, tryJust, ErrorCall(..))
+import Control.Monad ((<=<), filterM, guard)
 import qualified Data.ByteString as B
 import qualified Data.ByteString.Char8 as B8
 import Control.Arrow ((&&&), second)
 import Control.Applicative ((<$>))
 import Data.ByteString.Unsafe (unsafePackAddressLen)
+import System.IO.Error (isDoesNotExistError)
 import System.IO.Unsafe (unsafePerformIO)
 import System.FilePath ((</>), takeDirectory, takeExtension)
 import Data.String (fromString)
 import Prelude as P
+import Data.List (sortBy)
+import Data.Ord (comparing)
 
 -- | Embed a single file in your source code.
 --
@@ -85,6 +91,39 @@
 #endif
   (runIO $ B.readFile fp) >>= bsToExp
 
+-- | Embed a single file in your source code.
+--   Unlike 'embedFile', path is given relative to project root.
+-- @since 0.0.16.0
+embedFileRelative :: FilePath -> Q Exp
+embedFileRelative = embedFile <=< makeRelativeToProject
+
+-- | Maybe embed a single file in your source code depending on whether or not file exists.
+--
+-- Warning: When a build is compiled with the file missing, a recompile when the file exists might not trigger an embed of the file.
+-- You might try to fix this by doing a clean build.
+--
+-- > import qualified Data.ByteString
+-- >
+-- > maybeMyFile :: Maybe Data.ByteString.ByteString
+-- > maybeMyFile = $(embedFileIfExists "dirName/fileName")
+--
+-- @since 0.0.14.0
+embedFileIfExists :: FilePath -> Q Exp
+embedFileIfExists fp = do
+  mbs <- runIO maybeFile
+  case mbs of
+    Nothing -> [| Nothing |]
+    Just bs -> do
+#if MIN_VERSION_template_haskell(2,7,0)
+      qAddDependentFile fp
+#endif
+      [| Just $(bsToExp bs) |]
+  where
+    maybeFile :: IO (Maybe B.ByteString)
+    maybeFile = 
+      either (const Nothing) Just <$> 
+      tryJust (guard . isDoesNotExistError) (B.readFile fp)
+
 -- | Embed a single existing file in your source code
 -- out of list a list of paths supplied.
 --
@@ -155,7 +194,11 @@
     return $ VarE 'unsafePerformIO
       `AppE` (VarE 'unsafePackAddressLen
       `AppE` LitE (IntegerL $ fromIntegral $ B8.length bs)
-#if MIN_VERSION_template_haskell(2, 8, 0)
+#if MIN_VERSION_template_haskell(2, 16, 0)
+      `AppE` LitE (bytesPrimL (
+                let B.PS ptr off sz = bs
+                in  mkBytes ptr (fromIntegral off) (fromIntegral sz))))
+#elif MIN_VERSION_template_haskell(2, 8, 0)
       `AppE` LitE (StringPrimL $ B.unpack bs))
 #else
       `AppE` LitE (StringPrimL $ B8.unpack bs))
@@ -230,7 +273,7 @@
              mapM (liftPair2 . second B.readFile)
     dirs <- filterM (doesDirectoryExist . snd) all' >>=
             mapM (fileList' realTop . fst)
-    return $ concat $ files : dirs
+    return $ sortBy (comparing fst) $ concat $ files : dirs
 
 liftPair2 :: Monad m => (a, m b) -> m (a, b)
 liftPair2 (a, b) = b >>= \b' -> return (a, b')
@@ -373,7 +416,19 @@
 --
 -- @since 0.0.10
 makeRelativeToProject :: FilePath -> Q FilePath
-makeRelativeToProject rel = do
+makeRelativeToProject = makeRelativeToLocationPredicate $ (==) ".cabal" . takeExtension
+
+-- | Take a predicate to infer the project root and a relative file path, the given file path is then attached to the inferred project root
+--
+-- This function looks at the source location of the Haskell file calling it,
+-- finds the first parent directory with a file matching the given predicate, and uses that as the
+-- root directory for fixing the relative path.
+--
+-- @$(makeRelativeToLocationPredicate ((==) ".cabal" . takeExtension) "data/foo.txt" >>= embedFile)@
+--
+-- @since 0.0.15.0
+makeRelativeToLocationPredicate :: (FilePath -> Bool) -> FilePath -> Q FilePath
+makeRelativeToLocationPredicate isTargetFile rel = do
     loc <- qLocation
     runIO $ do
         srcFP <- canonicalizePath $ loc_filename loc
@@ -388,8 +443,6 @@
             then return Nothing
             else do
                 contents <- getDirectoryContents dir
-                if any isCabalFile contents
+                if any isTargetFile contents
                     then return (Just dir)
                     else findProjectDir dir
-
-    isCabalFile fp = takeExtension fp == ".cabal"
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,8 +1,6 @@
 ## file-embed
 
-[![Build Status](https://travis-ci.org/snoyberg/file-embed.svg?branch=master)](https://travis-ci.org/snoyberg/file-embed)
-[![Build status](https://ci.appveyor.com/api/projects/status/vlgo8uudpt374uoy/branch/master?svg=true)](https://ci.appveyor.com/project/snoyberg/file-embed/branch/master)
-
+![Tests](https://github.com/snoyberg/file-embed/workflows/Tests/badge.svg)
 
 Use Template Haskell to read a file or all the files in a directory, and turn
 them into (path, bytestring) pairs embedded in your haskell code.
diff --git a/file-embed.cabal b/file-embed.cabal
--- a/file-embed.cabal
+++ b/file-embed.cabal
@@ -1,6 +1,6 @@
 name:            file-embed
-version:         0.0.11.2
-license:         BSD3
+version:         0.0.16.0
+license:         BSD2
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>
 maintainer:      Michael Snoyman <michael@snoyman.com>
@@ -10,7 +10,7 @@
                  embedded in your Haskell code.
 category:        Data
 stability:       Stable
-cabal-version:   >= 1.8
+cabal-version:   >= 1.10
 build-type:      Simple
 homepage:        https://github.com/snoyberg/file-embed
 extra-source-files: test/main.hs, test/sample/foo, test/sample/bar/baz,
@@ -18,6 +18,7 @@
                     README.md
 
 library
+    default-language: Haskell2010
     build-depends:   base               >= 4.9.1   && < 5
                    , bytestring         >= 0.9.1.4
                    , directory          >= 1.0.0.3
@@ -27,10 +28,12 @@
     ghc-options:     -Wall
 
 test-suite test
+    default-language: Haskell2010
     type: exitcode-stdio-1.0
     main-is: main.hs
     hs-source-dirs: test
     build-depends: base
+                 , bytestring
                  , file-embed
                  , filepath
 
diff --git a/test/main.hs b/test/main.hs
--- a/test/main.hs
+++ b/test/main.hs
@@ -2,6 +2,7 @@
 {-# LANGUAGE OverloadedStrings #-}
 
 import Control.Monad (unless)
+import qualified Data.ByteString as B (ByteString, filter)
 import Data.FileEmbed
 import System.FilePath ((</>))
 
@@ -14,8 +15,14 @@
 main = do
     let received = $(embedDir "test/sample")
     received @?=
-        [ ("foo", "foo\r\n")
-        , ("bar" </> "baz", "baz\r\n")
+        [ ("bar" </> "baz", "baz\r\n")
+        , ("foo", "foo\r\n")
         ]
     let str = $(embedStringFile "test/sample/foo") :: String
     filter (/= '\r') str @?= "foo\n"
+
+    let mbs = $(embedFileIfExists "test/sample/foo")
+    fmap (B.filter (/= fromIntegral (fromEnum '\r'))) mbs @?= Just "foo\n"
+
+    let mbs2 = $(embedFileIfExists "test/sample/foo2") :: Maybe B.ByteString
+    mbs2 @?= Nothing
