diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # Revision history for aeson-combinators
 
+## 0.0.4.1 -- 2021-02-14
+* Cleanup README
+* CI maintanance & GHC compatibility update
+
 ## 0.0.4.0 -- 2020-10-24
 * `Encode` module for encoding
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -4,22 +4,24 @@
 [![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2FturboMaCk%2Faeson-combinators%2Fbadge%3Fref%3Dmaster&style=flat)](https://actions-badge.atrox.dev/turboMaCk/aeson-combinators/goto?ref=master)
 [![built with nix](https://builtwithnix.org/badge.svg)](https://builtwithnix.org)
 
-[**Low overhead**](#internals) value space `Decoder`
+[**Low overhead**](#performance) value space `Decoder`
 on top of Aeson's Parser for combinator style decoding.
 
 This library is compatible with GHC as well as recent versions of **GHCJS**.
 
-__Encoding to JSON is currently not supported but might be added in the future version.__
-
 I wrote a [blob post](https://turbomack.github.io/posts/2020-02-21-value-space-decoding-for-aeson.html)
 describing what this library attempts to solve.
 
-## Internals
+## Performance
 
-`Decoder a` type is a function `Value -> Parser a` the same as `fromJSON`
+`Decoder a` type is a function `Value -> Parser a` the same as `parseJSON`
 member function of `FromJSON` class. This means there should be near zero overhead.
 Aeson types and functions are reused where possible. Similarly `Encoder a` type
 follow `toJSON` from `ToJSON` type class.
+
+Simple benchmark shows that implementation using aeson-combinators performs better
+than equivalent derived instance and on par (actually even slightly better though with difference in noise range)
+with manually implemented instance.
 
 ## License
 
diff --git a/aeson-combinators.cabal b/aeson-combinators.cabal
--- a/aeson-combinators.cabal
+++ b/aeson-combinators.cabal
@@ -1,6 +1,6 @@
 cabal-version:       >=1.10
 name:                aeson-combinators
-version:             0.0.4.0
+version:             0.0.4.1
 synopsis:            Aeson combinators for dead simple JSON decoding
 description:
     Low overhead value space `Decoder`
@@ -21,7 +21,9 @@
 tested-with:         GHC == 8.4.4
                    , GHC == 8.6.5
                    , GHC == 8.8.3
+                   , GHC == 8.8.4
                    , GHC == 8.10.1
+                   , GHC == 8.10.3
                    , GHCJS == 8.6.0.1
 
 Flag doctest
@@ -52,6 +54,19 @@
   default-language:    Haskell2010
   hs-source-dirs:      lib
 
+benchmark benchmark
+    type:              exitcode-stdio-1.0
+    main-is:           Main.hs
+    hs-source-dirs:    benchmarks
+    build-depends:     base
+                     , aeson
+                     , aeson-combinators
+                     , bytestring
+                     , criterion
+                     , deepseq
+                     , text
+    ghc-options:       -Wall
+    default-language:  Haskell2010
 
 test-suite spec
     type:              exitcode-stdio-1.0
@@ -80,7 +95,6 @@
     else
         build-depends:    base
                         , doctest
-
 
 source-repository head
   type:              git
diff --git a/benchmarks/Main.hs b/benchmarks/Main.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/Main.hs
@@ -0,0 +1,102 @@
+{-# LANGUAGE BangPatterns       #-}
+{-# LANGUAGE DeriveAnyClass     #-}
+{-# LANGUAGE DeriveGeneric      #-}
+{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE FlexibleInstances  #-}
+{-# LANGUAGE OverloadedStrings  #-}
+{-# LANGUAGE TypeApplications   #-}
+
+import           Control.DeepSeq               (NFData)
+import           Criterion                     (Benchmark, nf)
+import           Data.Aeson.Combinators.Decode (Decoder)
+import           Data.Aeson.Types              (FromJSON, ToJSON, withObject,
+                                                (.:))
+import           Data.ByteString.Lazy          (ByteString)
+import           GHC.Generics                  (Generic)
+
+import qualified Criterion.Main                as Criterion
+import qualified Data.Aeson                    as Aeson
+import qualified Data.Aeson.Combinators.Decode as Decode
+
+
+bench :: NFData b => String -> (a -> b) -> (Int -> a) -> [Benchmark]
+bench name f gen = fmap (\i -> let !n         = 10 ^ i
+                                   !generated = gen n
+                               in Criterion.bench (name <> " " <> show n) $ (nf f) generated
+                        ) ([1..4] :: [Int])
+{-# INLINE bench #-}
+
+
+main :: IO ()
+main =
+  Criterion.defaultMain
+    [ Criterion.bgroup "Combinators decoder nested" $
+        bench "nested" (Decode.decode deeplyNestedDecoder) deeplyNestedValue
+    , Criterion.bgroup "Derived (generic) decoder nested" $
+        bench "nested" (Aeson.decode @ DeeplyNested) deeplyNestedValue
+    , Criterion.bgroup "Implemented instance decoder nested" $
+        bench "nested" (Aeson.decode @ DeeplyNested') deeplyNestedValue
+    , Criterion.bgroup "Combinators decoder narrow" $
+        bench "narrow" (Decode.decode narrowDecoder) narrowValue
+    , Criterion.bgroup "Derived (generic) decoder narrow" $
+        bench "narrow" (Aeson.decode @ Narrow) narrowValue
+    , Criterion.bgroup "Implemented instance decoder narrow" $
+        bench "narrow" (Aeson.decode @ Narrow') narrowValue
+    ]
+
+
+data DeeplyNested = DeeplyNested
+    { nested :: ![DeeplyNested]
+    } deriving stock (Show, Generic)
+      deriving anyclass (FromJSON, NFData, ToJSON)
+
+
+deeplyNestedDecoder :: Decoder DeeplyNested
+deeplyNestedDecoder = DeeplyNested
+  <$> Decode.key "nested" (Decode.list deeplyNestedDecoder)
+
+
+deeplyNestedValue :: Int -> ByteString
+deeplyNestedValue depth = Aeson.encode $ go depth (DeeplyNested [])
+  where
+    go :: Int -> DeeplyNested -> DeeplyNested
+    go n dn
+      | n <= 0 = dn
+      | otherwise = go (n - 1) $ DeeplyNested [dn]
+
+
+data DeeplyNested' = DeeplyNested'
+    { nested' :: ![DeeplyNested']
+    } deriving stock (Show, Generic)
+      deriving anyclass (NFData)
+
+
+instance FromJSON DeeplyNested' where
+  parseJSON = withObject "DeeplyNested'" $ \v ->
+    DeeplyNested' <$> v .: "nested"
+
+
+data Narrow = Narrow
+    { narrow :: ![Int]
+    } deriving stock (Show, Generic)
+      deriving anyclass (FromJSON, NFData, ToJSON)
+
+
+narrowDecoder :: Decoder Narrow
+narrowDecoder = Narrow
+  <$> Decode.key "narrow" (Decode.list Decode.int)
+
+
+narrowValue :: Int -> ByteString
+narrowValue width = Aeson.encode $ Narrow [1..width]
+
+
+data Narrow' = Narrow'
+    { narrow' :: ![Int]
+    } deriving stock (Show, Generic)
+      deriving anyclass (NFData)
+
+
+instance FromJSON Narrow' where
+  parseJSON = withObject "narrow'" $ \v ->
+    Narrow' <$> v .: "narrow"
