diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2016, Thomas Feron
+Copyright (c) 2016-2021, Thomas Feron
 
 All rights reserved.
 
diff --git a/Main.hs b/Main.hs
--- a/Main.hs
+++ b/Main.hs
@@ -1,10 +1,8 @@
-import Morph.Config
 import Morph.Migrator
 import Morph.Options
 
 main :: IO ()
 main = do
-  opts   <- getOptions
-  config <- readConfigOrDie opts
-  withConnection config $ \conn -> do
+  opts  <- getOptions
+  withConnection opts $ \conn -> do
     migrate (optsTransaction opts) conn (optsMigrationsDirectory opts)
diff --git a/morph.cabal b/morph.cabal
--- a/morph.cabal
+++ b/morph.cabal
@@ -1,5 +1,5 @@
 name:                  morph
-version:               0.1.1.3
+version:               0.2.0.0
 synopsis:              A simple database migrator for PostgreSQL
 description:           Morph is a tool to migrate your PostgreSQL databases
                        safely which supports rollbacks.
@@ -13,8 +13,8 @@
 
 source-repository head
   type:                git
-  location:            http://github.com/thoferon/morph
-  tag:                 0.1.1.3
+  location:            http://github.com/tomferon/morph
+  tag:                 0.2.0.0
 
 library
   hs-source-dirs:      src
@@ -23,14 +23,11 @@
 
   default-extensions:  OverloadedStrings
 
-  exposed-modules:     Morph.Config
-                       Morph.Migrator
+  exposed-modules:     Morph.Migrator
                        Morph.Options
 
   build-depends:       base >=4.8 && <5
                      , optparse-applicative
-                     , aeson
-                     , yaml
                      , postgresql-simple
                      , bytestring
                      , text
diff --git a/src/Morph/Config.hs b/src/Morph/Config.hs
deleted file mode 100644
--- a/src/Morph/Config.hs
+++ /dev/null
@@ -1,89 +0,0 @@
-module Morph.Config
-  ( readConfigOrDie
-  , withConnection
-  ) where
-
-import           Control.Exception
-
-import           Data.Maybe
-import qualified Data.Aeson                 as J
-import qualified Data.Aeson.Types           as J hiding (Options)
-import qualified Data.Bifunctor             as B
-import qualified Data.Yaml                  as Y
-import qualified Data.ByteString.Lazy.Char8 as BSL
-import qualified Data.Text                  as T
-
-import           System.Exit
-import           System.IO
-
-import           Database.PostgreSQL.Simple
-
-import           Morph.Options
-
-data Config = Config
-  { configUsername :: String
-  , configPassword :: String
-  , configHostname :: String
-  , configPort     :: Integer
-  , configName     :: String
-  }
-
-instance J.FromJSON Config where
-  parseJSON = J.withObject "Config" $ \obj -> Config
-    <$> obj J..: "username"
-    <*> obj J..: "password"
-    <*> obj J..: "hostname"
-    <*> obj J..: "port"
-    <*> obj J..: "name"
-
-parseJSONConfig :: [T.Text] -> J.Value -> J.Parser Config
-parseJSONConfig [] = J.parseJSON
-parseJSONConfig (key : keys) = J.withObject "Parent object" $ \obj -> do
-  val <- obj J..: key
-  parseJSONConfig keys val
-
-parseYAMLConfig :: [T.Text] -> Y.Value -> Y.Parser Config
-parseYAMLConfig [] val = Y.parseJSON val
-parseYAMLConfig (key : keys) (Y.Object obj) = do
-  val <- obj Y..: key
-  parseYAMLConfig keys val
-parseYAMLConfig _ _ = fail "Object expected"
-
-readConfigOrDie :: Options -> IO Config
-readConfigOrDie opts = do
-  contents <- BSL.readFile $
-    fromMaybe (if optsJSONConfig opts then "config.json" else "config.yml")
-              (optsConfigFile opts)
-
-  let eConfig
-        | optsJSONConfig opts = do
-            val <- J.eitherDecode contents
-            J.parseEither (parseJSONConfig (optsKeysPath opts)) val
-        | otherwise = do
-            val <- B.first show . Y.decodeEither' . BSL.toStrict $ contents
-            Y.parseEither (parseYAMLConfig (optsKeysPath opts)) val
-
-  case eConfig of
-    Right config -> return config
-    Left err -> do
-      hPutStrLn stderr $ "Can't read the config file: " ++ err
-      exitFailure
-
-createConn :: Config -> IO Connection
-createConn config = connect ConnectInfo
-  { connectHost     = configHostname config
-  , connectUser     = configUsername config
-  , connectPassword = configPassword config
-  , connectDatabase = configName     config
-  , connectPort     = fromInteger $ configPort config
-  }
-
-destroyConn :: Connection -> IO ()
-destroyConn = close
-
-withConnection :: Config -> (Connection -> IO a) -> IO a
-withConnection config f = do
-  conn <- createConn config
-  res <- catch (f conn) $ \e -> destroyConn conn >> throw (e :: SomeException)
-  destroyConn conn
-  return res
diff --git a/src/Morph/Options.hs b/src/Morph/Options.hs
--- a/src/Morph/Options.hs
+++ b/src/Morph/Options.hs
@@ -1,40 +1,55 @@
 module Morph.Options
   ( Options(..)
   , getOptions
+  , withConnection
   ) where
 
+import           Control.Exception (bracket)
+import           System.Environment (getEnv)
+
 import           Data.Monoid
-import qualified Data.Text as T
+import qualified Data.ByteString.Char8 as BS
 
+import           Database.PostgreSQL.Simple
+
 import           Options.Applicative
 
 data Options = Options
-  { optsConfigFile          :: Maybe FilePath
-  , optsKeysPath            :: [T.Text]
+  { optsConnectionString    :: Maybe BS.ByteString
   , optsMigrationsDirectory :: FilePath
-  , optsJSONConfig          :: Bool
   , optsTransaction         :: Bool
   }
 
 optionsParser :: Parser Options
 optionsParser = Options
   <$> option (Just <$> str)
-             (short 'c' <> long "config" <> metavar "PATH"
-              <> value Nothing <> help "Path to the config file.")
-  <*> option ((T.splitOn "." . T.pack) <$> str)
-             (short 'p' <> long "path" <> metavar "KEY1[.KEY2[...]]"
-              <> value [] <> help "The keys to traverse in the JSON to find\
-                                  \ the database connection info.")
-  <*> strOption (short 'd' <> long "dir" <> metavar "PATH"
-                 <> showDefault <> value "migrations"
-                 <> help "Path to the directory containing migrations.")
-  <*> flag False True (short 'j' <> long "json"
-                       <> help "Read config file as JSON.")
-  <*> flag True False (long "no-transaction"
-                       <> help "Do not run migrations in a SQL transaction. ")
+        (short 'c' <> long "connection"
+          <> metavar "DATABASE_CONNECTION_STRING"
+          <> help "Libpq connection string. Read from environment variable otherwise."
+          <> value Nothing)
+  <*> strOption
+        (short 'd' <> long "dir" <> metavar "PATH"
+          <> showDefault <> value "migrations"
+          <> help "Path to the directory containing migrations.")
+  <*> flag True False
+        (long "no-transaction"
+          <> help "Do not run migrations in a SQL transaction.")
 
 getOptions :: IO Options
 getOptions = execParser $ info (helper <*> optionsParser) $
   fullDesc
   <> progDesc "Migrator for PostgreSQL databases with support for rollbacks"
   <> footer "This program is licensed under the BSD-3 license."
+
+createConn :: Options -> IO Connection
+createConn opts = do
+  connString <- case optsConnectionString opts of
+    Nothing -> BS.pack <$> getEnv "DATABASE_CONNECTION_STRING"
+    Just cs -> pure cs
+  connectPostgreSQL connString
+
+destroyConn :: Connection -> IO ()
+destroyConn = close
+
+withConnection :: Options -> (Connection -> IO a) -> IO a
+withConnection options f = bracket (createConn options) destroyConn f
