diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -5,91 +5,49 @@
 module Main where
 
 import Control.Applicative
-import Control.Monad (filterM)
-import Data.Coerce (coerce)
-import Data.Maybe (fromMaybe, listToMaybe)
+import qualified Data.List.NonEmpty as NonEmpty
 import Data.Semigroup ((<>))
 import qualified Data.Set as Set
 import Data.String
-import Data.Text (Text)
 import qualified Data.Version
-import qualified Data.Yaml as Yaml
 import qualified Development.GitRev
-import GHC.Generics
-import qualified Language.Docker as Docker
-import Language.Docker.Syntax (Dockerfile)
 import Options.Applicative hiding (ParseError)
 import qualified Paths_hadolint -- version from hadolint.cabal file
-import System.Directory
-       (XdgDirectory(..), doesFileExist, getCurrentDirectory,
-        getXdgDirectory)
 import System.Exit (exitFailure, exitSuccess)
-import System.FilePath ((</>))
 
-import qualified Hadolint.Formatter.Checkstyle as Checkstyle
-import qualified Hadolint.Formatter.Codeclimate as Codeclimate
-import qualified Hadolint.Formatter.Format as Format
-import qualified Hadolint.Formatter.Json as Json
-import qualified Hadolint.Formatter.TTY as TTY
-import qualified Hadolint.Formatter.Codacy as Codacy
-import qualified Hadolint.Rules as Rules
-
-type IgnoreRule = Text
-
-type TrustedRegistry = Text
-
-data OutputFormat
-    = Json
-    | TTY
-    | CodeclimateJson
-    | Checkstyle
-    | Codacy
-    deriving (Show, Eq)
+import qualified Hadolint
 
-data LintOptions = LintOptions
+data CommandOptions = CommandOptions
     { showVersion :: Bool
     , configFile :: Maybe FilePath
-    , format :: OutputFormat
-    , ignoreRules :: [IgnoreRule]
+    , format :: Hadolint.OutputFormat
     , dockerfiles :: [String]
-    , rulesConfig :: Rules.RulesConfig
-    } deriving (Show)
-
-data ConfigFile = ConfigFile
-    { ignored :: Maybe [IgnoreRule]
-    , trustedRegistries :: Maybe [TrustedRegistry]
-    } deriving (Show, Eq, Generic)
-
-instance Yaml.FromJSON ConfigFile
-
-ignoreFilter :: [IgnoreRule] -> Rules.RuleCheck -> Bool
-ignoreFilter ignoredRules (Rules.RuleCheck (Rules.Metadata code _ _) _ _ _) =
-    code `notElem` ignoredRules
+    , lintingOptions :: Hadolint.LintOptions
+    }
 
-toOutputFormat :: String -> Maybe OutputFormat
-toOutputFormat "json" = Just Json
-toOutputFormat "tty" = Just TTY
-toOutputFormat "codeclimate" = Just CodeclimateJson
-toOutputFormat "checkstyle" = Just Checkstyle
-toOutputFormat "codacy" = Just Codacy
+toOutputFormat :: String -> Maybe Hadolint.OutputFormat
+toOutputFormat "json" = Just Hadolint.Json
+toOutputFormat "tty" = Just Hadolint.TTY
+toOutputFormat "codeclimate" = Just Hadolint.CodeclimateJson
+toOutputFormat "checkstyle" = Just Hadolint.Checkstyle
+toOutputFormat "codacy" = Just Hadolint.Codacy
 toOutputFormat _ = Nothing
 
-showFormat :: OutputFormat -> String
-showFormat Json = "json"
-showFormat TTY = "tty"
-showFormat CodeclimateJson = "codeclimate"
-showFormat Checkstyle = "checkstyle"
-showFormat Codacy = "codacy"
+showFormat :: Hadolint.OutputFormat -> String
+showFormat Hadolint.Json = "json"
+showFormat Hadolint.TTY = "tty"
+showFormat Hadolint.CodeclimateJson = "codeclimate"
+showFormat Hadolint.Checkstyle = "checkstyle"
+showFormat Hadolint.Codacy = "codacy"
 
-parseOptions :: Parser LintOptions
+parseOptions :: Parser CommandOptions
 parseOptions =
-    LintOptions <$> -- CLI options parser definition
+    CommandOptions <$> -- CLI options parser definition
     version <*>
     configFile <*>
     outputFormat <*>
-    ignoreList <*>
     files <*>
-    parseRulesConfig
+    lintOptions
   where
     version = switch (long "version" <> short 'v' <> help "Show version")
     --
@@ -106,8 +64,9 @@
             (maybeReader toOutputFormat)
             (long "format" <> -- options for the output format
              short 'f' <>
-             help "The output format for the results [tty | json | checkstyle | codeclimate | codacy]" <>
-             value TTY <> -- The default value
+             help
+                 "The output format for the results [tty | json | checkstyle | codeclimate | codacy]" <>
+             value Hadolint.TTY <> -- The default value
              showDefaultWith showFormat <>
              completeWith ["tty", "json", "checkstyle", "codeclimate", "codacy"])
     --
@@ -122,9 +81,12 @@
     -- | Parse a list of dockerfile names
     files = many (argument str (metavar "DOCKERFILE..." <> action "file"))
     --
-    -- | Parses all the optional rules configuration
+    -- | Parse the rule ignore list and the rules configuration into a LintOptions
+    lintOptions = Hadolint.LintOptions <$> ignoreList <*> parseRulesConfig
+    --
+    -- | Parse all the optional rules configuration
     parseRulesConfig =
-        Rules.RulesConfig . Set.fromList . fmap fromString <$>
+        Hadolint.RulesConfig . Set.fromList . fmap fromString <$>
         many
             (strOption
                  (long "trusted-registry" <>
@@ -132,118 +94,29 @@
                   metavar "REGISTRY (e.g. docker.io)"))
 
 main :: IO ()
-main = execParser opts >>= applyConfig >>= lint
+main = do
+    cmd <- execParser opts
+    execute cmd
   where
+    execute CommandOptions {showVersion = True} = putStrLn getVersion >> exitSuccess
+    execute CommandOptions {dockerfiles = []} =
+        putStrLn "Please provide a Dockerfile" >> exitFailure
+    execute cmd = do
+        lintConfig <- Hadolint.applyConfig (configFile cmd) (lintingOptions cmd)
+        let files = NonEmpty.fromList (dockerfiles cmd)
+        case lintConfig of
+            Left err -> error err
+            Right conf -> do
+                res <- Hadolint.lint conf files
+                Hadolint.printResultsAndExit (format cmd) res
     opts =
         info
             (helper <*> parseOptions)
             (fullDesc <> progDesc "Lint Dockerfile for errors and best practices" <>
              header "hadolint - Dockerfile Linter written in Haskell")
 
-applyConfig :: LintOptions -> IO LintOptions
-applyConfig o
-    | not (null (ignoreRules o)) && rulesConfig o /= mempty = return o
-    | otherwise = do
-        theConfig <-
-            case configFile o of
-                Nothing -> findConfig
-                c -> return c
-        case theConfig of
-            Nothing -> return o
-            Just config -> parseAndApply config
-  where
-    findConfig = do
-        localConfigFile <- (</> ".hadolint.yaml") <$> getCurrentDirectory
-        configFile <- getXdgDirectory XdgConfig "hadolint.yaml"
-        listToMaybe <$> filterM doesFileExist [localConfigFile, configFile]
-    parseAndApply config = do
-        result <- Yaml.decodeFileEither config
-        case result of
-            Left err -> printError err config
-            Right (ConfigFile ignore trusted) -> return (override ignore trusted)
-    -- | Applies the configuration found in the file to the passed LintOptions
-    override ignore trusted = applyTrusted trusted . applyIgnore ignore $ o
-    applyIgnore ignore opts =
-        case ignoreRules opts of
-            [] -> opts {ignoreRules = fromMaybe [] ignore}
-            _ -> opts
-    applyTrusted trusted opts
-        | null (Rules.allowedRegistries (rulesConfig opts)) =
-            opts {rulesConfig = toRules trusted <> rulesConfig opts}
-        | otherwise = opts
-    -- | Converts a list of TrustedRegistry to a RulesConfig record
-    toRules (Just trusted) = Rules.RulesConfig (Set.fromList . coerce $ trusted)
-    toRules _ = mempty
-    printError err config =
-        case err of
-            Yaml.AesonException e ->
-                error $
-                unlines
-                    [ "Error parsing your config file in  '" ++ config ++ "':"
-                    , "It should contain one of the keys 'ignored' or 'trustedRegistries'. For example:\n"
-                    , "ignored:"
-                    , "\t- DL3000"
-                    , "\t- SC1099\n\n"
-                    , "The key 'trustedRegistries' should contain the names of the allowed docker registries:\n"
-                    , "allowedRegistries:"
-                    , "\t- docker.io"
-                    , "\t- my-company.com"
-                    , ""
-                    , e
-                    ]
-            _ ->
-                error $
-                "Error parsing your config file in  '" ++
-                config ++ "': " ++ Yaml.prettyPrintParseException err
-
--- | Support UNIX convention of passing "-" instead of "/dev/stdin"
-parseFilename :: String -> String
-parseFilename "-" = "/dev/stdin"
-parseFilename s = s
-
 getVersion :: String
 getVersion
     | $(Development.GitRev.gitDescribe) == "UNKNOWN" =
         "Haskell Dockerfile Linter " ++ Data.Version.showVersion Paths_hadolint.version ++ "-no-git"
     | otherwise = "Haskell Dockerfile Linter " ++ $(Development.GitRev.gitDescribe)
-
--- | Performs the process of parsing the dockerfile and analyzing it with all the applicable
--- rules, depending on the list of ignored rules.
--- Depending on the preferred printing format, it will output the results to stdout
-lint :: LintOptions -> IO ()
-lint LintOptions {showVersion = True} = putStrLn getVersion >> exitSuccess
-lint LintOptions {dockerfiles = []} = putStrLn "Please provide a Dockerfile" >> exitFailure
-lint LintOptions {ignoreRules = ignoreList, dockerfiles = dFiles, format, rulesConfig} = do
-    processedFiles <- mapM (lintDockerfile ignoreList) dFiles
-    let allResults = results processedFiles
-    printResult allResults
-    if allResults /= mempty
-        then exitFailure
-        else exitSuccess
-  where
-    results = foldMap Format.toResult -- Parse and check rules for each dockerfile,
-                                      -- then convert them to a Result and combine with
-                                      -- the result of the previous dockerfile results
-    printResult res =
-        case format of
-            TTY -> TTY.printResult res
-            Json -> Json.printResult res
-            Checkstyle -> Checkstyle.printResult res
-            CodeclimateJson -> Codeclimate.printResult res >> exitSuccess
-            Codacy -> Codacy.printResult res >> exitSuccess
-    lintDockerfile ignoreRules dockerFile = do
-        ast <- Docker.parseFile (parseFilename dockerFile)
-        return (processedFile ast)
-      where
-        processedFile = fmap processRules
-        processRules fileLines = filter ignoredRules (analyzeAll rulesConfig fileLines)
-        ignoredRules = ignoreFilter ignoreRules
-
--- | Returns the result of applying all the rules to the given dockerfile
-analyzeAll :: Rules.RulesConfig -> Dockerfile -> [Rules.RuleCheck]
-analyzeAll config = Rules.analyze (Rules.rules ++ Rules.optionalRules config)
-
--- | Helper to analyze AST quickly in GHCI
-analyzeEither :: Rules.RulesConfig -> Either t Dockerfile -> [Rules.RuleCheck]
-analyzeEither _ (Left _) = []
-analyzeEither config (Right dockerFile) = analyzeAll config dockerFile
diff --git a/hadolint.cabal b/hadolint.cabal
--- a/hadolint.cabal
+++ b/hadolint.cabal
@@ -2,10 +2,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 4ff12972c5a652d9e4a6df3e276fdb1a565eaf408b15b14f6e7f9c22a20ade5d
+-- hash: a69d376d8be88ae5432a97710688afbe46ad227c9262d12796a4357211b33238
 
 name:           hadolint
-version:        1.12.0
+version:        1.13.0
 synopsis:       Dockerfile Linter JavaScript API
 description:    A smarter Dockerfile linter that helps you build best practice Docker images.
 category:       Development
@@ -34,19 +34,25 @@
     , base >=4.8 && <5
     , bytestring
     , containers
+    , directory >=1.3.0
+    , filepath
     , language-docker >=6.0.4 && <7
     , megaparsec >=6.4
     , mtl
     , split >=0.2
     , text
     , void
+    , yaml
   exposed-modules:
+      Hadolint
+      Hadolint.Config
       Hadolint.Formatter.Checkstyle
       Hadolint.Formatter.Codacy
       Hadolint.Formatter.Codeclimate
       Hadolint.Formatter.Format
       Hadolint.Formatter.Json
       Hadolint.Formatter.TTY
+      Hadolint.Lint
       Hadolint.Rules
       Hadolint.Shell
   other-modules:
@@ -61,15 +67,12 @@
   build-depends:
       base >=4.8 && <5
     , containers
-    , directory >=1.3.0
-    , filepath
     , gitrev >=1.3.1
     , hadolint
     , language-docker >=6.0.4 && <7
     , megaparsec >=6.4
     , optparse-applicative >=0.14.0
     , text
-    , yaml
   if !(os(osx))
     ld-options: -static -pthread
   other-modules:
diff --git a/src/Hadolint.hs b/src/Hadolint.hs
new file mode 100644
--- /dev/null
+++ b/src/Hadolint.hs
@@ -0,0 +1,9 @@
+module Hadolint
+    ( module Hadolint.Lint
+    , module Hadolint.Rules
+    , module Hadolint.Config
+    ) where
+
+import Hadolint.Config
+import Hadolint.Lint
+import Hadolint.Rules
diff --git a/src/Hadolint/Config.hs b/src/Hadolint/Config.hs
new file mode 100644
--- /dev/null
+++ b/src/Hadolint/Config.hs
@@ -0,0 +1,84 @@
+{-# LANGUAGE DeriveGeneric #-}
+
+module Hadolint.Config (applyConfig) where
+
+import Control.Monad (filterM)
+import Data.Coerce (coerce)
+import Data.Maybe (fromMaybe, listToMaybe)
+import qualified Data.Set as Set
+import qualified Data.Yaml as Yaml
+import GHC.Generics
+import qualified Language.Docker as Docker
+import System.Directory
+       (XdgDirectory(..), doesFileExist, getCurrentDirectory,
+        getXdgDirectory)
+import System.FilePath ((</>))
+
+import qualified Hadolint.Lint as Lint
+import qualified Hadolint.Rules as Rules
+
+data ConfigFile = ConfigFile
+    { ignored :: Maybe [Lint.IgnoreRule]
+    , trustedRegistries :: Maybe [Lint.TrustedRegistry]
+    } deriving (Show, Eq, Generic)
+
+instance Yaml.FromJSON ConfigFile
+
+-- | If both the ignoreRules and rulesConfig properties of Lint options are empty
+-- then this function will fill them with the default found in the passed config
+-- file. If there is an error parsing the default config file, this function will
+-- return the error string.
+applyConfig :: Maybe FilePath -> Lint.LintOptions -> IO (Either String Lint.LintOptions)
+applyConfig maybeConfig o
+    | not (null (Lint.ignoreRules o)) && Lint.rulesConfig o /= mempty = return (Right o)
+    | otherwise = do
+        theConfig <-
+            case maybeConfig of
+                Nothing -> findConfig
+                c -> return c
+        case theConfig of
+            Nothing -> return (Right o)
+            Just config -> parseAndApply config
+  where
+    findConfig = do
+        localConfigFile <- (</> ".hadolint.yaml") <$> getCurrentDirectory
+        configFile <- getXdgDirectory XdgConfig "hadolint.yaml"
+        listToMaybe <$> filterM doesFileExist [localConfigFile, configFile]
+    parseAndApply :: FilePath -> IO (Either String Lint.LintOptions)
+    parseAndApply configFile = do
+        result <- Yaml.decodeFileEither configFile
+        case result of
+            Left err -> return $ Left (formatError err configFile)
+            Right (ConfigFile ignore trusted) -> return (Right (override ignore trusted))
+    -- | Applies the configuration found in the file to the passed Lint.LintOptions
+    override ignore trusted = applyTrusted trusted . applyIgnore ignore $ o
+    applyIgnore ignore opts =
+        case Lint.ignoreRules opts of
+            [] -> opts {Lint.ignoreRules = fromMaybe [] ignore}
+            _ -> opts
+    applyTrusted trusted opts
+        | null (Rules.allowedRegistries (Lint.rulesConfig opts)) =
+            opts {Lint.rulesConfig = toRules trusted <> Lint.rulesConfig opts}
+        | otherwise = opts
+    -- | Converts a list of TrustedRegistry to a RulesConfig record
+    toRules (Just trusted) = Rules.RulesConfig (Set.fromList . coerce $ trusted)
+    toRules _ = mempty
+    formatError err config =
+        case err of
+            Yaml.AesonException e ->
+                unlines
+                    [ "Error parsing your config file in  '" ++ config ++ "':"
+                    , "It should contain one of the keys 'ignored' or 'trustedRegistries'. For example:\n"
+                    , "ignored:"
+                    , "\t- DL3000"
+                    , "\t- SC1099\n\n"
+                    , "The key 'trustedRegistries' should contain the names of the allowed docker registries:\n"
+                    , "allowedRegistries:"
+                    , "\t- docker.io"
+                    , "\t- my-company.com"
+                    , ""
+                    , e
+                    ]
+            _ ->
+                "Error parsing your config file in  '" ++
+                config ++ "': " ++ Yaml.prettyPrintParseException err
diff --git a/src/Hadolint/Lint.hs b/src/Hadolint/Lint.hs
new file mode 100644
--- /dev/null
+++ b/src/Hadolint/Lint.hs
@@ -0,0 +1,86 @@
+{-# LANGUAGE NamedFieldPuns #-}
+
+module Hadolint.Lint where
+
+import qualified Data.List.NonEmpty as NonEmpty
+import Data.Text (Text)
+import qualified Language.Docker as Docker
+import Language.Docker.Parser (DockerfileError)
+import Language.Docker.Syntax (Dockerfile)
+import System.Exit (exitFailure, exitSuccess)
+
+import qualified Hadolint.Formatter.Checkstyle as Checkstyle
+import qualified Hadolint.Formatter.Codacy as Codacy
+import qualified Hadolint.Formatter.Codeclimate as Codeclimate
+import qualified Hadolint.Formatter.Format as Format
+import qualified Hadolint.Formatter.Json as Json
+import qualified Hadolint.Formatter.TTY as TTY
+import qualified Hadolint.Rules as Rules
+
+type IgnoreRule = Text
+
+type TrustedRegistry = Text
+
+data LintOptions = LintOptions
+    { ignoreRules :: [IgnoreRule]
+    , rulesConfig :: Rules.RulesConfig
+    } deriving (Show)
+
+data OutputFormat
+    = Json
+    | TTY
+    | CodeclimateJson
+    | Checkstyle
+    | Codacy
+    deriving (Show, Eq)
+
+printResultsAndExit :: OutputFormat -> Format.Result Char DockerfileError -> IO ()
+printResultsAndExit format allResults = do
+    printResult allResults
+    if allResults /= mempty
+        then exitFailure
+        else exitSuccess
+  where
+    printResult res =
+        case format of
+            TTY -> TTY.printResult res
+            Json -> Json.printResult res
+            Checkstyle -> Checkstyle.printResult res
+            CodeclimateJson -> Codeclimate.printResult res >> exitSuccess
+            Codacy -> Codacy.printResult res >> exitSuccess
+
+-- | Performs the process of parsing the dockerfile and analyzing it with all the applicable
+-- rules, depending on the list of ignored rules.
+-- Depending on the preferred printing format, it will output the results to stdout
+lint :: LintOptions -> NonEmpty.NonEmpty String -> IO (Format.Result Char DockerfileError)
+lint LintOptions {ignoreRules = ignoreList, rulesConfig} dFiles = do
+    processedFiles <- mapM (lintDockerfile ignoreList) (NonEmpty.toList dFiles)
+    return (results processedFiles)
+  where
+    results = foldMap Format.toResult -- Parse and check rules for each dockerfile,
+                                      -- then convert them to a Result and combine with
+                                      -- the result of the previous dockerfile results
+    lintDockerfile ignoreRules dockerFile = do
+        ast <- Docker.parseFile (parseFilename dockerFile)
+        return (processedFile ast)
+      where
+        processedFile = fmap processRules
+        processRules fileLines = filter ignoredRules (analyzeAll rulesConfig fileLines)
+        ignoredRules = ignoreFilter ignoreRules
+        -- | Returns true if the rule should be ignored
+        ignoreFilter :: [IgnoreRule] -> Rules.RuleCheck -> Bool
+        ignoreFilter rules (Rules.RuleCheck (Rules.Metadata code _ _) _ _ _) =
+            code `notElem` rules
+        -- | Support UNIX convention of passing "-" instead of "/dev/stdin"
+        parseFilename :: String -> String
+        parseFilename "-" = "/dev/stdin"
+        parseFilename s = s
+
+-- | Returns the result of applying all the rules to the given dockerfile
+analyzeAll :: Rules.RulesConfig -> Dockerfile -> [Rules.RuleCheck]
+analyzeAll config = Rules.analyze (Rules.rules ++ Rules.optionalRules config)
+
+-- | Helper to analyze AST quickly in GHCI
+analyzeEither :: Rules.RulesConfig -> Either t Dockerfile -> [Rules.RuleCheck]
+analyzeEither _ (Left _) = []
+analyzeEither config (Right dockerFile) = analyzeAll config dockerFile
