diff --git a/build.sbt b/build.sbt
index 8ffc7af76..bc822a9d3 100644
--- a/build.sbt
+++ b/build.sbt
@@ -448,7 +448,7 @@ lazy val docs = projectMatrix
     scalacOptions += "-Wconf:msg='match may not be exhaustive':s", // silence exhaustive pattern matching warning for documentation
     scalacOptions += "-Xfatal-warnings",
     mdoc := (Compile / run).evaluated,
-    libraryDependencies += metaconfigDoc,
+    libraryDependencies += scalatags,
     dependencyOverrides += scalametaFor3Use2_13 // force eviction of mdoc transitive dependency
   )
   .defaultAxes(VirtualAxis.jvm)
diff --git a/project/Dependencies.scala b/project/Dependencies.scala
index 652bafa41..679c9e7af 100644
--- a/project/Dependencies.scala
+++ b/project/Dependencies.scala
@@ -17,10 +17,11 @@ object Dependencies {
   val commontTextV = "1.13.0"
   val googleDiffV = "1.3.0"
   val jgitV = "5.13.3.202401111512-r"
-  val metaconfigV = "0.13.0"
+  val metaconfigV = "0.14.0"
   val nailgunV = "0.9.1"
   val scalaXmlV = "2.2.0"
   val scalametaV = "4.12.2"
+  val scalatagsV = "0.13.1"
   val scalatestV = "3.2.19"
   val munitV = "1.0.3"
 
@@ -32,12 +33,12 @@ object Dependencies {
   val googleDiff = "com.googlecode.java-diff-utils" % "diffutils" % googleDiffV
   val jgit = "org.eclipse.jgit" % "org.eclipse.jgit" % jgitV
   val metaconfig = "org.scalameta" %% "metaconfig-typesafe-config" % metaconfigV
-  val metaconfigDoc = "org.scalameta" %% "metaconfig-docs" % metaconfigV
   val metacp = "org.scalameta" %% "metacp" % scalametaV
   val nailgunServer = "com.martiansoftware" % "nailgun-server" % nailgunV
   val scalaXml = "org.scala-lang.modules" %% "scala-xml" % scalaXmlV
   val scalametaFor3Use2_13 = "org.scalameta" %% "scalameta" % scalametaV cross CrossVersion.for3Use2_13
   val scalametaTeskitFor3Use2_13 = "org.scalameta" %% "testkit" % scalametaV cross CrossVersion.for3Use2_13
+  val scalatags = "com.lihaoyi" %% "scalatags" % scalatagsV
   val scalatest = "org.scalatest" %% "scalatest" % scalatestV
   val munit = "org.scalameta" %% "munit" % munitV
   val semanticdbScalacCore = "org.scalameta" % "semanticdb-scalac-core" % scalametaV cross CrossVersion.full
diff --git a/project/ScalafixBuild.scala b/project/ScalafixBuild.scala
index 3c1897ffd..f1ced5d39 100644
--- a/project/ScalafixBuild.scala
+++ b/project/ScalafixBuild.scala
@@ -240,17 +240,22 @@ object ScalafixBuild extends AutoPlugin with GhpagesKeys {
       "com.lihaoyi" %% "pprint",
       // https://github.com/scalacenter/scalafix/pull/1819#issuecomment-1636118496
       "org.scalameta" %% "fastparse-v2",
-      "com.lihaoyi" %% "geny",
-      // https://github.com/scalacenter/scalafix/pull/2025#issuecomment-2264188708
-      "com.geirsson" %% "metaconfig-core",
-      "com.geirsson" %% "metaconfig-pprint",
-      "com.geirsson" %% "metaconfig-typesafe-config"
+      "com.lihaoyi" %% "geny"
     ),
     versionPolicyIgnoredInternalDependencyVersions :=
       Some("^\\d+\\.\\d+\\.\\d+\\+\\d+".r),
     versionScheme := Some("early-semver"),
-    // coursier-versions always return false for the *.*.*.*-r pattern jgit uses
-    libraryDependencySchemes += Dependencies.jgit.withRevision("always")
+    libraryDependencySchemes ++= Seq(
+      // coursier-versions always return false for the *.*.*.*-r pattern jgit uses
+      Dependencies.jgit.withRevision(VersionScheme.Always),
+      // metaconfig has no breaking change from 0.13.0 to 0.14.0
+      "org.scalameta" % "metaconfig-core_2.12" % VersionScheme.Always,
+      "org.scalameta" % "metaconfig-core_2.13" % VersionScheme.Always,
+      "org.scalameta" % "metaconfig-pprint_2.12" % VersionScheme.Always,
+      "org.scalameta" % "metaconfig-pprint_2.13" % VersionScheme.Always,
+      "org.scalameta" % "metaconfig-typesafe-config_2.12" % VersionScheme.Always,
+      "org.scalameta" % "metaconfig-typesafe-config_2.13" % VersionScheme.Always
+    )
   )
 
   override def projectSettings: Seq[Def.Setting[_]] = List(
diff --git a/project/plugins.sbt b/project/plugins.sbt
index 151a1aabe..1996ec352 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -2,7 +2,7 @@ addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.9.0")
 addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.13.1")
 addSbtPlugin("com.github.sbt" % "sbt-ghpages" % "0.8.0")
 addSbtPlugin("ch.epfl.scala" % "sbt-version-policy" % "3.2.1")
-addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.6.1")
+addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.6.2")
 addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.2.2")
 addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.13.0")
 addSbtPlugin("com.eed3si9n" % "sbt-projectmatrix" % "0.10.1")
diff --git a/scalafix-cli/src/main/scala/scalafix/internal/v1/Args.scala b/scalafix-cli/src/main/scala/scalafix/internal/v1/Args.scala
index 6c935a58a..1ed5ef34e 100644
--- a/scalafix-cli/src/main/scala/scalafix/internal/v1/Args.scala
+++ b/scalafix-cli/src/main/scala/scalafix/internal/v1/Args.scala
@@ -255,23 +255,23 @@ case class Args(
 
   // With a --triggered flag, looking for settings in triggered block first, and fallback to standard settings.
   def maybeOverlaidConfWithTriggered(base: Conf): Conf =
-    if (triggered)
-      ScalafixConfOps.overlay(base, "triggered")
-    else
-      base
+    if (triggered) {
+      val triggeredOverlay = ConfGet
+        .getOrOK(base, "triggered" :: Nil, Configured.ok, Conf.Obj.empty)
+        .getOrElse(Conf.Obj.empty)
+      ConfOps.merge(base, triggeredOverlay)
+    } else base
 
   def rulesConf(base: () => Conf): Conf = {
     if (rules.isEmpty) {
-      val rulesInConf =
-        ConfGet.getKey(
+      ConfGet
+        .getOrOK(
           maybeOverlaidConfWithTriggered(base()),
-          "rules" :: "rule" :: Nil
+          "rules" :: "rule" :: Nil,
+          Configured.ok,
+          Conf.Lst(Nil)
         )
-
-      rulesInConf match {
-        case Some(c) => c
-        case _ => Conf.Lst(Nil)
-      }
+        .getOrElse(Conf.Lst(Nil))
     } else {
       Conf.Lst(rules.map(Conf.fromString))
     }
diff --git a/scalafix-cli/src/main/scala/scalafix/internal/v1/ScalafixConfOps.scala b/scalafix-cli/src/main/scala/scalafix/internal/v1/ScalafixConfOps.scala
deleted file mode 100644
index a0c2f0197..000000000
--- a/scalafix-cli/src/main/scala/scalafix/internal/v1/ScalafixConfOps.scala
+++ /dev/null
@@ -1,20 +0,0 @@
-package scalafix.internal.v1
-
-import metaconfig.Conf
-import metaconfig.Conf.Obj
-import metaconfig.ConfOps
-import metaconfig.internal.ConfGet
-
-object ScalafixConfOps {
-  def drop(original: Conf, key: String): Conf =
-    ConfOps.fold(original)(obj = { confObj =>
-      Obj(confObj.values.filterNot(_._1 == key))
-    })
-
-  def overlay(original: Conf, key: String): Conf = {
-    val child = ConfGet.getKey(original, key :: Nil)
-    child.fold(original)(
-      ConfOps.merge(drop(original, key), _)
-    )
-  }
-}
diff --git a/scalafix-core/src/main/scala/scalafix/internal/config/MetaconfigOps.scala b/scalafix-core/src/main/scala/scalafix/internal/config/MetaconfigOps.scala
index d72fd3e13..83b9c8a65 100644
--- a/scalafix-core/src/main/scala/scalafix/internal/config/MetaconfigOps.scala
+++ b/scalafix-core/src/main/scala/scalafix/internal/config/MetaconfigOps.scala
@@ -36,10 +36,10 @@ object MetaconfigOps {
   def getKey[T](conf: Conf.Obj, path: String, extraNames: String*)(implicit
       ev: ConfDecoder[T]
   ): Configured[T] = {
-    ConfGet.getKey(conf, path +: extraNames) match {
-      case Some(value) => ev.read(value)
-      case None => ConfError.missingField(conf, path).notOk
-    }
+    ConfGet.getOrElse(
+      value => ev.read(value),
+      ConfError.missingField(conf, path).notOk
+    )(conf, path +: extraNames)
   }
 
   implicit class XtensionMetaconfigInputToMeta(input: Input) {
diff --git a/scalafix-rules/src/main/scala/scalafix/internal/rule/OrganizeImports.scala b/scalafix-rules/src/main/scala/scalafix/internal/rule/OrganizeImports.scala
index 4e4c01c08..778353343 100644
--- a/scalafix-rules/src/main/scala/scalafix/internal/rule/OrganizeImports.scala
+++ b/scalafix-rules/src/main/scala/scalafix/internal/rule/OrganizeImports.scala
@@ -852,8 +852,9 @@ object OrganizeImports {
   ): Configured[OrganizeImportsConfig] = {
     val preset = OrganizeImportsConfig.presets(ruleConf.preset)
     val presetConf = ConfEncoder[OrganizeImportsConfig].write(preset)
-    val userConf =
-      ConfGet.getKey(conf, "OrganizeImports" :: Nil).getOrElse(Conf.Obj.empty)
+    val userConf = ConfGet
+      .getOrOK(conf, "OrganizeImports" :: Nil, Configured.ok, Conf.Obj.empty)
+      .getOrElse(Conf.Obj.empty)
     val mergedConf = ConfOps.merge(presetConf, userConf)
     ConfDecoder[OrganizeImportsConfig].read(mergedConf)
   }
diff --git a/scalafix-testkit/src/main/scala/scalafix/testkit/SemanticRuleSuite.scala b/scalafix-testkit/src/main/scala/scalafix/testkit/SemanticRuleSuite.scala
index 30d85b812..291e1f505 100644
--- a/scalafix-testkit/src/main/scala/scalafix/testkit/SemanticRuleSuite.scala
+++ b/scalafix-testkit/src/main/scala/scalafix/testkit/SemanticRuleSuite.scala
@@ -6,6 +6,8 @@ import scala.meta._
 import scala.meta.internal.inputs.XtensionInput
 
 import metaconfig.Conf
+import metaconfig.ConfError
+import metaconfig.Configured
 import metaconfig.internal.ConfGet
 import metaconfig.typesafeconfig.typesafeConfigMetaconfigParser
 import scalafix.internal.config.ScalafixConfig
@@ -45,7 +47,14 @@ object SemanticRuleSuite {
       for {
         conf <- Try(Conf.parseString("comment", syntax)).toOption
           .flatMap(_.toEither.toOption)
-        rulesConf <- ConfGet.getKey(conf, "rules" :: "rule" :: Nil)
+        rulesConf <-
+          ConfGet
+            .getOrElse(
+              Configured.ok,
+              ConfError.message("").notOk
+            )(conf, "rules" :: "rule" :: Nil)
+            .toEither
+            .toOption
         scalafixConfig <- conf.as[ScalafixConfig].toEither.toOption
       } yield (comment, conf, rulesConf, scalafixConfig)
     }
diff --git a/scalafix-tests/unit/src/test/scala/scalafix/tests/config/ArgsSuite.scala b/scalafix-tests/unit/src/test/scala/scalafix/tests/config/ArgsSuite.scala
index 1fa4c7b3c..37b4b25cd 100644
--- a/scalafix-tests/unit/src/test/scala/scalafix/tests/config/ArgsSuite.scala
+++ b/scalafix-tests/unit/src/test/scala/scalafix/tests/config/ArgsSuite.scala
@@ -3,6 +3,7 @@ package scalafix.tests.config
 import scala.meta.io.AbsolutePath
 
 import metaconfig.Conf
+import metaconfig.Configured
 import metaconfig.internal.ConfGet
 import metaconfig.typesafeconfig.typesafeConfigMetaconfigParser
 import scalafix.internal.config.ScalaVersion
@@ -46,7 +47,9 @@ class ArgsSuite extends munit.FunSuite {
 
     val merged = args.maybeOverlaidConfWithTriggered(givenConf)
 
-    val disableSyntaxRule = ConfGet.getKey(merged, "DisableSyntax" :: Nil).get
+    val disableSyntaxRule = ConfGet
+      .getOrOK(merged, "DisableSyntax" :: Nil, Configured.ok, Conf.Obj.empty)
+      .get
 
     val expected =
       Conf.Obj("noVars" -> Conf.Bool(true), "noThrows" -> Conf.Bool(true))
@@ -64,7 +67,9 @@ class ArgsSuite extends munit.FunSuite {
 
     val merged = args.maybeOverlaidConfWithTriggered(givenConf)
 
-    val disableSyntaxRule = ConfGet.getKey(merged, "DisableSyntax" :: Nil).get
+    val disableSyntaxRule = ConfGet
+      .getOrOK(merged, "DisableSyntax" :: Nil, Configured.ok, Conf.Obj.empty)
+      .get
 
     val expected =
       Conf.Obj(