diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,8 @@
 ## MASTER
+## Dotenv 0.10.0.0
+### Modified
+* `loadFile` change return type (back to `m ()`)
+
 ## Dotenv 0.9.0.3
 ### Added
 * Parse multi-word command interpolations (Kudos to @pbrisbin)
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -50,7 +50,7 @@
 
 ### Variable substitution
 
-In order to use compound env vars use the following sintax within your env vars
+In order to use compound env vars use the following syntax within your env vars
 ${your_env_var}. For instance:
 
 ```
@@ -66,8 +66,7 @@
 
 ### Command substitution
 
-In order to use the standard output of a command in your env vars use the following
-sintax $(your_command). For instance:
+In order to use the standard output of a command in your env vars use the following syntax $(your_command). For instance:
 
 ```
 DATABASE=postgres://$(whoami)@localhost/database
@@ -82,7 +81,7 @@
 
 ### Configuration
 
-The first argument to `loadFile` specifies the configuration. You cans use
+The first argument to `loadFile` specifies the configuration. You can use
 `defaultConfig` which parses the `.env` file in your current directory and
 doesn't override your envs. You can also define your own configuration with
 the `Config` type.
@@ -99,6 +98,11 @@
 (e.g `[".env.example", ".tokens.example", ".public_keys.example"]`). If you don't
 need this functionality you can set `configExamplePath` to an empty list.
 
+A `False` in the `configVerbose` means that Dotenv will not print any message
+when loading the envs. A `True` means that Dotenv will print a message when a variable is loaded.
+
+A `False` on `allowDuplicates` means that Dotenv will not allow duplicate keys, and instead it will throw
+an error. A `True` means that Dotenv will allow duplicate keys, and it will use the first one if,`configOverride` is not set to `True`.
 ### Advanced Dotenv File Syntax
 
 You can add comments to your Dotenv file, on separate lines or after
@@ -118,14 +122,13 @@
 $ dotenv -f mydotenvfile myprogram
 ```
 
-The `-f` flag is optional, by default it looks for the `.env` file in the current
-working directory.
+The `-f` flag is optional, by default it looks for the `.env` file in the current working directory.
 
 ```shell
 $ dotenv myprogram
 ```
 
-Aditionally you can pass arguments and flags to the program passed to
+Additionally, you can pass arguments and flags to the program passed to
 Dotenv:
 
 ```shell
@@ -181,5 +184,5 @@
 Do you want to contribute to this project? Please take a look at our [contributing guideline](/docs/CONTRIBUTING.md) to know how you can help us build it.
 
 ---
-<img src="https://www.stackbuilders.com/media/images/Sb-supports.original.png" alt="Stack Builders" width="50%"></img>
+<img src="https://cdn.stackbuilders.com/media/images/Sb-supports.original.png" alt="Stack Builders" width="50%"></img>
 [Check out our libraries](https://github.com/stackbuilders/) | [Join our team](https://www.stackbuilders.com/join-us/)
diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -11,10 +11,7 @@
 import           Options.Applicative
 import           Paths_dotenv         (version)
 
-import           Control.Monad        (void)
-
 import           Configuration.Dotenv (Config (..), defaultConfig, loadFile)
-
 import           System.Exit          (exitWith)
 import           System.Process       (system)
 
@@ -22,6 +19,8 @@
   { dotenvFiles        :: [String]
   , dotenvExampleFiles :: [String]
   , override           :: Bool
+  , verbose            :: Bool
+  , duplicates         :: Bool
   , program            :: String
   , args               :: [String]
   } deriving (Show)
@@ -33,13 +32,15 @@
         Config
           { configExamplePath = dotenvExampleFiles
           , configOverride = override
+          , configVerbose = verbose
+          , allowDuplicates = duplicates
           , configPath =
               if null dotenvFiles
                 then configPath defaultConfig
                 else dotenvFiles
           }
    in do
-     void $ loadFile configDotenv
+     loadFile configDotenv
      system (program ++ concatMap (" " ++) args) >>= exitWith
        where
          opts = info (helper <*> versionOption <*> config)
@@ -67,6 +68,14 @@
      <*> switch ( long "overload"
                   <> short 'o'
                   <> help "Specify this flag to override existing variables" )
+
+     <*> switch (  long "verbose"
+                  <> help "Specify this flag to print out the variables loaded and other useful insights" )
+
+     <*> flag True False (  long "no-dups"
+                  <> short 'D'
+                  <> help "Specify this flag to forbid duplicate variables"
+                  )
 
      <*> argument str (metavar "PROGRAM")
 
diff --git a/dotenv.cabal b/dotenv.cabal
--- a/dotenv.cabal
+++ b/dotenv.cabal
@@ -1,5 +1,5 @@
 name:                dotenv
-version:             0.9.0.3
+version:             0.10.0.0
 synopsis:            Loads environment variables from dotenv files
 homepage:            https://github.com/stackbuilders/dotenv-hs
 description:
diff --git a/spec/Configuration/DotenvSpec.hs b/spec/Configuration/DotenvSpec.hs
--- a/spec/Configuration/DotenvSpec.hs
+++ b/spec/Configuration/DotenvSpec.hs
@@ -12,7 +12,7 @@
 
 import           Test.Hspec
 
-import           Control.Monad                    (liftM, void)
+import           Control.Monad                    (liftM)
 import           Data.Maybe                       (fromMaybe)
 import           System.Process                   (readCreateProcess, shell)
 
@@ -47,31 +47,30 @@
     it "loads the configuration options to the environment from a file" $ do
       lookupEnv "DOTENV" `shouldReturn` Nothing
 
-      void $ loadFile $ Config ["spec/fixtures/.dotenv"] [] False
+      loadFile sampleConfig
 
       lookupEnv "DOTENV" `shouldReturn` Just "true"
 
     it "respects predefined settings when overload is false" $ do
       setEnv "DOTENV" "preset"
 
-      void $ loadFile $ Config ["spec/fixtures/.dotenv"] [] False
+      loadFile sampleConfig
 
       lookupEnv "DOTENV" `shouldReturn` Just "preset"
 
     it "overrides predefined settings when overload is true" $ do
       setEnv "DOTENV" "preset"
 
-      void $ loadFile $ Config ["spec/fixtures/.dotenv"] [] True
+      loadFile sampleConfig { configOverride = True }
 
       lookupEnv "DOTENV" `shouldReturn` Just "true"
 
     context "when the .env.example is present" $ do
-      let config = Config ["spec/fixtures/.dotenv"] ["spec/fixtures/.dotenv.example"] False
-
+      let config = sampleConfig { configExamplePath = ["spec/fixtures/.dotenv.example"]}
       context "when the needed env vars are missing" $
         it "should fail with an error call" $ do
           unsetEnv "ANOTHER_ENV"
-          void $ loadFile config `shouldThrow` anyErrorCall
+          loadFile config `shouldThrow` anyErrorCall
 
       context "when the needed env vars are not missing" $
         it "should succeed when loading all of the needed env vars" $ do
@@ -80,7 +79,7 @@
           home <- fromMaybe "" <$> lookupEnv "HOME"
 
           -- Load envs
-          void $ loadFile config
+          loadFile config
 
           -- Check existing envs
           lookupEnv "ENVIRONMENT" `shouldReturn` Just home
@@ -125,17 +124,29 @@
   describe "onMissingFile" $ after_ clearEnvs $ do
     context "when target file is present" $
       it "loading works as usual" $ do
-        void $ onMissingFile (loadFile $ Config ["spec/fixtures/.dotenv"] [] True) (return [])
+        onMissingFile (loadFile sampleConfig {configOverride = True}) (return ())
         lookupEnv "DOTENV" `shouldReturn` Just "true"
 
     context "when target file is missing" $
       it "executes supplied handler instead" $
-        onMissingFile (True <$ loadFile (Config ["spec/fixtures/foo"] [] True)) (return False)
+        onMissingFile (True <$ loadFile sampleConfig {configPath= ["spec/fixtures/.foo"], configOverride = True}) (return False)
           `shouldReturn` False
 
+  describe "onDuplicatedKeys" $ after_ clearEnvs $ do
+    context "when duplicates are forbidden" $ do
+      it "throws an error on duplicated keys" $
+        loadFile sampleConfig { configPath = ["spec/fixtures/.dotenv", "spec/fixtures/.dotenv"], allowDuplicates = False }
+          `shouldThrow` anyIOException
+      it "works as usual when there is no duplicated keys" $ do
+        loadFile sampleConfig { allowDuplicates = False }
+        lookupEnv "DOTENV" `shouldReturn` Just "true"
+
+sampleConfig :: Config
+sampleConfig = Config ["spec/fixtures/.dotenv"] [] False False True
+
 clearEnvs :: IO ()
 clearEnvs =
-  fmap (fmap fst) getEnvironment >>=  mapM_ unsetEnv
+  getEnvironment >>= mapM_ unsetEnv . fmap fst
 
 setupEnv :: IO ()
 setupEnv = do
diff --git a/src/Configuration/Dotenv.hs b/src/Configuration/Dotenv.hs
--- a/src/Configuration/Dotenv.hs
+++ b/src/Configuration/Dotenv.hs
@@ -8,100 +8,136 @@
 -- Portability :  portable
 --
 -- This module contains common functions to load and read dotenv files.
-
 {-# LANGUAGE RecordWildCards #-}
 
 module Configuration.Dotenv
-  (
-  -- * Dotenv Load Functions
+  ( -- * Dotenv Load Functions
     load
   , loadFile
   , parseFile
   , onMissingFile
-  -- * Dotenv Types
+      -- * Dotenv Types
   , module Configuration.Dotenv.Types
-  )
- where
+  ) where
 
 import           Configuration.Dotenv.Environment    (getEnvironment, lookupEnv,
                                                       setEnv)
 import           Configuration.Dotenv.Parse          (configParser)
 import           Configuration.Dotenv.ParsedVariable (interpolateParsedVariables)
-import           Configuration.Dotenv.Types          (Config (..),
-                                                      defaultConfig)
-import           Control.Monad                       (liftM)
+import           Configuration.Dotenv.Types          (Config (..), ReaderT, ask,
+                                                      defaultConfig,
+                                                      liftReaderT, runReaderT)
+import           Control.Exception                   (throw)
+import           Control.Monad                       (when)
 import           Control.Monad.Catch
+import           Control.Monad.Compat                (unless)
 import           Control.Monad.IO.Class              (MonadIO (..))
 import           Data.List                           (intersectBy, union,
                                                       unionBy)
 import           System.IO.Error                     (isDoesNotExistError)
 import           Text.Megaparsec                     (errorBundlePretty, parse)
 
+-- | Monad Stack for the application
+type DotEnv m a = ReaderT Config m a
+
 -- | Loads the given list of options into the environment. Optionally
 -- override existing variables with values from Dotenv files.
 load ::
-  MonadIO m =>
-  Bool -- ^ Override existing settings?
+     MonadIO m
+  => Bool -- ^ Override existing settings?
   -> [(String, String)] -- ^ List of values to be set in environment
   -> m ()
-load override = mapM_ (applySetting override)
+load override kv =
+  runReaderT (mapM_ applySetting kv) defaultConfig {configOverride = override}
 
 -- | @loadFile@ parses the environment variables defined in the dotenv example
 -- file and checks if they are defined in the dotenv file or in the environment.
 -- It also allows to override the environment variables defined in the environment
 -- with the values defined in the dotenv file.
-loadFile
-  :: MonadIO m
+loadFile ::
+     MonadIO m
   => Config -- ^ Dotenv configuration
-  -> m [(String, String)] -- ^ Environment variables loaded
-loadFile Config{..} = do
+  -> m ()
+loadFile config@Config {..} = do
   environment <- liftIO getEnvironment
-  readedVars <- concat `liftM` mapM parseFile configPath
-  neededVars <- concat `liftM` mapM parseFile configExamplePath
-  let coincidences = (environment `union` readedVars) `intersectEnvs` neededVars
+  readVars <- fmap concat (mapM parseFile configPath)
+  neededVars <- fmap concat (mapM parseFile configExamplePath)
+  let coincidences = (environment `union` readVars) `intersectEnvs` neededVars
       cmpEnvs env1 env2 = fst env1 == fst env2
       intersectEnvs = intersectBy cmpEnvs
       unionEnvs = unionBy cmpEnvs
       vars =
         if (not . null) neededVars
-          then
-            if length neededVars == length coincidences
-              then readedVars `unionEnvs` neededVars
-              else error $ "Missing env vars! Please, check (this/these) var(s) (is/are) set:" ++ concatMap ((++) " " . fst) neededVars
-          else readedVars
-  mapM (applySetting configOverride) vars
+          then if length neededVars == length coincidences
+                 then readVars `unionEnvs` neededVars
+                 else error $
+                      "Missing env vars! Please, check (this/these) var(s) (is/are) set:" ++
+                      concatMap ((++) " " . fst) neededVars
+          else readVars
+  unless allowDuplicates $ (lookUpDuplicates . map fst) vars
+  runReaderT (mapM_ applySetting vars) config
 
 -- | Parses the given dotenv file and returns values /without/ adding them to
 -- the environment.
 parseFile ::
-  MonadIO m =>
-  FilePath -- ^ A file containing options to read
+     MonadIO m
+  => FilePath -- ^ A file containing options to read
   -> m [(String, String)] -- ^ Variables contained in the file
 parseFile f = do
   contents <- liftIO $ readFile f
-
   case parse configParser f contents of
     Left e        -> error $ errorBundlePretty e
     Right options -> liftIO $ interpolateParsedVariables options
 
-applySetting :: MonadIO m => Bool -> (String, String) -> m (String, String)
-applySetting override (key, value) =
-  if override
-    then liftIO (setEnv key value) >> return (key, value)
+applySetting ::
+     MonadIO m
+  => (String, String) -- ^ A key-value pair to set in the environment
+  -> DotEnv m (String, String)
+applySetting kv@(k, v) = do
+  Config {..} <- ask
+  if configOverride
+    then info kv >> setEnv'
     else do
-      res <- liftIO $ lookupEnv key
-
+      res <- liftReaderT . liftIO $ lookupEnv k
       case res of
-        Nothing -> liftIO $ setEnv key value >> return (key, value)
-        Just _  -> return (key, value)
+        Nothing -> info kv >> setEnv'
+        Just _  -> return kv
+  where
+    setEnv' = liftReaderT . liftIO $ setEnv k v >> return kv
 
+-- | The function logs in console when a variable is loaded into the
+-- environment.
+info :: MonadIO m => (String, String) -> DotEnv m ()
+info (key, value) = do
+  Config {..} <- ask
+  when configVerbose $
+    liftReaderT . liftIO $
+    putStrLn $ "[INFO]: Load env '" ++ key ++ "' with value '" ++ value ++ "'"
+
 -- | The helper allows to avoid exceptions in the case of missing files and
 -- perform some action instead.
 --
 -- @since 0.3.1.0
-
-onMissingFile :: MonadCatch m
+onMissingFile ::
+     MonadCatch m
   => m a -- ^ Action to perform that may fail because of missing file
-  -> m a               -- ^ Action to perform if file is indeed missing
+  -> m a -- ^ Action to perform if file is indeed missing
   -> m a
 onMissingFile f h = catchIf isDoesNotExistError f (const h)
+
+-- | The helper throws an exception if the allow duplicate is set to False.
+forbidDuplicates :: MonadIO m => String -> m ()
+forbidDuplicates key =
+  throw $
+  userError $
+  "[ERROR]: Env '" ++
+  key ++
+  "' is duplicated in a dotenv file. Please, fix that (or remove --no-dups)."
+
+lookUpDuplicates :: MonadIO m => [String] -> m ()
+lookUpDuplicates [] = return ()
+lookUpDuplicates [_] = return ()
+lookUpDuplicates (x:xs) =
+  if x `elem` xs
+    then forbidDuplicates x
+    else lookUpDuplicates xs
diff --git a/src/Configuration/Dotenv/Parse.hs b/src/Configuration/Dotenv/Parse.hs
--- a/src/Configuration/Dotenv/Parse.hs
+++ b/src/Configuration/Dotenv/Parse.hs
@@ -70,7 +70,7 @@
 
 interpolatedValueVarInterpolation :: Parser VarFragment
 interpolatedValueVarInterpolation = VarInterpolation <$>
-                            ((between (symbol "${") (symbol "}") variableName) <|>
+                            (between (symbol "${") (symbol "}") variableName <|>
                             (char '$' >> variableName))
   where
     symbol                = L.symbol sc
diff --git a/src/Configuration/Dotenv/Types.hs b/src/Configuration/Dotenv/Types.hs
--- a/src/Configuration/Dotenv/Types.hs
+++ b/src/Configuration/Dotenv/Types.hs
@@ -12,6 +12,10 @@
 module Configuration.Dotenv.Types
   ( Config(..)
   , defaultConfig
+  , ask
+  , runReaderT
+  , liftReaderT
+  , ReaderT
   )
   where
 
@@ -20,6 +24,8 @@
   { configPath        :: [FilePath] -- ^ The paths for the .env files
   , configExamplePath :: [FilePath] -- ^ The paths for the .env.example files
   , configOverride    :: Bool     -- ^ Flag to allow override env variables
+  , configVerbose     :: Bool     -- ^ Flag to log the loaded variables and other useful information
+  , allowDuplicates   :: Bool     -- ^ Flag to allow duplicate variables
   } deriving (Eq, Show)
 
 -- | Default configuration. Use .env file without .env.example strict envs and
@@ -30,4 +36,29 @@
     { configExamplePath = []
     , configOverride = False
     , configPath = [ ".env" ]
+    , configVerbose = False
+    , allowDuplicates = True
     }
+
+
+newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }
+mapReaderT :: (m a -> n b) -> ReaderT r m a -> ReaderT r n b
+mapReaderT f m = ReaderT $ f . runReaderT m
+instance (Functor m) => Functor (ReaderT r m) where
+    fmap f  = mapReaderT (fmap f)
+instance (Applicative m) => Applicative (ReaderT r m) where
+    pure    = liftReaderT . pure
+    f <*> v = ReaderT $ \ r -> runReaderT f r <*> runReaderT v r
+
+instance (Monad m) => Monad (ReaderT r m) where
+    return   = liftReaderT . return
+    m >>= k  = ReaderT $ \ r -> do
+      a <- runReaderT m r
+      runReaderT (k a) r
+    m >> k = ReaderT $ \ r -> runReaderT m r >> runReaderT k r
+
+liftReaderT :: m a -> ReaderT r m a
+liftReaderT m = ReaderT (const m)
+
+ask :: (Monad m) => ReaderT r m r
+ask = ReaderT return
