diff --git a/System/REPL/Config.hs b/System/REPL/Config.hs
new file mode 100644
--- /dev/null
+++ b/System/REPL/Config.hs
@@ -0,0 +1,88 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+
+-- |Contains logic for reading configuration files.
+module System.REPL.Config (
+   readConfigFile,
+   readConfigJSON,
+   readConfigShow,
+   NoParseError(..),
+   ) where
+
+import Prelude hiding ((++), FilePath)
+import qualified Prelude as Pr
+
+import Control.Monad.Catch
+import Control.Monad.IO.Class
+import Data.Aeson
+import qualified Data.ByteString.Lazy as BL
+import Data.Default
+import Data.Functor.Monadic
+import Data.ListLike (ListLike(append), StringLike(fromString))
+import Data.Text.Lazy.Encoding (decodeUtf8, encodeUtf8)
+import qualified Data.Text.Lazy as T
+import Data.Typeable
+import qualified Filesystem.Path.CurrentOS as Fp
+import System.Directory
+import Text.Read (readMaybe)
+
+-- |Indicates that some string was not able to be parsed.
+data NoParseError = NoParseError T.Text deriving (Show, Eq, Read, Typeable)
+
+instance Exception NoParseError
+
+-- |Creates a NoParseError out of a 'Fp.FilePath'.
+noParseError :: Fp.FilePath -> NoParseError
+noParseError = NoParseError . T.pack  .  Fp.encodeString
+
+-- |Variant of 'readConfigFile' that uses 'Show' and 'Read' for (de)serialization.
+--
+--  If the file's content's can't be parsed, a 'NoParseError' will be thrown.
+readConfigShow :: forall m a.
+                  (MonadThrow m, Functor m, MonadIO m, Default a, Show a,
+                   Read a)
+               => Fp.FilePath
+               -> m a
+readConfigShow path = readConfigFile path readEither showBL
+   where
+      showBL = encodeUtf8 . T.pack . show
+      readEither = maybe (Left $ noParseError path) Right . readMaybe . T.unpack . decodeUtf8
+
+-- |Variant of 'readConfigFile' that uses JSON for (de)serialization.
+--
+--  If the file's content's can't be parsed, a 'NoParseError' will be thrown.
+readConfigJSON :: forall m a.
+                  (MonadThrow m, Functor m, MonadIO m, Default a, ToJSON a,
+                   FromJSON a)
+               => Fp.FilePath
+               -> m a
+readConfigJSON path = readConfigFile path decodeEither encode
+   where
+      decodeEither = maybe (Left $ noParseError path) Right . decode
+
+-- |Tries to read a configuration from file. If the file is missing,
+--  a default instance is written to file and returned. The following
+--  exceptions may be thrown:
+--
+--  * @IOException@, if the IO operations associated with reading or creating the
+--    configuration file fail, and
+--  * An exception of type @e@ if the configuration file is present, but its
+--    contents can't be parsed.
+readConfigFile :: forall e m a.
+                  (MonadThrow m, Functor m, MonadIO m, Default a, Exception e)
+               => Fp.FilePath -- ^Path of the configuration file.
+               -> (BL.ByteString -> Either e a)
+                  -- ^Parser for the file's contents.
+               -> (a -> BL.ByteString)
+                  -- ^Encoder for the default value. If the given configuration
+                  --  file does not exist, a default value will be serialized
+                  --  using this function.
+               -> m a
+readConfigFile path parser writer = do
+   let pathT = Fp.encodeString path
+   liftIO $ createDirectoryIfMissing True $ Fp.encodeString $ Fp.parent path
+   exists <- liftIO $ doesFileExist $ Fp.encodeString path
+   content <- if not exists then do liftIO $ BL.writeFile pathT (writer (def :: a))
+                                    return $ Right def
+              else liftIO (BL.readFile pathT) >$> parser
+   either throwM return content
diff --git a/changelog.txt b/changelog.txt
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,1 +1,3 @@
+0.3.1 Added functionality for reading configuration files.
+
 0.3 Ditched MonadError in favour of MonadThrow. This should make the functions much easier to use.
diff --git a/repl-toolkit.cabal b/repl-toolkit.cabal
--- a/repl-toolkit.cabal
+++ b/repl-toolkit.cabal
@@ -2,8 +2,8 @@
 -- documentation, see http://haskell.org/cabal/users-guide/
 
 name:                repl-toolkit
-version:             0.3.0.0
-synopsis:            Toolkit for quickly whipping up command-line interfaces.
+version:             0.3.1.0
+synopsis:            Toolkit for quickly whipping up config files and command-line interfaces.
 description:         A simple toolkit for quickly whipping up REPLs, input validation and sets of commands included.
 homepage:            https://github.com/ombocomp/repl-toolkit
 license:             Apache-2.0
@@ -20,8 +20,9 @@
   location: git://github.com/ombocomp/repl-toolkit.git
 
 library
-  exposed-modules:     System.REPL, System.REPL.State, System.REPL.Command
-  other-extensions:    OverloadedStrings, DeriveDataTypeable, FlexibleContexts, LambdaCase
-  build-depends:       base >=4.7 && <5, functor-monadic >=0.1, text >=1.1, ListLike >=4.1, exceptions >=0.4, parsec >=3.1, numericpeano >= 0.1, listsafe >= 0.1, monad-loops >= 0.3, mtl >= 2.2, transformers >= 0.3
+  exposed-modules:     System.REPL, System.REPL.State, System.REPL.Command,
+                       System.REPL.Config
+  other-extensions:    OverloadedStrings, DeriveDataTypeable, FlexibleContexts, LambdaCase, ScopedTypeVariables
+  build-depends:       base >=4.7 && <5, functor-monadic >=0.1, text >=1.1, ListLike >=4.1, exceptions >=0.4, parsec >=3.1, numericpeano >= 0.1, listsafe >= 0.1, monad-loops >= 0.3, mtl >= 2.2, transformers >= 0.3, directory >= 1.2.1, system-filepath >= 0.4.13, bytestring >= 0.10, data-default >= 0.5.3, aeson >=0.8.0.2
   default-language:    Haskell2010
 
