diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Author name here (c) 2016
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Author name here nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,15 @@
+# aeson-prefix
+
+Hiearchical prefixing of JSON objects from [Aeson](https://hackage.haskell.org/package/aeson).
+
+## Installation
+
+Run either `cabal install` or `stack install`. This is library, thus there is no executable available.
+
+## Running tests
+
+Tests can be run via `stack test`.
+
+## Discalmer
+
+Any feedback is very welcomed.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/aeson-prefix.cabal b/aeson-prefix.cabal
new file mode 100644
--- /dev/null
+++ b/aeson-prefix.cabal
@@ -0,0 +1,44 @@
+name:                aeson-prefix
+version:             0.1.0.0
+synopsis:            Hiearchical prefixing for aeson
+description:         Please see README.md
+homepage:            https://github.com/j1r1k/aeson-prefix#readme
+license:             BSD3
+license-file:        LICENSE
+author:              Jiri Marsicek
+maintainer:          jiri.marsicek@gmail.com
+copyright:           2016 Jiri Marsicek
+category:            Text, Web, JSON
+build-type:          Simple
+extra-source-files:  README.md
+cabal-version:       >=1.10
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     Data.Aeson.Prefix
+  build-depends:       base >= 4.7 && < 5
+                     , aeson
+                     , mtl
+                     , text
+                     , unordered-containers
+                     , vector
+  ghc-options:         -Wall
+  default-language:    Haskell2010
+
+test-suite aeson-prefix-test
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      test
+  main-is:             Spec.hs
+  build-depends:       base
+                     , aeson
+                     , aeson-prefix
+                     , bytestring
+                     , hspec
+                     , mtl
+                     , text
+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N -Wall
+  default-language:    Haskell2010
+
+source-repository head
+  type:     git
+  location: https://github.com/j1r1k/aeson-prefix
diff --git a/src/Data/Aeson/Prefix.hs b/src/Data/Aeson/Prefix.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Aeson/Prefix.hs
@@ -0,0 +1,134 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE FlexibleContexts #-}
+-- |
+-- Module: Data.Aeson.Prefix
+-- Maintainer: Jiri Marsicek <jiri.marsicek@gmail.com>
+--
+-- Hiearchical prefixing of JSON objects from 'Data.Aeson'
+-- Please see examples for understanding what does it mean.
+--
+-- == Examples
+--
+-- usage of 'prefix'
+--
+-- === Basic
+--
+-- @{ "a": { "b": 1 } }@ results in @{ "a": { "a.b": 2 }@
+--
+-- @{ "a": { "b": { "c": 1 } } }@ results in @{ "a": { "a.b": { "a.b.c": 1 } } }@
+--
+-- === Arrays
+--
+-- @{ "a": [ { "b": 1 }, { "b": 2 } ] }@ is not changed
+--
+-- * Arrays don't inherit the prefix from their parent keys by default
+--
+-- === With 'optionPreservePrefix' set to 'True'
+-- 
+-- @{ "a": [ { "b": 1 }, { "b": 2 } ] }@ results in @{ "a": [ { "a.b": 1 }, { "a.b": 2 } ] }@
+--
+-- === With 'optionPrefix' set to "prefix"
+--
+-- @{ "a": 1 }@ results in @{ "prefix.a": 1 }@
+--
+-- * This affects only keys in top level object. If array is top level, it doesn't take effect
+--
+-- === With 'optionSeparator' set to "~"
+--
+-- @{ "a": { "b": 1 } }@ results in @{ "a": { "a~b": 2 } }@
+module Data.Aeson.Prefix
+    ( prefix
+    -- * Options
+    , Options(..)
+    , Prefix
+    , Separator
+    , defaultOptions
+    -- * Utility functions and types
+    , Pair
+    , prefixKey
+    , prefixPair
+    , withPrefix
+    , withoutPrefix
+    ) where
+import Control.Monad.Reader (MonadReader, asks, local)
+
+import Data.Aeson
+import qualified Data.HashMap.Strict as Map (fromList, toList)
+import Data.Monoid ((<>))
+import qualified Data.Vector as Vector (mapM)
+import Data.Text (Text)
+import qualified Data.Text as Text (singleton)
+
+type Pair = (Text, Value)
+type Prefix = Maybe Text
+type Separator = Text
+
+data Options = Options {
+    -- |
+    -- Preserve prefix in Arrays, objects in arrays preserve prefix from their parent key
+    optionPreservePrefix :: Bool
+    -- |
+    -- Separator, text to delimit a prefix from a key
+  , optionSeparator :: Separator
+    -- |
+    -- Prefix, prefix added to all keys of top level object
+  , optionPrefix :: Prefix
+  } deriving Show
+
+-- |
+-- Default options
+-- 
+-- * 'optionPreservePrefix' set to 'False'
+-- * 'optionSeparator' set to "."
+-- * 'optionPrefix' set to 'Nothing'
+defaultOptions :: Options
+defaultOptions = Options False (Text.singleton '.') Nothing
+
+-- |
+-- Change options to use supplied prefix
+withPrefix :: Prefix -> Options -> Options
+withPrefix p o = o { optionPrefix = p }
+
+-- |
+-- Change options to not use any prefix
+withoutPrefix :: Options -> Options
+withoutPrefix o = o { optionPrefix = Nothing }
+
+-- |
+-- Prefixes text with prefix if defined in options, a separator from options is used to delimit prefix and text
+prefixKey :: forall m . (Monad m, MonadReader Options m) => Text -> m Text
+prefixKey t = do
+  sep <- asks optionSeparator
+  pre <- asks optionPrefix
+  return $ maybe t (\p -> p <> sep <> t) pre
+
+-- |
+-- Prefixes identifier (first in pair), this prefixed identifier is used as a prefix for value (second in pair)
+prefixPair :: forall m . (Monad m, MonadReader Options m) => Pair -> m Pair
+prefixPair (i, v) = do
+  pk <- prefixKey i
+  pv <- local (withPrefix $ Just pk) $ prefix v
+  return (pk, pv)
+
+-- |
+-- Convert `Object` to list of `Pair`s
+objectToPairs :: Object -> [Pair]
+objectToPairs = Map.toList
+
+-- Convert list of `Pair`s to `Object`
+pairsToObject :: [Pair] -> Object
+pairsToObject = Map.fromList
+
+-- |
+-- Prefixes supplied `Value` using `Options`
+prefix :: forall m . (Monad m, MonadReader Options m) => Value -> m Value
+prefix (Array a)  = do
+  preserve <- asks optionPreservePrefix
+  let prefixed = Array <$> Vector.mapM prefix a
+  if preserve
+    then prefixed
+    else local withoutPrefix prefixed
+prefix (Object o) = do
+  p <- mapM prefixPair $ objectToPairs o
+  return $ Object $ pairsToObject p
+prefix v = return v
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,117 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+import Test.Hspec
+
+import Control.Monad.Reader (runReader)
+
+import Data.Aeson
+import Data.Aeson.Prefix
+import Data.ByteString (ByteString)
+import Data.Maybe (fromJust)
+import Data.Text (Text)
+
+defaultSeparator :: Separator
+defaultSeparator = "."
+
+defaultPrefix :: Text
+defaultPrefix = "prefix"
+
+optionsDefault :: Options
+optionsDefault = Options False defaultSeparator Nothing
+
+optionsPrefixArrays :: Options
+optionsPrefixArrays = Options True defaultSeparator Nothing
+
+optionsWithPrefix :: Options
+optionsWithPrefix = Options False defaultSeparator (Just defaultPrefix)
+
+optionsWithPrefixAndPrefixArrays :: Options
+optionsWithPrefixAndPrefixArrays = Options True defaultSeparator (Just defaultPrefix)
+
+decodeExample :: ByteString -> Value
+decodeExample = fromJust . decodeStrict'
+
+prefixTest :: Options -> ByteString -> ByteString -> Expectation
+prefixTest opts input expected = (flip runReader opts . prefix) (decodeExample input) `shouldBe` decodeExample expected
+
+allOptions :: [Options]
+allOptions = [ optionsDefault
+             , optionsPrefixArrays
+             , optionsWithPrefix
+             , optionsWithPrefixAndPrefixArrays
+             ]
+
+-- Test Inputs
+
+inputSimple :: ByteString
+inputSimple = "{ \"a\": 1 }"
+
+inputOneLevel :: ByteString
+inputOneLevel = "{ \"a\": { \"b\": 1, \"c\": 2 } }"
+
+inputTwoLevel :: ByteString
+inputTwoLevel = "{ \"a\": { \"b\": { \"d\": 1 }, \"c\": { \"e\": 2 } } }"
+
+inputTopArray :: ByteString
+inputTopArray = "[ { \"a\": { \"b\": 1 } }, { \"a\": { \"b\": 2 } } ]"
+
+inputWithArrayOneLevel :: ByteString
+inputWithArrayOneLevel = "{ \"a\": [ { \"b\": { \"c\": 1 } }, { \"b\": { \"c\": 2 } } ] }"
+
+main :: IO ()
+main = hspec $
+  describe "Data.Aeson.Prefix" $
+    describe "prefix" $ do
+      it "doesn't change empty object" $
+        mapM_ (\o -> prefixTest o "{}" "{}") allOptions
+      it "doesn't change flat array" $ do
+        let input = "[\"a\", \"b\"]"
+        mapM_ (\o -> prefixTest o input input) allOptions
+      describe "default options" $ do
+        let shouldResultIn = prefixTest optionsDefault
+        it "doesn't change simple object" $ 
+          inputSimple `shouldResultIn` inputSimple
+        it "works for one level prefixing" $ 
+          inputOneLevel `shouldResultIn` "{ \"a\": { \"a.b\": 1, \"a.c\": 2 } }"
+        it "works with two level prefixing" $ 
+          inputTwoLevel `shouldResultIn` "{ \"a\": { \"a.b\": { \"a.b.d\": 1 }, \"a.c\": { \"a.c.e\": 2 } } }"
+        it "works with top level array of one level prefixing" $
+          inputTopArray `shouldResultIn` "[ { \"a\": { \"a.b\": 1 } }, { \"a\": { \"a.b\": 2 } } ]"
+        it "works with array of one level prefixing" $ 
+          inputWithArrayOneLevel `shouldResultIn` "{ \"a\": [ { \"b\": {\"b.c\": 1 } }, { \"b\": { \"b.c\": 2 } } ] }"
+      describe "options with prefixArrays" $ do
+        let shouldResultIn = prefixTest optionsPrefixArrays
+        it "doesn't change simple object" $ 
+          inputSimple `shouldResultIn` inputSimple
+        it "works for one level prefixing" $ 
+          inputOneLevel `shouldResultIn` "{ \"a\": { \"a.b\": 1, \"a.c\": 2 } }"
+        it "works with two level prefixing" $ 
+          inputTwoLevel `shouldResultIn` "{ \"a\": { \"a.b\": { \"a.b.d\": 1 }, \"a.c\": { \"a.c.e\": 2 } } }"
+        it "works with top level array of one level prefixing" $
+          inputTopArray `shouldResultIn` "[ { \"a\": { \"a.b\": 1 } }, { \"a\": { \"a.b\": 2 } } ]"
+        it "works with array of one level prefixing" $ 
+          inputWithArrayOneLevel `shouldResultIn` "{ \"a\": [ { \"a.b\": {\"a.b.c\": 1 } }, { \"a.b\": { \"a.b.c\": 2 } } ] }"
+      describe "options with user defined prefix" $ do
+        let shouldResultIn = prefixTest optionsWithPrefix
+        it "doesn't change simple object" $ 
+          inputSimple `shouldResultIn` "{ \"prefix.a\": 1 }"
+        it "works for one level prefixing" $ 
+          inputOneLevel `shouldResultIn` "{ \"prefix.a\": { \"prefix.a.b\": 1, \"prefix.a.c\": 2 } }"
+        it "works with two level prefixing" $ 
+          inputTwoLevel `shouldResultIn` "{ \"prefix.a\": { \"prefix.a.b\": { \"prefix.a.b.d\": 1 }, \"prefix.a.c\": { \"prefix.a.c.e\": 2 } } }"
+        it "works with top level array of one level prefixing" $
+          inputTopArray `shouldResultIn` "[ { \"a\": { \"a.b\": 1 } }, { \"a\": { \"a.b\": 2 } } ]"
+        it "works with array of one level prefixing" $ 
+          inputWithArrayOneLevel `shouldResultIn` "{ \"prefix.a\": [ { \"b\": {\"b.c\": 1 } }, { \"b\": { \"b.c\": 2 } } ] }"
+      describe "options with prefixArrays and user defined prefix" $ do
+        let shouldResultIn = prefixTest optionsWithPrefixAndPrefixArrays
+        it "doesn't change simple object" $ 
+          inputSimple `shouldResultIn` "{ \"prefix.a\": 1 }"
+        it "works for one level prefixing" $ 
+          inputOneLevel `shouldResultIn` "{ \"prefix.a\": { \"prefix.a.b\": 1, \"prefix.a.c\": 2 } }"
+        it "works with two level prefixing" $ 
+          inputTwoLevel `shouldResultIn` "{ \"prefix.a\": { \"prefix.a.b\": { \"prefix.a.b.d\": 1 }, \"prefix.a.c\": { \"prefix.a.c.e\": 2 } } }"
+        it "works with top level array of one level prefixing" $
+          inputTopArray `shouldResultIn` "[ { \"prefix.a\": { \"prefix.a.b\": 1 } }, { \"prefix.a\": { \"prefix.a.b\": 2 } } ]"
+        it "works with array of one level prefixing" $ 
+          inputWithArrayOneLevel `shouldResultIn` "{ \"prefix.a\": [ { \"prefix.a.b\": {\"prefix.a.b.c\": 1 } }, { \"prefix.a.b\": { \"prefix.a.b.c\": 2 } } ] }"
