diff --git a/Yst/Sqlite3.hs b/Yst/Sqlite3.hs
--- a/Yst/Sqlite3.hs
+++ b/Yst/Sqlite3.hs
@@ -5,7 +5,6 @@
 import Database.HDBC.Sqlite3
 import Data.Maybe
 import Yst.Types
-import Yst.Util (parseAsDate)
 
 readSqlite3 :: FilePath -> String -> IO Node
 readSqlite3 filename query = do
diff --git a/Yst/Types.hs b/Yst/Types.hs
--- a/Yst/Types.hs
+++ b/Yst/Types.hs
@@ -20,9 +20,14 @@
 module Yst.Types
 where
 import Data.Char
+import qualified Data.HashMap.Strict as H
 import Data.Time
+import qualified Data.Text as T
 import Text.StringTemplate
+import Data.Aeson
 import qualified Data.Map as M
+import System.Locale (defaultTimeLocale)
+import Control.Monad
 
 data Site = Site {
     siteTitle     :: String
@@ -50,29 +55,6 @@
   , pageInMenu    :: Bool
   } deriving (Show, Read, Eq)
 
-data NavNode = NavPage String String
-             | NavMenu String [NavNode]
-             deriving (Show, Read, Eq)
-
-data Node = NString String
-          | NDate Day
-          | NList [Node]
-          | NMap [(String, Node)]
-          | NNil
-          deriving (Show, Read, Eq)
-
-instance Ord Node where
-  compare (NString x) (NString y)   = compare x y
-  compare (NDate x) (NDate y)       = compare x y
-  compare (NList x) (NList y)       = compare x y
-  compare (NMap x) (NMap y)         = compare x y
-  compare NNil NNil                 = EQ
-  compare (NList x) y               = compare (NList x) (NList [y])
-  compare x (NList y)               = compare (NList [x]) (NList y)
-  compare (NString _) _             = GT
-  compare (NDate _) _               = GT
-  compare _ _                       = GT
-
 data DataSpec = DataConstant Node
               | DataFromFile FilePath [DataOption]
               | DataFromSqlite3 FilePath String [DataOption]
@@ -103,6 +85,58 @@
                 | TestContains
                 deriving (Show, Read, Eq)
 
+data NavNode = NavPage String String
+             | NavMenu String [NavNode]
+             deriving (Show, Read, Eq)
+
+data Node = NString String
+          | NDate Day
+          | NList [Node]
+          | NMap [(String, Node)]
+          | NNil
+          deriving (Show, Read, Eq)
+
+instance Ord Node where
+  compare (NString x) (NString y)   = compare x y
+  compare (NDate x) (NDate y)       = compare x y
+  compare (NList x) (NList y)       = compare x y
+  compare (NMap x) (NMap y)         = compare x y
+  compare NNil NNil                 = EQ
+  compare (NList x) y               = compare (NList x) (NList [y])
+  compare x (NList y)               = compare (NList [x]) (NList y)
+  compare (NString _) _             = GT
+  compare (NDate _) _               = GT
+  compare _ _                       = GT
+
+instance FromJSON Node where
+  parseJSON (String t) = do
+    let t' = T.unpack t
+    case parseAsDate t' of
+         Nothing -> return $ NString t'
+         Just d  -> return $ NDate d
+  parseJSON (Object h) = case fromJSON (Object $ handleMerges h) of
+                                Success y -> return $ NMap $ M.toList y
+                                _         -> mzero
+  parseJSON x@(Array _) = case fromJSON x of
+                               Success y -> return $ NList y
+                               _         -> mzero
+  parseJSON (Bool b) = return $ NString $ show b
+  parseJSON (Number y) = return $ NString $ show y
+  parseJSON _ = return $ NNil
+
+handleMerges :: H.HashMap T.Text Value -> H.HashMap T.Text Value
+handleMerges = H.foldrWithKey go H.empty
+  where go k (Object h) m | isMerge k = H.foldrWithKey go m h
+        go k v m = H.insert k v m
+        isMerge k = k == T.pack "<<"
+
+instance ToJSON Node where
+  toJSON (NDate s) = toJSON (NString $ formatTime defaultTimeLocale "%x" s)
+  toJSON (NString s) = toJSON s
+  toJSON (NMap xs) = toJSON $ M.fromList xs
+  toJSON (NList xs) = toJSON xs
+  toJSON (NNil) = toJSON ()
+
 data SortDirection = Ascending | Descending deriving (Show, Read, Eq)
 
 data Format = HtmlFormat
@@ -135,3 +169,9 @@
          NList xs    -> toSElem xs
          NMap xs     -> toSElem $ M.fromList xs
          NNil        -> toSElem ""
+
+parseAsDate :: (ParseTime t) => String -> Maybe t
+parseAsDate s =
+  msum $ map (\fs -> parsetimeWith fs s) formats
+   where parsetimeWith = parseTime defaultTimeLocale
+         formats = ["%x","%m/%d/%Y", "%D","%F", "%d %b %Y"]
diff --git a/Yst/Util.hs b/Yst/Util.hs
--- a/Yst/Util.hs
+++ b/Yst/Util.hs
@@ -30,21 +30,12 @@
 import System.IO.UTF8 (hPutStrLn)
 #endif
 import System.Directory
-import Control.Monad
-import Data.Time
 import Data.List (intercalate)
 import Data.Char (isSpace)
-import System.Locale (defaultTimeLocale)
 
 -- | Strip blank lines from a file.
 stripBlanks :: String -> String
 stripBlanks = intercalate "\n" . filter (not . all isSpace) . lines
-
-parseAsDate :: (ParseTime t) => String -> Maybe t
-parseAsDate s =
-  msum $ map (\fs -> parsetimeWith fs s) formats
-   where parsetimeWith = parseTime defaultTimeLocale
-         formats = ["%x","%m/%d/%Y", "%D","%F", "%d %b %Y"]
 
 stripStExt :: FilePath -> FilePath
 stripStExt f =
diff --git a/Yst/Yaml.hs b/Yst/Yaml.hs
--- a/Yst/Yaml.hs
+++ b/Yst/Yaml.hs
@@ -17,74 +17,12 @@
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 -}
 
-module Yst.Yaml (readYamlFile, nodeToYamlNode)
+module Yst.Yaml (readYamlFile)
 where
 import Yst.Types
-import Yst.Util
-import Data.Yaml.Syck hiding (unpackBuf, packBuf)
-import qualified Data.Yaml.Syck (unpackBuf, packBuf)
-import Data.Time
-import System.Locale (defaultTimeLocale)
-import Codec.Binary.UTF8.String (encodeString, decodeString)
-import qualified Data.ByteString.Char8 as B (ByteString, readFile, filter)
-import Prelude hiding (catch)
-import Control.Exception (catch, SomeException)
-
--- Note: Syck isn't unicode aware, so we use parseYamlBytes and do our
--- own encoding and decoding.
-
-type Buf = B.ByteString
-
-unpackBuf :: Buf -> String
-unpackBuf = decodeString . Data.Yaml.Syck.unpackBuf
-
-packBuf :: String -> Buf
-packBuf = Data.Yaml.Syck.packBuf . encodeString
+import Data.Yaml
 
 readYamlFile :: FilePath -> IO Node
-readYamlFile f = catch (B.readFile f
-                        >>= parseYamlBytes . B.filter (/='\r')
-                        >>= return . yamlNodeToNode)
-                        (\(e::SomeException) -> do
-                             errorExit 11 ("Error parsing " ++ f ++ ": " ++
-                                show e)
-                             return NNil)
-
-yamlNodeToNode :: YamlNode -> Node
-yamlNodeToNode n =
-  case n_elem n of
-        EStr s  -> case parseAsDate (unpackBuf s) of
-                        Nothing  -> NString (unpackBuf s)
-                        Just d   -> NDate d
-        EMap xs | all (\(k,_) -> isStrNode k) xs -> NMap pairs
-                     where pairs = foldr addPair [] xs
-                           addPair (k,v) acc = if isStrNode k && strFrom k == "<<"  -- hash merge, unsupported in Syck!
-                                                  then case n_elem v of             -- so we do it ourselves
-                                                            EMap ys -> foldr addPair acc ys
-                                                            _       -> error "Tried hash merge on non-hash"
-                                                  else case lookup kstr acc of
-                                                             Just _  -> acc   -- overridden
-                                                             Nothing -> (kstr, yamlNodeToNode v) : acc
-                                                          where kstr = strFrom k
-        EMap _  -> error "Map keys must all be strings."
-        ESeq xs -> NList $ map yamlNodeToNode xs
-        ENil    -> NNil
-
-nodeToYamlNode :: Node -> YamlNode
-nodeToYamlNode n =
-  case n of
-       NString s -> mkNode (EStr $ packBuf s)
-       NDate s   -> mkNode (EStr $ packBuf $ formatTime defaultTimeLocale "%x" s)
-       NMap xs   -> mkNode (EMap $ map (\(k,v) -> (nodeToYamlNode (NString k), nodeToYamlNode v)) xs)
-       NList xs  -> mkNode (ESeq $ map nodeToYamlNode xs)
-       NNil      -> mkNode ENil
-
-isStrNode :: YamlNode -> Bool
-isStrNode x = case n_elem x of
-                   EStr _ -> True
-                   _      -> False
+readYamlFile f =
+  (maybe (error $ "Could not parse " ++ f) id) `fmap` decodeFile f
 
-strFrom :: YamlNode -> String
-strFrom x = case n_elem x of
-                 EStr z   -> unpackBuf z
-                 _        -> error "expected EStr node"
diff --git a/changelog b/changelog
--- a/changelog
+++ b/changelog
@@ -1,3 +1,9 @@
+yst 0.4 (released 15 Sep 2013)
+
+  * Use yaml package instead of HsSyck.
+  * Data.Yaml no longer exports nodeToYamlNode.  (We use ToJSON
+    and FromJSON instances instead.)
+
 yst 0.3.1.2 (released 15 Sep 2013)
 
   * Updated to compile with pandoc 1.12.
diff --git a/yst.cabal b/yst.cabal
--- a/yst.cabal
+++ b/yst.cabal
@@ -1,5 +1,5 @@
 name:                yst
-version:             0.3.1.2
+version:             0.4
 Tested-With:         GHC == 7.4.1
 Cabal-version:       >= 1.8
 build-type:          Simple
@@ -54,9 +54,9 @@
   main-is:           yst.hs
   other-modules:     Yst.Types, Yst.Yaml, Yst.Util, Yst.Data, Yst.Config,
                      Yst.Render, Yst.Build, Yst.CSV, Yst.Sqlite3
-  build-depends:     base >=3 && < 5,
-                     HStringTemplate >= 0.6.1 && < 0.6.9 || > 0.6.11 && < 0.7,
-                     HsSyck, csv,
+  build-depends:     base >=3 && < 5, unordered-containers,
+                     HStringTemplate >= 0.6.1 && < 0.6.9 || > 0.6.11 && < 0.8,
+                     yaml, csv, aeson, text,
                      filepath, containers, directory, utf8-string, time,
                      old-locale, old-time, parsec, xhtml,
                      pandoc >= 1.10 && < 1.13, bytestring,
