diff --git a/Yesod/Fay.hs b/Yesod/Fay.hs
--- a/Yesod/Fay.hs
+++ b/Yesod/Fay.hs
@@ -83,6 +83,7 @@
 import           Data.Aeson                 (decode)
 import qualified Data.ByteString.Lazy       as L
 import qualified Data.ByteString.Lazy.UTF8  as BSU
+import           Data.Data                  (Data)
 import           Data.Default               (def)
 import           Data.Digest.Pure.MD5       (md5)
 import           Data.List                  (isPrefixOf)
@@ -90,6 +91,7 @@
 import           Data.Monoid                ((<>), mempty)
 import           Data.Text                  (pack, unpack)
 import qualified Data.Text                  as T
+import qualified Data.Text.IO               as T
 import qualified Data.Text.Lazy             as TL
 import           Data.Text.Encoding         (encodeUtf8)
 import qualified Data.Text.Lazy.Encoding as TLE
@@ -151,6 +153,13 @@
     -- >     fayRoute = FaySiteR
     fayRoute :: Route FaySite -> Route master
 
+    -- | User-defined function specifying how to encode data as json for fay.
+    --
+    --   Most users won't need to define this, the default is @const showToFay@.
+    --   Custom definitions will usually be in terms of 'encodeFay'.
+    fayEncode :: (Show a, Data a) => master -> a -> Maybe Value
+    fayEncode = const showToFay
+
 -- | A function provided by the developer describing how to answer individual
 -- commands from client-side code.
 --
@@ -164,7 +173,7 @@
 -- and produces the expected result.
 type CommandHandler master
     = forall s.
-      (forall a. Show a => Returns a -> a -> HandlerT master IO s)
+      (forall a. (Show a, Data a) => Returns a -> a -> HandlerT master IO s)
    -> Value
    -> HandlerT master IO s
 
@@ -179,10 +188,11 @@
     -- ^ Note that the server call functions provided for your Fay code require
     -- jQuery to be present. If you disable this option and still use the
     -- provided server call functions, your code will break.
+    , yfsPackages        :: [String]
     }
 
 yesodFaySettings :: String -> YesodFaySettings
-yesodFaySettings moduleName = YesodFaySettings moduleName Nothing return Nothing True
+yesodFaySettings moduleName = YesodFaySettings moduleName Nothing return Nothing True []
 
 updateRuntime :: FilePath -> IO ()
 updateRuntime fp = getRuntime >>= \js -> createTree (directory $ decodeString fp) >> copyFile js fp
@@ -194,7 +204,7 @@
 getFaySite :: a -> FaySite
 getFaySite _ = FaySite
 
-postFayCommandR :: YesodFay master => HandlerT FaySite (HandlerT master IO) Value
+postFayCommandR :: forall master. YesodFay master => HandlerT FaySite (HandlerT master IO) Value
 postFayCommandR =
     lift $ runCommandHandler yesodFayCommand
   where
@@ -211,7 +221,9 @@
                     Nothing -> error $ "Unable to parse input: " ++ show txt
                     Just cmd -> f go cmd
       where
-        go Returns = returnJson . showToFay
+        go Returns value = do
+          master <- getYesod
+          returnJson $ fayEncode master value -- FIXME what should we do for Nothing values?
 
 langYesodFay :: String
 langYesodFay = $(qRunIO $ fmap (LitE . StringL . unpack) $ readTextFile "Language/Fay/Yesod.hs")
@@ -269,7 +281,6 @@
       packageConf <- fmap (lookup "HASKELL_PACKAGE_SANDBOX") getEnvironment
       result <- compileFileWithState conf {
           configPackageConf = packageConf
-
         } fp
       case result of
         Left e -> return (Left e)
@@ -303,17 +314,14 @@
       fp_o = dir ++ guid ++ ".o"
       refresh = return $ Left (fp_hi,fp_o)
   createDirectoryIfMissing True dir
-  exists <- doesFileExist fp_hi
-  if not exists
-     then refresh
-     else do thisModTime <- getModificationTime fp_o
-             modules <- fmap ((fp :) . lines) (readFile fp_hi)
-             changed <- anyM (fmap (> thisModTime) . getModificationTime) modules
-             if changed
-                then refresh
-                else catch (fmap Right (readFile fp_o))
-                           (\(_ :: IOException) ->
-                             refresh)
+  catch (do thisModTime <- getModificationTime fp_o
+            modules <- fmap ((fp :) . lines . T.unpack) (T.readFile fp_hi)
+            changed <- anyM (fmap (> thisModTime) . getModificationTime) modules
+            if changed
+               then refresh
+               else fmap (Right . T.unpack) (T.readFile fp_o))
+        -- If any IO exceptions occur at this point, just invalidate the cache.
+        (\(_ :: IOException) -> refresh)
 
 -- | Does a full compile of the Fay code via GHC for type checking, and then
 -- embeds the Fay-generated Javascript as a static string. File changes during
@@ -325,6 +333,7 @@
     qRunIO writeYesodFay
     eres <- qRunIO $ compileFayFile fp config
         { configExportRuntime = exportRuntime
+        , configPackages = packages
         }
     case eres of
         Left e -> error $ "Unable to compile Fay module \"" ++ name ++ "\": " ++ show e
@@ -353,6 +362,7 @@
   where
     name = yfsModuleName settings
     exportRuntime = isNothing (yfsSeparateRuntime settings)
+    packages = yfsPackages settings
     fp = mkfp name
 
 config :: CompileConfig
@@ -373,6 +383,7 @@
         liftIO (compileFayFile (mkfp name) config
                 { configTypecheck = False
                 , configExportRuntime = exportRuntime
+                , configPackages = packages
 #if MIN_VERSION_fay(0, 19, 0)
                 , configSourceMap = True
 #endif
@@ -387,3 +398,4 @@
   where
     name = yfsModuleName settings
     exportRuntime = isNothing (yfsSeparateRuntime settings)
+    packages = yfsPackages settings
diff --git a/yesod-fay.cabal b/yesod-fay.cabal
--- a/yesod-fay.cabal
+++ b/yesod-fay.cabal
@@ -2,7 +2,7 @@
 -- documentation, see http://haskell.org/cabal/users-guide/
 
 name:                yesod-fay
-version:             0.4.0.7
+version:             0.5.0
 synopsis:            Utilities for using the Fay Haskell-to-JS compiler with Yesod.
 description:         For initial discussion, see <http://www.yesodweb.com/blog/2012/10/yesod-fay-js>. This is a work-in-progress.
 homepage:            https://github.com/fpco/yesod-fay
@@ -31,6 +31,7 @@
                      , template-haskell
                      , process
                      , shakespeare-js >= 1.0.2
+                     , shakespeare
                      , yesod-core >= 1.2
                      , yesod-form >= 1.2
                      , yesod-static >= 1.2
