diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.markdown
@@ -0,0 +1,12 @@
+# aeson-pretty changelog
+
+## 0.8.11
+ * Dropped support for Aeson 1.4 and older
+ * Added support for Aeson 2.3
+ * Added support for Aeson 2.2
+
+## 0.8.10
+ * Added support for Aeson 2.1
+
+## 0.8.9
+ * Added support for Aeson 2.0
diff --git a/Data/Aeson/Encode/Pretty.hs b/Data/Aeson/Encode/Pretty.hs
--- a/Data/Aeson/Encode/Pretty.hs
+++ b/Data/Aeson/Encode/Pretty.hs
@@ -1,21 +1,22 @@
-{-# LANGUAGE OverloadedStrings, RecordWildCards #-}
+{-# LANGUAGE OverloadedStrings, RecordWildCards, CPP #-}
 
 -- |Aeson-compatible pretty-printing of JSON 'Value's.
 module Data.Aeson.Encode.Pretty (
     -- * Simple Pretty-Printing
     encodePretty, encodePrettyToTextBuilder,
-    
+
     -- * Pretty-Printing with Configuration Options
     encodePretty', encodePrettyToTextBuilder',
     Config (..), defConfig,
+    Indent(..), NumberFormat(..),
     -- ** Sorting Keys in Objects
-    -- |With the Aeson library, the order of keys in objects is undefined due
+    -- |With the Aeson library, the order of keys in objects is undefined due to
     --  objects being implemented as HashMaps. To allow user-specified key
     --  orders in the pretty-printed JSON, 'encodePretty'' can be configured
     --  with a comparison function. These comparison functions can be composed
     --  using the 'Monoid' interface. Some other useful helper functions to keep
     --  in mind are 'comparing' and 'on'.
-    --  
+    --
     --  Consider the following deliberately convoluted example, demonstrating
     --  the use of comparison functions:
     --
@@ -43,7 +44,7 @@
     --  >   "quux": ...,
     --  > }
     --
-    
+
     mempty,
     -- |Serves as an order-preserving (non-)sort function. Re-exported from
     --  "Data.Monoid".
@@ -53,30 +54,68 @@
     keyOrder
 ) where
 
+#if MIN_VERSION_aeson(2,0,0)
+import qualified Data.Aeson.Key as AK
+import qualified Data.Aeson.KeyMap as AKM
+#endif
 import Data.Aeson (Value(..), ToJSON(..))
-import qualified Data.Aeson.Encode as Aeson
+import qualified Data.Aeson.Text as Aeson
 import Data.ByteString.Lazy (ByteString)
 import Data.Function (on)
+#if !MIN_VERSION_aeson(2,0,0)
 import qualified Data.HashMap.Strict as H (toList)
+#endif
 import Data.List (intersperse, sortBy, elemIndex)
 import Data.Maybe (fromMaybe)
-import Data.Monoid ((<>), mconcat, mempty)
-import Data.Ord
+#if !MIN_VERSION_base(4,13,0)
+import Data.Semigroup ((<>))
+#endif
+import qualified Data.Scientific as S (Scientific, FPFormat(..))
+import Data.Ord (comparing)
 import Data.Text (Text)
 import Data.Text.Lazy.Builder (Builder, toLazyText)
+import Data.Text.Lazy.Builder.Scientific (formatScientificBuilder)
 import Data.Text.Lazy.Encoding (encodeUtf8)
 import qualified Data.Vector as V (toList)
+import Prelude ()
+import Prelude.Compat
 
-data PState = PState { pstIndent :: Int
-                     , pstLevel  :: Int
-                     , pstSort   :: [(Text, Value)] -> [(Text, Value)]
+
+data PState = PState { pLevel     :: Int
+                     , pIndent    :: Builder
+                     , pNewline   :: Builder
+                     , pItemSep   :: Builder
+                     , pKeyValSep :: Builder
+                     , pNumFormat :: NumberFormat
+                     , pSort      :: [(Text, Value)] -> [(Text, Value)]
                      }
 
+-- | Indentation per level of nesting. @'Spaces' 0@ removes __all__ whitespace
+--   from the output.
+data Indent = Spaces Int | Tab
+
+data NumberFormat
+  -- | For numbers with absolute value less than 1e19, this follows the standard
+  -- behaviour of the 'Data.Aeson.encode' function. Uses integer literals for
+  -- integers (1, 2, 3...), simple decimals for fractional values between 0.1
+  -- and 9,999,999, and scientific notation otherwise. For numbers with an
+  -- absolute value larger than 1e19, always uses scientific notation.
+  = Generic
+  -- | Scientific notation (e.g. 2.3e123).
+  | Scientific
+  -- | Standard decimal notation
+  | Decimal
+  -- | Custom formatting function
+  | Custom (S.Scientific -> Builder)
+
 data Config = Config
-    { confIndent  :: Int
-      -- ^ Indentation spaces per level of nesting
+    { confIndent  :: Indent
+      -- ^ Indentation per level of nesting
     , confCompare :: Text -> Text -> Ordering
       -- ^ Function used to sort keys in objects
+    , confNumFormat :: NumberFormat
+    , confTrailingNewline :: Bool
+      -- ^ Whether to add a trailing newline to the output
     }
 
 -- |Sort keys by their order of appearance in the argument list.
@@ -90,13 +129,14 @@
 
 
 -- |The default configuration: indent by four spaces per level of nesting, do
---  not sort objects by key.
+--  not sort objects by key, do not add trailing newline.
 --
---  > defConfig = Config { confIndent = 4, confCompare = mempty }
+--  > defConfig = Config { confIndent = Spaces 4, confCompare = mempty, confNumFormat = Generic, confTrailingNewline = False }
 defConfig :: Config
-defConfig = Config { confIndent = 4, confCompare = mempty }
+defConfig =
+  Config {confIndent = Spaces 4, confCompare = mempty, confNumFormat = Generic, confTrailingNewline = False}
 
--- |A drop-in replacement for aeson's 'Aeson.encode' function, producing 
+-- |A drop-in replacement for aeson's 'Aeson.encode' function, producing
 --  JSON-ByteStrings for human readers.
 --
 --  Follows the default configuration in 'defConfig'.
@@ -115,22 +155,40 @@
 encodePrettyToTextBuilder :: ToJSON a => a -> Builder
 encodePrettyToTextBuilder = encodePrettyToTextBuilder' defConfig
 
--- |A variant of 'encodeToTextBuilder' that takes an additional configuration
+-- |A variant of 'Aeson.encodeToTextBuilder' that takes an additional configuration
 --  parameter.
 encodePrettyToTextBuilder' :: ToJSON a => Config -> a -> Builder
-encodePrettyToTextBuilder' Config{..} = fromValue st . toJSON
+encodePrettyToTextBuilder' Config{..} x = fromValue st (toJSON x) <> trail
   where
-    st       = PState confIndent 0 condSort
-    condSort = sortBy (confCompare `on` fst)
+    st      = PState 0 indent newline itemSep kvSep confNumFormat sortFn
+    indent  = case confIndent of
+                Spaces n -> mconcat (replicate n " ")
+                Tab      -> "\t"
+    newline = case confIndent of
+                Spaces 0 -> ""
+                _        -> "\n"
+    itemSep = ","
+    kvSep   = case confIndent of
+                Spaces 0 -> ":"
+                _        -> ": "
+    sortFn  = sortBy (confCompare `on` fst)
+    trail   = if confTrailingNewline then "\n" else ""
 
 
 fromValue :: PState -> Value -> Builder
-fromValue st@PState{..} = go
+fromValue st@PState{..} val = go val
   where
     go (Array v)  = fromCompound st ("[","]") fromValue (V.toList v)
-    go (Object m) = fromCompound st ("{","}") fromPair (pstSort (H.toList m))
+    go (Object m) = fromCompound st ("{","}") fromPair (pSort (toList' m))
+    go (Number x) = fromNumber st x
     go v          = Aeson.encodeToTextBuilder v
 
+#if MIN_VERSION_aeson(2,0,0)
+    toList' = fmap (\(k, v) -> (AK.toText k, v)) . AKM.toList
+#else
+    toList' = H.toList
+#endif
+
 fromCompound :: PState
              -> (Builder, Builder)
              -> (PState -> a -> Builder)
@@ -139,17 +197,27 @@
 fromCompound st@PState{..} (delimL,delimR) fromItem items = mconcat
     [ delimL
     , if null items then mempty
-        else "\n" <> items' <> "\n" <> fromIndent st
+        else pNewline <> items' <> pNewline <> fromIndent st
     , delimR
     ]
   where
-    items' = mconcat . intersperse ",\n" $
+    items' = mconcat . intersperse (pItemSep <> pNewline) $
                 map (\item -> fromIndent st' <> fromItem st' item)
                     items
-    st' = st { pstLevel = pstLevel + 1 }
+    st' = st { pLevel = pLevel + 1}
 
 fromPair :: PState -> (Text, Value) -> Builder
-fromPair st (k,v) = Aeson.encodeToTextBuilder (toJSON k) <> ": " <> fromValue st v
+fromPair st (k,v) =
+  Aeson.encodeToTextBuilder (toJSON k) <> pKeyValSep st <> fromValue st v
 
 fromIndent :: PState -> Builder
-fromIndent PState{..} = mconcat $ replicate (pstIndent * pstLevel) " "
+fromIndent PState{..} = mconcat (replicate pLevel pIndent)
+
+fromNumber :: PState -> S.Scientific -> Builder
+fromNumber st x = case pNumFormat st of
+  Generic
+    | (x > 1.0e19 || x < -1.0e19) -> formatScientificBuilder S.Exponent Nothing x
+    | otherwise -> Aeson.encodeToTextBuilder $ Number x
+  Scientific -> formatScientificBuilder S.Exponent Nothing x
+  Decimal    -> formatScientificBuilder S.Fixed Nothing x
+  Custom f   -> f x
diff --git a/README.markdown b/README.markdown
--- a/README.markdown
+++ b/README.markdown
@@ -18,6 +18,9 @@
 
 * `git clone git://github.com/informatikr/aeson-pretty.git`
 
+# Aeson / GHC support
+We support all GHCs supported by the latest Aeson release. This in turn determines which Aeson releases we support.
+
 # Authors
 
-This library is written and maintained by Falko Peters, <falko.peters@gmail.com>.
+This library is written by Falko Peters <falko.peters@gmail.com> and maintained by Martijn Bastiaan <martijn@qbaylogic.com>.
diff --git a/aeson-pretty.cabal b/aeson-pretty.cabal
--- a/aeson-pretty.cabal
+++ b/aeson-pretty.cabal
@@ -1,20 +1,20 @@
+cabal-version:  2.0
 name:           aeson-pretty
-version:        0.7.2
+version:        0.8.11
 license:        BSD3
 license-file:   LICENSE
 category:       Text, Web, JSON, Pretty Printer
 copyright:      Copyright 2011 Falko Peters
 author:         Falko Peters <falko.peters@gmail.com>
-maintainer:     Falko Peters <falko.peters@gmail.com>
+maintainer:     Martijn Bastiaan <martijn@hmbastiaan.nl>
 stability:      experimental
-cabal-version:  >= 1.8
 homepage:       http://github.com/informatikr/aeson-pretty
 bug-reports:    http://github.com/informatikr/aeson-pretty/issues
 build-type:     Simple
 synopsis:       JSON pretty-printing library and command-line tool.
 description:
     A JSON pretty-printing library compatible with aeson as well as
-    a command-line tool to improve readabilty of streams of JSON data.
+    a command-line tool to improve readability of streams of JSON data.
     .
     The /library/ provides the function "encodePretty". It is a drop-in
     replacement for aeson's "encode" function, producing JSON-ByteStrings for
@@ -22,36 +22,41 @@
     .
     The /command-line tool/ reads JSON from stdin and writes prettified JSON
     to stdout. It also offers a complementary "compact"-mode, essentially the
-    opposite of pretty-printing. If you specify @-flib-only@ like this
-    .
-        > cabal install -flib-only aeson-pretty
-    .
-    the command-line tool will NOT be installed.
+    opposite of pretty-printing.
 
 extra-source-files:
     README.markdown
 
+extra-doc-files:
+    CHANGELOG.markdown
+
 flag lib-only
     description: Only build/install the library, NOT the command-line tool.
     default: False
+    manual: True
 
 library
     exposed-modules:
         Data.Aeson.Encode.Pretty
 
     build-depends:
-        aeson >= 0.7,
-        base >= 4.5,
+        aeson >=1.5  && <2.4,
+        base >= 4.10 && < 4.23,
+        base-compat >= 0.9,
         bytestring >= 0.9,
+        scientific >= 0.3,
         vector >= 0.9,
         text >= 0.11,
-        unordered-containers >= 0.1.3.0
+        unordered-containers >= 0.2.14.0
 
     ghc-options: -Wall
+    default-language: Haskell2010
 
 executable aeson-pretty
     hs-source-dirs: cli-tool
     main-is: Main.hs
+    other-modules: Paths_aeson_pretty
+    autogen-modules: Paths_aeson_pretty
 
     if flag(lib-only)
         buildable: False
@@ -60,12 +65,13 @@
             aeson >= 0.6,
             aeson-pretty,
             attoparsec >= 0.10,
-            base == 4.*,
+            attoparsec-aeson,
+            base >= 4.10 && < 4.23,
             bytestring >= 0.9,
             cmdargs >= 0.7
 
     ghc-options: -Wall
-    ghc-prof-options: -auto-all
+    default-language: Haskell2010
 
 source-repository head
     type:     git
diff --git a/cli-tool/Main.hs b/cli-tool/Main.hs
--- a/cli-tool/Main.hs
+++ b/cli-tool/Main.hs
@@ -1,9 +1,14 @@
-{-# LANGUAGE DeriveDataTypeable, RecordWildCards, OverloadedStrings #-}
+{-# LANGUAGE CPP, DeriveDataTypeable, RecordWildCards, OverloadedStrings, PackageImports #-}
 module Main (main) where
 
 import Prelude hiding (interact, concat, unlines, null)
-import Data.Aeson (Value(..), json', encode)
+import Data.Aeson (Value(..), encode)
 import Data.Aeson.Encode.Pretty
+#if MIN_VERSION_aeson(2,2,0)
+import "attoparsec-aeson" Data.Aeson.Parser.Internal (value')
+#else
+import "aeson" Data.Aeson.Parser.Internal (value')
+#endif
 import Data.Attoparsec.Lazy (Result(..), parse)
 import Data.ByteString.Lazy.Char8 (ByteString, interact, unlines, null)
 import Data.Version (showVersion)
@@ -15,7 +20,11 @@
                     , indent  :: Int
                     , sort    :: Bool
                     }
+#if __GLASGOW_HASKELL__ >= 912
+    deriving (Data)
+#else
     deriving (Data, Typeable)
+#endif
 
 opts :: Options
 opts = Opts
@@ -44,14 +53,16 @@
 main :: IO ()
 main = do
     Opts{..} <- cmdArgs opts
-    let conf = Config { confIndent  = indent
-                      , confCompare = if sort then compare else mempty
+    let conf = Config { confIndent          = Spaces indent
+                      , confCompare         = if sort then compare else mempty
+                      , confNumFormat       = Generic
+                      , confTrailingNewline = False
                       }
         enc = if compact then encode else encodePretty' conf
     interact $ unlines . map enc . values
 
 values :: ByteString -> [Value]
-values s = case parse json' s of
+values s = case parse value' s of
             Done rest v     -> v : values rest
             Fail rest _ _
                 | null rest -> []
