diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -8,20 +8,23 @@
 import qualified Data.Attoparsec.ByteString as Parsec
 import qualified Data.ByteString as ByteString
 import qualified Data.ByteString.Lazy as ByteString.Lazy
+import Data.HashMap.Strict (HashMap)
+import Data.Text (Text)
 import qualified Data.Text as Text
 import qualified Data.Text.Encoding as Text.Encoding
 import qualified Data.Text.Lazy.IO as Text.Lazy.IO
 import qualified Options.Applicative as Options
 import qualified Options.Applicative.Help.Pretty as Pretty
-import qualified System.Exit as Exit
-import qualified Text.EDE as EDE
 import qualified Prettyprinter as PP
 import qualified Prettyprinter.Render.Terminal as PP
+import qualified System.Exit as Exit
+import qualified Text.EDE as EDE
+import qualified Text.EDE.Internal.Compat as Compat
 
 data Options = Options
   { templateFile :: FilePath,
     jsonFile :: Maybe FilePath,
-    jsonObject :: Maybe Aeson.Object
+    jsonObject :: Maybe (HashMap Text Aeson.Value)
   }
 
 optionsParser :: Options.Parser Options
@@ -117,7 +120,7 @@
         EDE.Failure err -> PP.putDoc (err <> PP.hardline) >> Exit.exitFailure
         EDE.Success output -> Text.Lazy.IO.putStr output
 
-stdinParser :: Parsec.Parser Aeson.Object
+stdinParser :: Parsec.Parser (HashMap Text Aeson.Value)
 stdinParser = Aeson.json >>= requireObject
 
 readValue :: Options.ReadM Aeson.Value
@@ -129,10 +132,10 @@
     . Text.Encoding.encodeUtf8
     . Text.pack
 
-readObject :: Options.ReadM Aeson.Object
+readObject :: Options.ReadM (HashMap Text Aeson.Value)
 readObject = readValue >>= requireObject
 
-requireObject :: Fail.MonadFail m => Aeson.Value -> m Aeson.Object
+requireObject :: Fail.MonadFail m => Aeson.Value -> m (HashMap Text Aeson.Value)
 requireObject = \case
-  Aeson.Object obj -> pure obj
+  Aeson.Object obj -> pure (Compat.toHashMapText obj)
   _ -> fail "JSON value must be an object"
diff --git a/ede.cabal b/ede.cabal
--- a/ede.cabal
+++ b/ede.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.2
 name:               ede
-version:            0.3.2.0
+version:            0.3.3.0
 synopsis:
   Templating language with similar syntax and features to Liquid or Jinja2.
 
@@ -49,9 +49,9 @@
   default-language: Haskell2010
   ghc-options:
     -Wall -funbox-strict-fields -fwarn-incomplete-uni-patterns
-    -fwarn-incomplete-record-updates
+    -fwarn-incomplete-record-updates -fwarn-unused-packages
 
-  build-depends:    base >=4.12 && <5
+  build-depends:    base >=4.13 && <5
   autogen-modules:  Paths_ede
   other-modules:    Paths_ede
 
@@ -62,6 +62,7 @@
     Text.EDE
     Text.EDE.Filters
     Text.EDE.Internal.AST
+    Text.EDE.Internal.Compat
     Text.EDE.Internal.Eval
     Text.EDE.Internal.Filters
     Text.EDE.Internal.Parser
@@ -70,8 +71,8 @@
     Text.EDE.Internal.Types
 
   build-depends:
-    , aeson                        >=0.7
-    , bytestring                   >=0.9
+    , aeson                        >=1.4
+    , bytestring                   >=0.10.4
     , comonad                      >=4.2
     , directory                    >=1.2
     , filepath                     >=1.2
@@ -79,7 +80,7 @@
     , lens                         >=4.0
     , mtl                          >=2.1.3.1
     , parsers                      >=0.12.1.1
-    , prettyprinter                >=1.6
+    , prettyprinter                >=1.7
     , prettyprinter-ansi-terminal  >=1.1
     , scientific                   >=0.3.1
     , text                         >=1.2
@@ -94,14 +95,15 @@
   main-is:        Main.hs
   ghc-options:    -threaded -rtsopts -with-rtsopts=-A128m
   build-depends:
-    , aeson                        >=0.8
-    , attoparsec
+    , aeson                        >=1.4
+    , attoparsec                   >=0.13
     , bytestring                   >=0.10.4
     , ede
     , optparse-applicative         >=0.11
-    , prettyprinter                >=1.6
+    , prettyprinter                >= 1.7
     , prettyprinter-ansi-terminal  >=1.1
     , text                         >=1.2
+    , unordered-containers         >=0.2.3
 
 test-suite tests
   import:         base
diff --git a/lib/Text/EDE.hs b/lib/Text/EDE.hs
--- a/lib/Text/EDE.hs
+++ b/lib/Text/EDE.hs
@@ -114,7 +114,7 @@
 
 import qualified Control.Monad as Monad
 import Data.Aeson ((.=))
-import Data.Aeson.Types (Object)
+import Data.Aeson.Types (Value)
 import Data.ByteString (ByteString)
 import qualified Data.ByteString as ByteString
 import qualified Data.Foldable as Foldable
@@ -125,9 +125,9 @@
 import qualified Data.Text as Text
 import qualified Data.Text.Lazy as Text.Lazy
 import qualified Data.Text.Lazy.Builder as Text.Builder
-import Data.Text.Prettyprint.Doc (Pretty (..))
 import Data.Version (Version)
 import qualified Paths_ede as Paths
+import Prettyprinter (Pretty (..))
 import qualified System.Directory as Directory
 import qualified System.FilePath as FilePath
 import qualified Text.EDE.Internal.Eval as Eval
@@ -270,23 +270,23 @@
     then failure ("file " <> pretty path <> " doesn't exist.")
     else ByteString.readFile path >>= success
 
--- | Render an 'Object' using the supplied 'Template'.
+-- | Render an 'HashMap Text Value' using the supplied 'Template'.
 render ::
   -- | Parsed 'Template' to render.
   Template ->
   -- | Bindings to make available in the environment.
-  Object ->
+  HashMap Text Value ->
   Result Text.Lazy.Text
 render = renderWith mempty
 
--- | Render an 'Object' using the supplied 'Template'.
+-- | Render an 'HashMap Text Value' using the supplied 'Template'.
 renderWith ::
   -- | Filters to make available in the environment.
   HashMap Id Term ->
   -- | Parsed 'Template' to render.
   Template ->
   -- | Bindings to make available in the environment.
-  Object ->
+  HashMap Text Value ->
   Result Text.Lazy.Text
 renderWith fs (Template _ u ts) =
   fmap Text.Builder.toLazyText . Eval.render ts fs u
@@ -312,7 +312,7 @@
 -- | /See:/ 'render'
 eitherRender ::
   Template ->
-  Object ->
+  HashMap Text Value ->
   Either String Text.Lazy.Text
 eitherRender t = eitherResult . render t
 
@@ -320,7 +320,7 @@
 eitherRenderWith ::
   HashMap Id Term ->
   Template ->
-  Object ->
+  HashMap Text Value ->
   Either String Text.Lazy.Text
 eitherRenderWith fs t = eitherResult . renderWith fs t
 
@@ -333,15 +333,15 @@
 --
 -- >>> tmpl <- parse "{% if var %}\nHello, {{ var }}!\n{% else %}\nnegative!\n{% endif %}\n" :: Result Template
 --
--- Then an 'Object' is defined containing the environment which will be
+-- Then an 'HashMap Text Value' is defined containing the environment which will be
 -- available to the 'Template' during rendering:
 --
--- >>> let env = fromPairs [ "var" .= "World" ] :: Object
+-- >>> let env = fromPairs [ "var" .= "World" ] :: HashMap Text Value
 --
 -- Note: the 'fromPairs' function above is a wrapper over Aeson's 'object'
--- which removes the outer 'Object' 'Value' constructor, exposing the underlying 'HashMap'.
+-- which removes the outer 'Data.Aeson.Object' 'Value' constructor, exposing the underlying 'HashMap'.
 --
--- Then, the 'Template' is rendered using the 'Object' environment:
+-- Then, the 'Template' is rendered using the 'HashMap Text Value' environment:
 --
 -- >>> render tmpl env :: Result Text
 -- > Success "Hello, World!"
@@ -379,7 +379,7 @@
 -- which can be cached for future use.
 --
 -- * Rendering takes a 'HashMap' of custom 'Fun's (functions available in the
--- template context), an 'Object' as the binding environment, and a parsed
+-- template context), an 'HashMap Text Value' as the binding environment, and a parsed
 -- 'Template' to subsitute the values into.
 -- The result is a Lazy 'Text.Lazy.Text' value containing the rendered output.
 
@@ -487,12 +487,12 @@
 --
 -- Variables are substituted directly for their renderable representation.
 -- An error is raised if the varaible being substituted is not a literal type
--- (ie. an 'Array' or 'Object') or doesn't exist in the supplied environment.
+-- (ie. an 'Array' or 'HashMap Text Value') or doesn't exist in the supplied environment.
 --
 -- > {{ var }}
 --
--- Nested variable access is also supported for variables which resolve to an 'Object'.
--- Dot delimiters are used to chain access through multiple nested 'Object's.
+-- Nested variable access is also supported for variables which resolve to an 'HashMap Text Value'.
+-- Dot delimiters are used to chain access through multiple nested 'HashMap Text Value's.
 -- The right-most accessor must resolve to a renderable type as with the previous
 -- non-nested variable access.
 --
@@ -564,7 +564,7 @@
 
 -- $loops
 --
--- Iterating over an 'Array' or 'Object' can be acheived using the 'for ... in' section syntax.
+-- Iterating over an 'Array' or 'HashMap Text Value' can be acheived using the 'for ... in' section syntax.
 -- Attempting to iterate over any other type will raise an error.
 --
 -- Example:
@@ -578,13 +578,13 @@
 -- The iteration branch is rendering per item with the else branch being (which is optional)
 -- being rendered if the @{{ list }}@ variable is empty.
 --
--- When iterating over an 'Object', a stable sort using key equivalence is applied, 'Array's
+-- When iterating over an 'HashMap Text Value', a stable sort using key equivalence is applied, 'Array's
 -- are unmodified.
 --
 -- The resulting binding within the iteration expression (in this case, @{{ var }}@) is
--- an 'Object' containing the following keys:
+-- an 'HashMap Text Value' containing the following keys:
 --
--- * @key        :: Text@: They key if the loop target is an 'Object'
+-- * @key        :: Text@: They key if the loop target is an 'HashMap Text Value'
 --
 -- * @value      :: a@: The value of the loop target
 --
@@ -620,8 +620,8 @@
 -- Will render each item with its (1-based) loop index as a prefix, separated
 -- by a blank newline, without a trailing at the end of the document.
 --
--- Valid loop targets are 'Object's, 'Array's, and 'String's, with only 'Object's
--- having an available @{{ <var>.key }}@ in scope.
+-- Valid loop targets are 'HashMap Text Value's, 'Array's, and 'String's, with
+-- only 'HashMap Text Value's having an available @{{ <var>.key }}@ in scope.
 
 -- $includes
 --
diff --git a/lib/Text/EDE/Internal/Compat.hs b/lib/Text/EDE/Internal/Compat.hs
new file mode 100644
--- /dev/null
+++ b/lib/Text/EDE/Internal/Compat.hs
@@ -0,0 +1,35 @@
+{-# LANGUAGE CPP #-}
+
+-- |
+-- Module      : Text.EDE.Internal.Eval
+-- Copyright   : (c) 2022 Brendan Hay <brendan.g.hay@gmail.com>
+-- License     : This Source Code Form is subject to the terms of
+--               the Mozilla Public License, v. 2.0.
+--               A copy of the MPL can be found in the LICENSE file or
+--               you can obtain it at http://mozilla.org/MPL/2.0/.
+-- Maintainer  : Brendan Hay <brendan.g.hay@gmail.com>
+-- Stability   : experimental
+-- Portability : non-portable (GHC extensions)
+--
+-- /Warning/: this is an internal module, and does not have a stable
+-- API or name. Functions in this module may not check or enforce
+-- preconditions expected by public modules. Use at your own risk!
+module Text.EDE.Internal.Compat
+  ( toHashMapText,
+    fromHashMapText,
+  )
+where
+
+#if MIN_VERSION_aeson(2,0,0)
+import Data.Aeson.KeyMap (toHashMapText, fromHashMapText)
+#else
+import Data.HashMap.Strict (HashMap)
+import Data.Aeson.Types (Value)
+import Data.Text (Text)
+
+toHashMapText :: HashMap Text Value -> HashMap Text Value
+toHashMapText = id
+
+fromHashMapText :: HashMap Text Value -> HashMap Text Value
+fromHashMapText = id
+#endif
diff --git a/lib/Text/EDE/Internal/Eval.hs b/lib/Text/EDE/Internal/Eval.hs
--- a/lib/Text/EDE/Internal/Eval.hs
+++ b/lib/Text/EDE/Internal/Eval.hs
@@ -26,20 +26,22 @@
 import Control.Monad.Trans (lift)
 import Data.Aeson ((.=))
 import qualified Data.Aeson as Aeson
-import Data.Aeson.Types (Object, Value (..))
+import Data.Aeson.Types (Value (..))
 import qualified Data.Foldable as Foldable
 import Data.HashMap.Strict (HashMap)
 import qualified Data.HashMap.Strict as HashMap
 import Data.List.NonEmpty (NonEmpty (..))
 import qualified Data.List.NonEmpty as NonEmpty
 import Data.Scientific (isFloating)
+import Data.Text (Text)
 import qualified Data.Text as Text
 import Data.Text.Lazy.Builder (Builder)
 import qualified Data.Text.Lazy.Builder as Text.Builder
 import Data.Text.Lazy.Builder.Scientific (FPFormat (Fixed), formatScientificBuilder)
 import Data.Text.Manipulate (toOrdinal)
-import Data.Text.Prettyprint.Doc ((<+>))
-import qualified Data.Text.Prettyprint.Doc as PP
+import Prettyprinter ((<+>))
+import qualified Prettyprinter as PP
+import Text.EDE.Internal.Compat
 import Text.EDE.Internal.Filters (stdlib)
 import Text.EDE.Internal.Quoting
 import Text.EDE.Internal.Types
@@ -171,13 +173,13 @@
           <+> PP.brackets (pp (Text.intercalate "," $ HashMap.keys ts))
 {-# INLINEABLE eval #-}
 
-bind :: (Object -> Object) -> Context a -> Context a
+bind :: (HashMap Text Value -> HashMap Text Value) -> Context a -> Context a
 bind f = Reader.withReaderT (\x -> x {_values = f (_values x)})
 {-# INLINEABLE bind #-}
 
 variable :: Delta -> Var -> Context Value
 variable d (Var is) =
-  Reader.asks _values >>= go (NonEmpty.toList is) [] . Object
+  Reader.asks _values >>= go (NonEmpty.toList is) [] . Object . fromHashMapText
   where
     go [] _ v = pure v
     go (k : ks) r v = do
@@ -189,8 +191,8 @@
       where
         cur = Var (k :| r)
 
-        nest :: Value -> Context Object
-        nest (Object o) = pure o
+        nest :: Value -> Context (HashMap Text Value)
+        nest (Object o) = pure (toHashMapText o)
         nest x =
           throwError d $
             "variable"
diff --git a/lib/Text/EDE/Internal/Filters.hs b/lib/Text/EDE/Internal/Filters.hs
--- a/lib/Text/EDE/Internal/Filters.hs
+++ b/lib/Text/EDE/Internal/Filters.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE ExtendedDefaultRules #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE LambdaCase #-}
@@ -22,7 +23,7 @@
 module Text.EDE.Internal.Filters where
 
 import qualified Data.Aeson as Aeson
-import Data.Aeson.Types (Array, Object, Value (..))
+import Data.Aeson.Types (Value (..))
 import qualified Data.Char as Char
 import Data.HashMap.Strict (HashMap)
 import qualified Data.HashMap.Strict as HashMap
@@ -33,9 +34,11 @@
 import qualified Data.Text.Lazy as Text.Lazy
 import qualified Data.Text.Lazy.Encoding as Text.Lazy.Encoding
 import qualified Data.Text.Manipulate as Text.Manipulate
-import Data.Text.Prettyprint.Doc ((<+>))
 import qualified Data.Text.Unsafe as Text.Unsafe
+import Data.Vector (Vector)
 import qualified Data.Vector as Vector
+import Prettyprinter ((<+>))
+import Text.EDE.Internal.Compat
 import Text.EDE.Internal.Quoting
 import Text.EDE.Internal.Types
 
@@ -110,8 +113,8 @@
       qlist1 "init" initT initV,
       "at" @: (\x i -> x Vector.! i :: Value),
       -- object
-      "keys" @: (HashMap.keys :: Object -> [Text]),
-      "elems" @: (HashMap.elems :: Object -> [Value]),
+      "keys" @: (HashMap.keys :: HashMap Text Value -> [Text]),
+      "elems" @: (HashMap.elems :: HashMap Text Value -> [Value]),
       -- , "map"        @: undefined
       -- , "filter"     @: undefined
       -- , "zip"        @: undefined
@@ -119,7 +122,7 @@
 
       -- polymorphic
       "show" @: (Text.Lazy.Encoding.decodeUtf8 . Aeson.encode :: Value -> Text.Lazy.Text),
-      "singleton" @: (pure :: Value -> Vector.Vector Value)
+      "singleton" @: (pure :: Value -> Vector Value)
       -- FIXME: existence checks currently hardcoded into the evaluator:
       -- "default"
       -- "defined"
@@ -146,7 +149,7 @@
   (Quote a, Quote b) =>
   Id ->
   (Text -> a) ->
-  (Array -> b) ->
+  (Vector Value -> b) ->
   (Id, Term)
 qlist1 k f g = (k,) . TLam $ \case
   TVal (String t) -> pure . quote k 0 $ f t
@@ -161,12 +164,12 @@
   (Quote a, Quote b, Quote c) =>
   Id ->
   (Text -> a) ->
-  (Object -> b) ->
-  (Array -> c) ->
+  (HashMap Text Value -> b) ->
+  (Vector Value -> c) ->
   (Id, Term)
 qcol1 k f g h = (k,) . TLam $ \case
   TVal (String t) -> pure . quote k 0 $ f t
-  TVal (Object o) -> pure . quote k 0 $ g o
+  TVal (Object o) -> pure . quote k 0 $ g (toHashMapText o)
   TVal (Array v) -> pure . quote k 0 $ h v
   x ->
     Failure $
@@ -178,7 +181,7 @@
 tailT = text Text.Unsafe.unsafeTail
 initT = text Text.init
 
-headV, lastV, tailV, initV :: Array -> Value
+headV, lastV, tailV, initV :: Vector Value -> Value
 headV = vec Vector.unsafeHead
 lastV = vec Vector.unsafeLast
 tailV = vec (Array . Vector.unsafeTail)
@@ -187,7 +190,7 @@
 text :: (Text -> Text) -> Text -> Value
 text f = String . safe mempty Text.null f
 
-vec :: (Array -> Value) -> Array -> Value
+vec :: (Vector Value -> Value) -> Vector Value -> Value
 vec = safe (Array Vector.empty) Vector.null
 
 safe :: b -> (a -> Bool) -> (a -> b) -> a -> b
diff --git a/lib/Text/EDE/Internal/Parser.hs b/lib/Text/EDE/Internal/Parser.hs
--- a/lib/Text/EDE/Internal/Parser.hs
+++ b/lib/Text/EDE/Internal/Parser.hs
@@ -1,5 +1,4 @@
 {-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE CPP #-}
 {-# LANGUAGE ConstraintKinds #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
@@ -31,11 +30,11 @@
 import Control.Comonad.Cofree (Cofree ((:<)))
 import Control.Lens ((%=))
 import qualified Control.Lens as Lens
-import Control.Monad (MonadPlus, void, unless)
+import Control.Monad (MonadPlus, unless, void)
 import Control.Monad.State.Strict (MonadState, StateT)
 import qualified Control.Monad.State.Strict as State
 import Control.Monad.Trans (lift)
-import Data.Aeson.Types (Array, Object, Value (..))
+import Data.Aeson.Types (Value (..))
 import qualified Data.Bifunctor as Bifunctor
 import Data.ByteString (ByteString)
 import qualified Data.Char as Char
@@ -48,8 +47,10 @@
 import Data.Text (Text)
 import qualified Data.Text as Text
 import qualified Data.Text.Encoding as Text.Encoding
+import Data.Vector (Vector)
 import qualified Data.Vector as Vector
 import Text.EDE.Internal.AST
+import Text.EDE.Internal.Compat
 import Text.EDE.Internal.Syntax
 import Text.EDE.Internal.Types
 import qualified Text.Parser.Expression as Expression
@@ -73,9 +74,7 @@
 
 type Parser m =
   ( Monad m,
-#if MIN_VERSION_base(4,13,0)
     MonadFail m,
-#endif
     MonadState Env m,
     Trifecta.TokenParsing m,
     Trifecta.DeltaParsing m,
@@ -89,9 +88,7 @@
       Applicative,
       Alternative,
       Monad,
-#if MIN_VERSION_base(4,13,0)
       MonadFail,
-#endif
       MonadPlus,
       Trifecta.Parsing,
       Trifecta.CharParsing,
@@ -137,10 +134,11 @@
 pragma :: Parser m => m ()
 pragma =
   void . Trifecta.many $ do
-    !xs <- pragmal
-      *> Trifecta.symbol "EDE_SYNTAX"
-      *> Trifecta.sepBy field spaces
-      <* trimr pragmar
+    !xs <-
+      pragmal
+        *> Trifecta.symbol "EDE_SYNTAX"
+        *> Trifecta.sepBy field spaces
+        <* trimr pragmar
 
     mapM_ (uncurry Lens.assign) xs
   where
@@ -194,7 +192,7 @@
 block :: Parser m => String -> m a -> m a
 block k p =
   Trifecta.try (multiLine (keyword k) p)
-  <|> singleLine (keyword k) p
+    <|> singleLine (keyword k) p
 
 multiLine :: Parser m => m b -> m a -> m a
 multiLine s =
@@ -342,7 +340,7 @@
 collection = ann (EVar <$> variable <|> ELit <$> col)
   where
     col =
-      Object <$> object
+      (Object . fromHashMapText) <$> object
         <|> Array <$> array
         <|> String <$> Trifecta.stringLiteral
 
@@ -351,7 +349,7 @@
   Bool <$> bool
     <|> Number <$> number
     <|> String <$> Trifecta.stringLiteral
-    <|> Object <$> object
+    <|> (Object . fromHashMapText) <$> object
     <|> Array <$> array
 
 number :: Parser m => m Scientific
@@ -364,7 +362,7 @@
   Trifecta.symbol "true" *> pure True
     <|> Trifecta.symbol "false" *> pure False
 
-object :: Parser m => m Object
+object :: Parser m => m (HashMap Text Value)
 object = HashMap.fromList <$> Trifecta.braces (Trifecta.commaSep pair)
   where
     pair =
@@ -372,7 +370,7 @@
         <$> (Trifecta.stringLiteral <* Trifecta.spaces)
         <*> (Trifecta.char ':' *> Trifecta.spaces *> literal)
 
-array :: Parser m => m Array
+array :: Parser m => m (Vector Value)
 array = Vector.fromList <$> Trifecta.brackets (Trifecta.commaSep literal)
 
 operator :: Parser m => Text -> m Delta
@@ -413,10 +411,10 @@
 
 triml :: Parser m => m a -> m a
 triml p = do
-    c <- Trifecta.Delta.column <$> Trifecta.position
-    if c == 0
-        then Trifecta.spaces *> p
-        else fail "left whitespace removal failed"
+  c <- Trifecta.Delta.column <$> Trifecta.position
+  if c == 0
+    then Trifecta.spaces *> p
+    else fail "left whitespace removal failed"
 
 trimr :: Parser m => m a -> m a
 trimr p = p <* Trifecta.newline -- <* Trifecta.newline
diff --git a/lib/Text/EDE/Internal/Quoting.hs b/lib/Text/EDE/Internal/Quoting.hs
--- a/lib/Text/EDE/Internal/Quoting.hs
+++ b/lib/Text/EDE/Internal/Quoting.hs
@@ -1,5 +1,5 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE DefaultSignatures #-}
-{-# LANGUAGE ExtendedDefaultRules #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE GADTs #-}
 {-# LANGUAGE LambdaCase #-}
@@ -26,9 +26,10 @@
 import Control.Monad ((>=>))
 import Data.Aeson (FromJSON, ToJSON)
 import qualified Data.Aeson as Aeson
-import Data.Aeson.Types (Array, Object, Value (..))
+import Data.Aeson.Types (Value (..))
 import qualified Data.Bifunctor as Bifunctor
 import qualified Data.ByteString.Char8 as ByteString.Char8
+import Data.HashMap.Strict (HashMap)
 import qualified Data.HashMap.Strict as HashMap
 import Data.List (sortBy)
 import Data.Ord (comparing)
@@ -41,15 +42,18 @@
 import Data.Text.Lazy.Builder (Builder)
 import qualified Data.Text.Lazy.Builder as Text.Builder
 import Data.Text.Manipulate (toOrdinal)
-import Data.Text.Prettyprint.Doc (Pretty (..), (<+>))
-import qualified Data.Text.Prettyprint.Doc as PP
+import Data.Vector (Vector)
 import qualified Data.Vector as Vector
+import Prettyprinter (Pretty (..), (<+>))
+import qualified Prettyprinter as PP
 import Text.EDE.Internal.Types
 import Text.Trifecta.Delta (Delta)
 import qualified Text.Trifecta.Delta as Trifecta.Delta
 import qualified Text.Trifecta.Rendering as Trifecta.Rendering
 
-default (AnsiDoc, Double, Integer)
+#if MIN_VERSION_aeson(2,0,0)
+import Data.Aeson.KeyMap (KeyMap)
+#endif
 
 -- | A HOAS representation of (possibly partially applied) values
 -- in the environment.
@@ -96,6 +100,14 @@
 
 instance Unquote Value
 
+#if MIN_VERSION_aeson(2,0,0)
+instance Unquote (KeyMap Value)
+#endif
+
+instance Unquote (HashMap Text Value)
+
+instance Unquote (Vector Value)
+
 instance Unquote Text
 
 instance Unquote [Text]
@@ -108,10 +120,6 @@
 
 instance Unquote Scientific
 
-instance Unquote Object
-
-instance Unquote Array
-
 instance Unquote Int where
   unquote k n =
     unquote k n
@@ -164,6 +172,14 @@
 
 instance Quote Value
 
+#if MIN_VERSION_aeson(2,0,0)
+instance Quote (KeyMap Value)
+#endif
+
+instance Quote (HashMap Text Value)
+
+instance Quote (Vector Value)
+
 instance Quote [Value]
 
 instance Quote Text
@@ -181,10 +197,6 @@
 instance Quote Double
 
 instance Quote Scientific
-
-instance Quote Object
-
-instance Quote Array
 
 instance Quote Builder where
   quote k n = quote k n . Text.Builder.toLazyText
diff --git a/lib/Text/EDE/Internal/Types.hs b/lib/Text/EDE/Internal/Types.hs
--- a/lib/Text/EDE/Internal/Types.hs
+++ b/lib/Text/EDE/Internal/Types.hs
@@ -30,7 +30,7 @@
 import Control.Comonad.Cofree (Cofree)
 import qualified Control.Lens as Lens
 import qualified Data.Aeson as Aeson
-import Data.Aeson.Types (Object, Pair, Value (..))
+import Data.Aeson.Types (Pair, Value (..))
 import qualified Data.Functor.Classes as Functor.Classes
 import Data.HashMap.Strict (HashMap)
 import qualified Data.List as List
@@ -38,9 +38,10 @@
 import qualified Data.List.NonEmpty as NonEmpty
 import Data.Text (Text)
 import qualified Data.Text as Text
-import Data.Text.Prettyprint.Doc (Doc, Pretty (..))
-import qualified Data.Text.Prettyprint.Doc as PP
-import qualified Data.Text.Prettyprint.Doc.Render.Terminal as PP
+import Prettyprinter (Doc, Pretty (..))
+import qualified Prettyprinter as PP
+import qualified Prettyprinter.Render.Terminal as PP
+import Text.EDE.Internal.Compat
 import Text.Trifecta.Delta (Delta, HasDelta)
 import qualified Text.Trifecta.Delta as Trifecta.Delta
 
@@ -86,7 +87,7 @@
 $(Lens.makePrisms ''Result)
 
 instance Monad Result where
-  return = Success
+  return = pure
   {-# INLINE return #-}
 
   Success x >>= k = k x
@@ -94,7 +95,7 @@
   {-# INLINE (>>=) #-}
 
 instance Applicative Result where
-  pure = return
+  pure = Success
   {-# INLINE pure #-}
 
   Success f <*> Success x = Success (f x)
@@ -228,15 +229,15 @@
 -- | Unwrap a 'Value' to an 'Object' safely.
 --
 -- See Aeson\'s documentation for more details.
-fromValue :: Value -> Maybe Object
-fromValue (Object o) = Just o
+fromValue :: Value -> Maybe (HashMap Text Value)
+fromValue (Object o) = Just (toHashMapText o)
 fromValue _ = Nothing
 
 -- | Create an 'Object' from a list of name/value 'Pair's.
 --
 -- See Aeson\'s documentation for more details.
-fromPairs :: [Pair] -> Object
+fromPairs :: [Pair] -> HashMap Text Value
 fromPairs xs =
   case Aeson.object xs of
-    Object o -> o
+    Object o -> toHashMapText o
     _other -> mempty
