diff --git a/lib/config/migration.ts b/lib/config/migration.ts
index d7619dbf07d93bf9920279e1d7f72d999721e29c..d77d4136da646229b5d7ecb17c5a97bac43d71a0 100644
--- a/lib/config/migration.ts
+++ b/lib/config/migration.ts
@@ -38,15 +38,7 @@ export function migrateConfig(config: RenovateConfig): MigratedConfig {
       'peerDependencies',
     ];
     for (const [key, val] of Object.entries(newConfig)) {
-      if (key === 'matchStrings' && is.array(val)) {
-        migratedConfig.matchStrings = val
-          .map(
-            (matchString) =>
-              is.string(matchString) &&
-              matchString.replace(regEx(/\(\?<lookupName>/g), '(?<packageName>')
-          )
-          .filter(Boolean);
-      } else if (key.startsWith('masterIssue')) {
+      if (key.startsWith('masterIssue')) {
         const newKey = key.replace('masterIssue', 'dependencyDashboard');
         migratedConfig[newKey] = val;
         if (optionTypes[newKey] === 'boolean' && val === 'true') {
diff --git a/lib/config/migrations/custom/match-strings-migration.spec.ts b/lib/config/migrations/custom/match-strings-migration.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6091d091ffe625807297233fb05fc81cdd770386
--- /dev/null
+++ b/lib/config/migrations/custom/match-strings-migration.spec.ts
@@ -0,0 +1,20 @@
+import { MatchStringsMigration } from './match-strings-migration';
+
+describe('config/migrations/custom/match-strings-migration', () => {
+  it('should migrate properly', () => {
+    expect(MatchStringsMigration).toMigrate(
+      {
+        matchStrings: [
+          undefined,
+          '(?<lookupName>',
+          null,
+          '(?<lookupName>(?<lookupName>',
+          '',
+        ],
+      },
+      {
+        matchStrings: ['(?<packageName>', '(?<packageName>(?<packageName>'],
+      }
+    );
+  });
+});
diff --git a/lib/config/migrations/custom/match-strings-migration.ts b/lib/config/migrations/custom/match-strings-migration.ts
new file mode 100644
index 0000000000000000000000000000000000000000..269d564038de1386d79fad55c9f820fe8905df26
--- /dev/null
+++ b/lib/config/migrations/custom/match-strings-migration.ts
@@ -0,0 +1,19 @@
+import is from '@sindresorhus/is';
+import { regEx } from '../../../util/regex';
+import { AbstractMigration } from '../base/abstract-migration';
+
+export class MatchStringsMigration extends AbstractMigration {
+  override readonly propertyName = 'matchStrings';
+
+  override run(value: unknown): void {
+    if (Array.isArray(value)) {
+      const newValue = value
+        .filter(is.nonEmptyString)
+        .map((matchString) =>
+          matchString.replace(regEx(/\(\?<lookupName>/g), '(?<packageName>')
+        );
+
+      this.rewrite(newValue);
+    }
+  }
+}
diff --git a/lib/config/migrations/migrations-service.ts b/lib/config/migrations/migrations-service.ts
index 2aafbeb709f8b267c09c3b5b4e2bc5a168527869..de5f024736d9840c7a14a5e1eefaeaba2b61eb31 100644
--- a/lib/config/migrations/migrations-service.ts
+++ b/lib/config/migrations/migrations-service.ts
@@ -22,6 +22,7 @@ import { GoModTidyMigration } from './custom/go-mod-tidy-migration';
 import { HostRulesMigration } from './custom/host-rules-migration';
 import { IgnoreNodeModulesMigration } from './custom/ignore-node-modules-migration';
 import { IgnoreNpmrcFileMigration } from './custom/ignore-npmrc-file-migration';
+import { MatchStringsMigration } from './custom/match-strings-migration';
 import { PackageNameMigration } from './custom/package-name-migration';
 import { PackagePatternMigration } from './custom/package-pattern-migration';
 import { PackagesMigration } from './custom/packages-migration';
@@ -92,6 +93,7 @@ export class MigrationsService {
     HostRulesMigration,
     IgnoreNodeModulesMigration,
     IgnoreNpmrcFileMigration,
+    MatchStringsMigration,
     PackageNameMigration,
     PackagePatternMigration,
     PackagesMigration,