diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md
index a73a5d408d0463eceed2b370a6c95b0a681377d7..1300c46b43d94c8f940d30411b7edfa88c3041aa 100644
--- a/docs/usage/configuration-options.md
+++ b/docs/usage/configuration-options.md
@@ -1596,6 +1596,157 @@ Example:
 }
 ```
 
+### matchStringsStrategy
+
+`matchStringsStrategy` controls behavior when multiple `matchStrings` values are provided.
+Three options are available:
+
+- `any` (default)
+- `recursive`
+- `combination`
+
+#### any
+
+Each provided `matchString` will be matched individually to the content of the `packageFile`.
+If a `matchString` has multiple matches in a file each will be interpreted as an independent dependency.
+
+As example the following configuration will update all 3 lines in the Dockerfile.
+renovate.json:
+
+```json
+{
+  "regexManagers": [
+    {
+      "fileMatch": ["^Dockerfile$"],
+      "matchStringsStrategy": "any",
+      "matchStrings": [
+        "ENV [A-Z]+_VERSION=(?<currentValue>.*) # (?<datasource>.*?)/(?<depName>.*?)(\\&versioning=(?<versioning>.*?))?\\s",
+        "FROM (?<depName>\\S*):(?<currentValue>\\S*)"
+      ],
+      "datasourceTemplate": "docker"
+    }
+  ]
+}
+```
+
+a Dockerfile:
+
+```dockerfile
+FROM amd64/ubuntu:18.04
+ENV GRADLE_VERSION=6.2 # gradle-version/gradle&versioning=maven
+ENV NODE_VERSION=10.19.0 # github-tags/nodejs/node&versioning=node
+```
+
+#### recursive
+
+If using `recursive` the `matchStrings` will be looped through and the full match of the last will define the range of the next one.
+This can be used to narrow down the search area to prevent multiple matches.
+However, the `recursive` strategy still allows the matching of multiple dependencies as described below.
+All matches of the first `matchStrings` pattern are detected, then each of these matches will used as basis be used as the input for the next `matchStrings` pattern, and so on.
+If the next `matchStrings` pattern has multiple matches then it will split again.
+This process will be followed as long there is a match plus a next `matchingStrings` pattern is available or a dependency is detected.
+
+This is an example how this can work.
+The first regex manager will only upgrade `grafana/loki` as looks for the `backup` key then looks for the `test` key and then uses this result for extraction of necessary attributes.
+However, the second regex manager will upgrade both definitions as its first `matchStrings` matches both `test` keys.
+
+renovate.json:
+
+```json
+{
+  "regexManagers": [
+    {
+      "fileMatch": ["^example.json$"],
+      "matchStringsStrategy": "recursive",
+      "matchStrings": [
+        "\"backup\":\\s*{[^}]*}",
+        "\"test\":\\s*\\{[^}]*}",
+        "\"name\":\\s*\"(?<depName>.*)\"[^\"]*\"type\":\\s*\"(?<datasource>.*)\"[^\"]*\"value\":\\s*\"(?<currentValue>.*)\""
+      ],
+      "datasourceTemplate": "docker"
+    },
+    {
+      "fileMatch": ["^example.json$"],
+      "matchStringsStrategy": "recursive",
+      "matchStrings": [
+        "\"test\":\\s*\\{[^}]*}",
+        "\"name\":\\s*\"(?<depName>.*)\"[^\"]*\"type\":\\s*\"(?<datasource>.*)\"[^\"]*\"value\":\\s*\"(?<currentValue>.*)\""
+      ],
+      "datasourceTemplate": "docker"
+    }
+  ]
+}
+```
+
+example.json:
+
+```json
+{
+  "backup": {
+    "test": {
+      "name": "grafana/loki",
+      "type": "docker",
+      "value": "1.6.1"
+    }
+  },
+  "setup": {
+    "test": {
+      "name": "python",
+      "type": "docker",
+      "value": "3.9.0"
+    }
+  }
+}
+```
+
+#### combination
+
+This option allows the possibility to combine the values of multiple lines inside a file.
+While using multiple lines is also possible using both other `matchStringStrategy` values, the `combination` approach is less susceptible to white space or line breaks stopping a match.
+
+`combination` will only match at most one dependency per file, so if you want to update multiple dependencies using `combination` you have to define multiple regex managers.
+
+Matched group values will be merged to form a single dependency.
+
+renovate.json:
+
+```json
+{
+  "regexManagers": [
+    {
+      "fileMatch": ["^main.yml$"],
+      "matchStringsStrategy": "combination",
+      "matchStrings": [
+        "prometheus_image:\\s*\"(?<depName>.*)\"\\s*//",
+        "prometheus_version:\\s*\"(?<currentValue>.*)\"\\s*//"
+      ],
+      "datasourceTemplate": "docker"
+    },
+    {
+      "fileMatch": ["^main.yml$"],
+      "matchStringsStrategy": "combination",
+      "matchStrings": [
+        "thanos_image:\\s*\"(?<depName>.*)\"\\s*//",
+        "thanos_version:\\s*\"(?<currentValue>.*)\"\\s*//"
+      ],
+      "datasourceTemplate": "docker"
+    }
+  ]
+}
+```
+
+Ansible variable file ( yaml ):
+
+```yaml
+prometheus_image: "prom/prometheus"  // a comment
+prometheus_version: "v2.21.0" // a comment
+------
+thanos_image: "prom/prometheus"  // a comment
+thanos_version: "0.15.0" // a comment
+```
+
+In the above example, each regex manager will match a single dependency each.
+
 ### depNameTemplate
 
 If `depName` cannot be captured with a named capture group in `matchString` then it can be defined manually using this field.
diff --git a/lib/config/common.ts b/lib/config/common.ts
index 86032544dde66530a0ed9c794ad6a71e5b8e9e3e..26f9205669e0659cf5b837ae8da6dca2b634c63f 100644
--- a/lib/config/common.ts
+++ b/lib/config/common.ts
@@ -127,6 +127,7 @@ export type RenovateRepository =
 export interface CustomManager {
   fileMatch: string[];
   matchStrings: string[];
+  matchStringsStrategy?: string;
   depNameTemplate?: string;
   datasourceTemplate?: string;
   lookupNameTemplate?: string;
@@ -205,6 +206,8 @@ export type UpdateType =
   | 'rollback'
   | 'bump';
 
+export type MatchStringsStrategy = 'any' | 'recursive' | 'combination';
+
 // TODO: Proper typings
 export interface PackageRule
   extends RenovateSharedConfig,
diff --git a/lib/config/definitions.ts b/lib/config/definitions.ts
index 104c9aaf66766fea38006fc29a0f3dd5cf6625a0..f7cfa954f800880719bfe53e4d8d09543a4589ef 100644
--- a/lib/config/definitions.ts
+++ b/lib/config/definitions.ts
@@ -1807,6 +1807,15 @@ const options: RenovateOptions[] = [
     cli: false,
     env: false,
   },
+  {
+    name: 'matchStringsStrategy',
+    description: 'Strategy how to interpret matchStrings',
+    type: 'string',
+    default: 'any',
+    parent: 'regexManagers',
+    cli: false,
+    env: false,
+  },
   {
     name: 'depNameTemplate',
     description:
diff --git a/lib/config/validation.ts b/lib/config/validation.ts
index 0bf9cebffbb737f42e88d741907daca2401020f3..36e63095d6d2b60bd1c8748d836cbc8a74bbc883 100644
--- a/lib/config/validation.ts
+++ b/lib/config/validation.ts
@@ -268,6 +268,7 @@ export async function validateConfig(
               const allowedKeys = [
                 'fileMatch',
                 'matchStrings',
+                'matchStringsStrategy',
                 'depNameTemplate',
                 'lookupNameTemplate',
                 'datasourceTemplate',
@@ -289,14 +290,6 @@ export async function validateConfig(
                       ', '
                     )}`,
                   });
-                } else if (
-                  !regexManager.matchStrings ||
-                  regexManager.matchStrings.length !== 1
-                ) {
-                  errors.push({
-                    depName: 'Configuration Error',
-                    message: `Each Regex Manager must contain a matchStrings array of length one`,
-                  });
                 } else if (!is.nonEmptyArray(regexManager.fileMatch)) {
                   errors.push({
                     depName: 'Configuration Error',
diff --git a/lib/manager/common.ts b/lib/manager/common.ts
index 8cfa32501ead316bdeca4ae9e8efeb09a302810c..3bc5c0a9595ad4619bebda5ade5709fe81dd7c15 100644
--- a/lib/manager/common.ts
+++ b/lib/manager/common.ts
@@ -1,5 +1,10 @@
 import { ReleaseType } from 'semver';
-import { GlobalConfig, UpdateType, ValidationMessage } from '../config/common';
+import {
+  GlobalConfig,
+  MatchStringsStrategy,
+  UpdateType,
+  ValidationMessage,
+} from '../config/common';
 import { RangeStrategy, SkipReason } from '../types';
 import { File } from '../util/git';
 
@@ -29,6 +34,7 @@ export interface ExtractConfig extends ManagerConfig {
 
 export interface CustomExtractConfig extends ExtractConfig {
   matchStrings: string[];
+  matchStringsStrategy?: MatchStringsStrategy;
   depNameTemplate?: string;
   lookupNameTemplate?: string;
   datasourceTemplate?: string;
@@ -96,6 +102,7 @@ export interface PackageFile<T = Record<string, any>>
   yarnrc?: string;
   yarnWorkspacesPackages?: string[] | string;
   matchStrings?: string[];
+  matchStringsStrategy?: MatchStringsStrategy;
 }
 
 export interface Package<T> extends ManagerData<T> {
diff --git a/lib/manager/regex/__fixtures__/ansible.yml b/lib/manager/regex/__fixtures__/ansible.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b3647cd99fbeb1b678a160df6f114ada656672c5
--- /dev/null
+++ b/lib/manager/regex/__fixtures__/ansible.yml
@@ -0,0 +1,5 @@
+prometheus_image: "prom/prometheus"  // depName gets initially set
+prometheus_version: "v2.21.0" // currentValue get set
+
+someother_image: "" // will not be set as group value is null/empty string
+someother_version: "0.12.0" // overwrites currentValue as later values take precedence.
diff --git a/lib/manager/regex/__fixtures__/example.json b/lib/manager/regex/__fixtures__/example.json
new file mode 100644
index 0000000000000000000000000000000000000000..d764721e232edb18c887082931a6dc09986143e0
--- /dev/null
+++ b/lib/manager/regex/__fixtures__/example.json
@@ -0,0 +1,26 @@
+{
+  "group1": {
+    "name": "prom/prometheus",
+    "type": "docker",
+    "value": "v2.19.0"
+  },
+  "group2": {
+    "name": "grafana/grafana",
+    "type": "docker",
+    "value": "7.2.2"
+  },
+  "backup": {
+    "test": {
+      "name": "grafana/loki",
+      "type": "docker",
+      "value": "1.6.1"
+    }
+  },
+  "setup": {
+    "test": {
+      "name": "python",
+      "type": "docker",
+      "value": "3.9.0"
+    }
+  }
+}
diff --git a/lib/manager/regex/__snapshots__/index.spec.ts.snap b/lib/manager/regex/__snapshots__/index.spec.ts.snap
index 2cbc5039f10181ae9d72d8588d70aa22c2a42416..cb28bedfe3cb5a93e05e76278a8382a44d987471 100644
--- a/lib/manager/regex/__snapshots__/index.spec.ts.snap
+++ b/lib/manager/regex/__snapshots__/index.spec.ts.snap
@@ -100,3 +100,139 @@ Object {
   ],
 }
 `;
+
+exports[`manager/regex/index extracts multiple dependencies with multiple matchStrings 1`] = `
+Object {
+  "deps": Array [
+    Object {
+      "currentValue": "6.2",
+      "datasource": "gradle-version",
+      "depName": "gradle",
+      "replaceString": "ENV GRADLE_VERSION=6.2 # gradle-version/gradle&versioning=maven
+",
+      "versioning": "maven",
+    },
+    Object {
+      "currentValue": "10.19.0",
+      "datasource": "github-tags",
+      "depName": "nodejs/node",
+      "replaceString": "ENV NODE_VERSION=10.19.0 # github-tags/nodejs/node&versioning=node
+",
+      "versioning": "node",
+    },
+  ],
+  "matchStrings": Array [
+    "ENV GRADLE_VERSION=(?<currentValue>.*) # (?<datasource>.*?)/(?<depName>.*?)(\\\\&versioning=(?<versioning>.*?))?\\\\s",
+    "ENV NODE_VERSION=(?<currentValue>.*) # (?<datasource>.*?)/(?<depName>.*?)(\\\\&versioning=(?<versioning>.*?))?\\\\s",
+  ],
+}
+`;
+
+exports[`manager/regex/index extracts with combination strategy 1`] = `
+Object {
+  "deps": Array [
+    Object {
+      "currentValue": "v2.21.0",
+      "datasource": "docker",
+      "depName": "prom/prometheus",
+      "replaceString": "prometheus_version: \\"v2.21.0\\" //",
+    },
+  ],
+  "matchStrings": Array [
+    "prometheus_image:\\\\s*\\"(?<depName>.*)\\"\\\\s*\\\\/\\\\/",
+    "prometheus_version:\\\\s*\\"(?<currentValue>.*)\\"\\\\s*\\\\/\\\\/",
+  ],
+  "matchStringsStrategy": "combination",
+}
+`;
+
+exports[`manager/regex/index extracts with combination strategy and multiple matches 1`] = `
+Object {
+  "deps": Array [
+    Object {
+      "currentValue": "0.12.0",
+      "datasource": "docker",
+      "depName": "prom/prometheus",
+      "replaceString": "someother_version: \\"0.12.0\\" //",
+    },
+  ],
+  "matchStrings": Array [
+    ".*_image:\\\\s*\\"(?<depName>.*)\\"\\\\s*\\\\/\\\\/",
+    ".*_version:\\\\s*\\"(?<currentValue>.*)\\"\\\\s*\\\\/\\\\/",
+  ],
+  "matchStringsStrategy": "combination",
+}
+`;
+
+exports[`manager/regex/index extracts with recursive strategy and fail because of not sufficient regexes 1`] = `null`;
+
+exports[`manager/regex/index extracts with recursive strategy and fail because there is no match 1`] = `null`;
+
+exports[`manager/regex/index extracts with recursive strategy and multiple layers  1`] = `
+Object {
+  "deps": Array [
+    Object {
+      "currentValue": "1.6.1",
+      "datasource": "docker",
+      "depName": "grafana/loki",
+      "replaceString": "\\"name\\": \\"grafana/loki\\",
+      \\"type\\": \\"docker\\",
+      \\"value\\": \\"1.6.1\\"",
+    },
+  ],
+  "matchStrings": Array [
+    "\\"backup\\":\\\\s*{[^}]*}",
+    "\\"test\\":\\\\s*\\\\{[^}]*}",
+    "\\"name\\":\\\\s*\\"(?<depName>.*)\\"[^\\"]*\\"type\\":\\\\s*\\"(?<datasource>.*)\\"[^\\"]*\\"value\\":\\\\s*\\"(?<currentValue>.*)\\"",
+  ],
+  "matchStringsStrategy": "recursive",
+}
+`;
+
+exports[`manager/regex/index extracts with recursive strategy and multiple matches 1`] = `
+Object {
+  "deps": Array [
+    Object {
+      "currentValue": "v2.19.0",
+      "datasource": "docker",
+      "depName": "prom/prometheus",
+      "replaceString": "\\"name\\": \\"prom/prometheus\\",
+    \\"type\\": \\"docker\\",
+    \\"value\\": \\"v2.19.0\\"",
+    },
+    Object {
+      "currentValue": "7.2.2",
+      "datasource": "docker",
+      "depName": "grafana/grafana",
+      "replaceString": "\\"name\\": \\"grafana/grafana\\",
+    \\"type\\": \\"docker\\",
+    \\"value\\": \\"7.2.2\\"",
+    },
+  ],
+  "matchStrings": Array [
+    "\\"group.{1}\\":\\\\s*\\\\{[^}]*}",
+    "\\"name\\":\\\\s*\\"(?<depName>.*)\\"[^\\"]*\\"type\\":\\\\s*\\"(?<datasource>.*)\\"[^\\"]*\\"value\\":\\\\s*\\"(?<currentValue>.*)\\"",
+  ],
+  "matchStringsStrategy": "recursive",
+}
+`;
+
+exports[`manager/regex/index extracts with recursive strategy and single match 1`] = `
+Object {
+  "deps": Array [
+    Object {
+      "currentValue": "v2.19.0",
+      "datasource": "docker",
+      "depName": "prom/prometheus",
+      "replaceString": "\\"name\\": \\"prom/prometheus\\",
+    \\"type\\": \\"docker\\",
+    \\"value\\": \\"v2.19.0\\"",
+    },
+  ],
+  "matchStrings": Array [
+    "\\"group1\\":\\\\s*\\\\{[^}]*}",
+    "\\"name\\":\\\\s*\\"(?<depName>.*)\\"[^\\"]*\\"type\\":\\\\s*\\"(?<datasource>.*)\\"[^\\"]*\\"value\\":\\\\s*\\"(?<currentValue>.*)\\"",
+  ],
+  "matchStringsStrategy": "recursive",
+}
+`;
diff --git a/lib/manager/regex/index.spec.ts b/lib/manager/regex/index.spec.ts
index 39faae5dda9bfdb1512eec9b29cb81bec45a28de..1716d539792d2a0bb71b7c6db149598ceea336c5 100644
--- a/lib/manager/regex/index.spec.ts
+++ b/lib/manager/regex/index.spec.ts
@@ -1,12 +1,22 @@
 import { readFileSync } from 'fs';
 import { resolve } from 'upath';
 import { getName } from '../../../test/util';
+import { CustomExtractConfig } from '../common';
 import { defaultConfig, extractPackageFile } from '.';
 
 const dockerfileContent = readFileSync(
   resolve(__dirname, `./__fixtures__/Dockerfile`),
   'utf8'
 );
+const ansibleYamlContent = readFileSync(
+  resolve(__dirname, `./__fixtures__/ansible.yml`),
+  'utf8'
+);
+const exampleJsonContent = readFileSync(
+  resolve(__dirname, `./__fixtures__/example.json`),
+  'utf8'
+);
+
 describe(getName(__filename), () => {
   it('has default config', () => {
     expect(defaultConfig).toEqual({
@@ -86,4 +96,136 @@ describe(getName(__filename), () => {
     );
     expect(res).toMatchSnapshot();
   });
+  it('extracts multiple dependencies with multiple matchStrings', async () => {
+    const config = {
+      matchStrings: [
+        'ENV GRADLE_VERSION=(?<currentValue>.*) # (?<datasource>.*?)/(?<depName>.*?)(\\&versioning=(?<versioning>.*?))?\\s',
+        'ENV NODE_VERSION=(?<currentValue>.*) # (?<datasource>.*?)/(?<depName>.*?)(\\&versioning=(?<versioning>.*?))?\\s',
+      ],
+      versioningTemplate:
+        '{{#if versioning}}{{versioning}}{{else}}semver{{/if}}',
+    };
+    const res = await extractPackageFile(
+      dockerfileContent,
+      'Dockerfile',
+      config
+    );
+    expect(res).toMatchSnapshot();
+    expect(res.deps).toHaveLength(2);
+    expect(
+      res.deps.find((dep) => dep.depName === 'nodejs/node').versioning
+    ).toEqual('node');
+    expect(res.deps.find((dep) => dep.depName === 'gradle').versioning).toEqual(
+      'maven'
+    );
+  });
+  it('extracts with combination strategy', async () => {
+    const config: CustomExtractConfig = {
+      matchStrings: [
+        'prometheus_image:\\s*"(?<depName>.*)"\\s*\\/\\/',
+        'prometheus_version:\\s*"(?<currentValue>.*)"\\s*\\/\\/',
+      ],
+      matchStringsStrategy: 'combination',
+      datasourceTemplate: 'docker',
+    };
+    const res = await extractPackageFile(
+      ansibleYamlContent,
+      'ansible.yml',
+      config
+    );
+    expect(res).toMatchSnapshot();
+    expect(res.deps).toHaveLength(1);
+  });
+  it('extracts with combination strategy and multiple matches', async () => {
+    const config: CustomExtractConfig = {
+      matchStrings: [
+        '.*_image:\\s*"(?<depName>.*)"\\s*\\/\\/',
+        '.*_version:\\s*"(?<currentValue>.*)"\\s*\\/\\/',
+      ],
+      matchStringsStrategy: 'combination',
+      datasourceTemplate: 'docker',
+    };
+    const res = await extractPackageFile(
+      ansibleYamlContent,
+      'ansible.yml',
+      config
+    );
+    expect(res).toMatchSnapshot();
+    expect(res.deps).toHaveLength(1);
+  });
+  it('extracts with recursive strategy and single match', async () => {
+    const config: CustomExtractConfig = {
+      matchStrings: [
+        '"group1":\\s*\\{[^}]*}',
+        '"name":\\s*"(?<depName>.*)"[^"]*"type":\\s*"(?<datasource>.*)"[^"]*"value":\\s*"(?<currentValue>.*)"',
+      ],
+      matchStringsStrategy: 'recursive',
+    };
+    const res = await extractPackageFile(
+      exampleJsonContent,
+      'example.json',
+      config
+    );
+    expect(res).toMatchSnapshot();
+    expect(res.deps).toHaveLength(1);
+  });
+  it('extracts with recursive strategy and multiple matches', async () => {
+    const config: CustomExtractConfig = {
+      matchStrings: [
+        '"group.{1}":\\s*\\{[^}]*}',
+        '"name":\\s*"(?<depName>.*)"[^"]*"type":\\s*"(?<datasource>.*)"[^"]*"value":\\s*"(?<currentValue>.*)"',
+      ],
+      matchStringsStrategy: 'recursive',
+    };
+    const res = await extractPackageFile(
+      exampleJsonContent,
+      'example.json',
+      config
+    );
+    expect(res).toMatchSnapshot();
+    expect(res.deps).toHaveLength(2);
+  });
+  it('extracts with recursive strategy and multiple layers ', async () => {
+    const config: CustomExtractConfig = {
+      matchStrings: [
+        '"backup":\\s*{[^}]*}',
+        '"test":\\s*\\{[^}]*}',
+        '"name":\\s*"(?<depName>.*)"[^"]*"type":\\s*"(?<datasource>.*)"[^"]*"value":\\s*"(?<currentValue>.*)"',
+      ],
+      matchStringsStrategy: 'recursive',
+    };
+    const res = await extractPackageFile(
+      exampleJsonContent,
+      'example.json',
+      config
+    );
+    expect(res).toMatchSnapshot();
+    expect(res.deps).toHaveLength(1);
+  });
+  it('extracts with recursive strategy and fail because of not sufficient regexes', async () => {
+    const config: CustomExtractConfig = {
+      matchStrings: ['"group.{1}":\\s*\\{[^}]*}'],
+      matchStringsStrategy: 'recursive',
+    };
+    const res = await extractPackageFile(
+      exampleJsonContent,
+      'example.json',
+      config
+    );
+    expect(res).toMatchSnapshot();
+    expect(res).toBeNull();
+  });
+  it('extracts with recursive strategy and fail because there is no match', async () => {
+    const config: CustomExtractConfig = {
+      matchStrings: ['"trunk.{1}":\\s*\\{[^}]*}'],
+      matchStringsStrategy: 'recursive',
+    };
+    const res = await extractPackageFile(
+      exampleJsonContent,
+      'example.json',
+      config
+    );
+    expect(res).toMatchSnapshot();
+    expect(res).toBeNull();
+  });
 });
diff --git a/lib/manager/regex/index.ts b/lib/manager/regex/index.ts
index 7eb28b8eec4382dd5515e2f5dd6d8dafdb943d71..1b3c724cfab6796d8b20c1bba0864403ddfbf93e 100644
--- a/lib/manager/regex/index.ts
+++ b/lib/manager/regex/index.ts
@@ -2,62 +2,171 @@ import url from 'url';
 import { logger } from '../../logger';
 import { regEx } from '../../util/regex';
 import * as template from '../../util/template';
-import { CustomExtractConfig, PackageFile, Result } from '../common';
+import {
+  CustomExtractConfig,
+  PackageDependency,
+  PackageFile,
+  Result,
+} from '../common';
 
 export const defaultConfig = {
   pinDigests: false,
 };
 
-export function extractPackageFile(
-  content: string,
-  packageFile: string,
-  config: CustomExtractConfig
-): Result<PackageFile | null> {
-  const regexMatch = regEx(config.matchStrings[0], 'g');
-  const deps = [];
+const validMatchFields = [
+  'depName',
+  'lookupName',
+  'currentValue',
+  'currentDigest',
+  'datasource',
+  'versioning',
+  'registryUrl',
+];
+
+function regexMatchAll(regex: RegExp, content: string): RegExpMatchArray[] {
+  const matches: RegExpMatchArray[] = [];
   let matchResult;
   do {
-    matchResult = regexMatch.exec(content);
+    matchResult = regex.exec(content);
     if (matchResult) {
-      const dep: any = {};
-      const { groups } = matchResult;
-      const fields = [
-        'depName',
-        'lookupName',
-        'currentValue',
-        'currentDigest',
-        'datasource',
-        'versioning',
-        'registryUrl',
-      ];
-      for (const field of fields) {
-        const fieldTemplate = `${field}Template`;
-        if (config[fieldTemplate]) {
-          try {
-            dep[field] = template.compile(config[fieldTemplate], groups);
-          } catch (err) {
-            logger.warn(
-              { template: config[fieldTemplate] },
-              'Error compiling template for custom manager'
-            );
-            return null;
+      matches.push(matchResult);
+    }
+  } while (matchResult);
+  return matches;
+}
+
+function createDependency(
+  matchResult: RegExpMatchArray,
+  config: CustomExtractConfig,
+  dep?: PackageDependency
+): PackageDependency {
+  const dependency = dep || {};
+  const { groups } = matchResult;
+  for (const field of validMatchFields) {
+    const fieldTemplate = `${field}Template`;
+    if (config[fieldTemplate]) {
+      try {
+        dependency[field] = template.compile(config[fieldTemplate], groups);
+      } catch (err) {
+        logger.warn(
+          { template: config[fieldTemplate] },
+          'Error compiling template for custom manager'
+        );
+        return null;
+      }
+    } else if (groups[field]) {
+      switch (field) {
+        case 'registryUrl':
+          // check if URL is valid and pack inside an array
+          if (url.parse(groups[field])) {
+            dependency.registryUrls = [groups[field]];
           }
-        } else if (groups[field]) {
-          dep[field] = groups[field];
-        }
+          break;
+        default:
+          dependency[field] = groups[field];
+          break;
       }
-      dep.replaceString = String(matchResult[0]);
-      if (dep.registryUrl) {
-        if (url.parse(dep.registryUrl)) {
-          dep.registryUrls = [dep.registryUrl];
+    }
+  }
+  dependency.replaceString = String(matchResult[0]);
+  return dependency;
+}
+
+function mergeDependency(deps: PackageDependency[]): PackageDependency {
+  const result: PackageDependency = {};
+  deps.forEach((dep) => {
+    validMatchFields.forEach((field) => {
+      if (dep[field]) {
+        result[field] = dep[field];
+        // save the line replaceString of the section which contains the current Value for a speed up lookup during the replace phase
+        if (field === 'currentValue') {
+          result.replaceString = dep.replaceString;
         }
-        delete dep.registryUrl;
       }
-      deps.push(dep);
+    });
+  });
+  return result;
+}
+
+function handleAny(
+  content: string,
+  packageFile: string,
+  config: CustomExtractConfig
+): PackageDependency[] {
+  return config.matchStrings
+    .map((matchString) => regEx(matchString, 'g'))
+    .flatMap((regex) => regexMatchAll(regex, content)) // match all regex to content, get all matches, reduce to single array
+    .map((matchResult) => createDependency(matchResult, config));
+}
+
+function handleCombination(
+  content: string,
+  packageFile: string,
+  config: CustomExtractConfig
+): PackageDependency[] {
+  const dep = handleAny(content, packageFile, config).reduce(
+    (mergedDep, currentDep) => mergeDependency([mergedDep, currentDep]),
+    {}
+  ); // merge fields of dependencies
+  return [dep];
+}
+
+function handleRecursive(
+  content: string,
+  packageFile: string,
+  config: CustomExtractConfig,
+  index = 0
+): PackageDependency[] {
+  const regexes = config.matchStrings.map((matchString) =>
+    regEx(matchString, 'g')
+  );
+  // abort if we have no matchString anymore
+  if (regexes[index] == null) {
+    return [];
+  }
+  return regexMatchAll(regexes[index], content).flatMap((match) => {
+    // if we have a depName and a currentValue with have the minimal viable definition
+    if (match?.groups?.depName && match?.groups?.currentValue) {
+      return createDependency(match, config);
     }
-  } while (matchResult);
+    return handleRecursive(match[0], packageFile, config, index + 1);
+  });
+}
+
+export function extractPackageFile(
+  content: string,
+  packageFile: string,
+  config: CustomExtractConfig
+): Result<PackageFile | null> {
+  let deps;
+  switch (config.matchStringsStrategy) {
+    default:
+    case 'any':
+      deps = handleAny(content, packageFile, config);
+      break;
+    case 'combination':
+      deps = handleCombination(content, packageFile, config);
+      break;
+    case 'recursive':
+      deps = handleRecursive(content, packageFile, config);
+      break;
+  }
+
+  // filter all null values
+  deps = deps.filter(Boolean);
   if (deps.length) {
-    return { deps, matchStrings: config.matchStrings };
+    if (config.matchStringsStrategy) {
+      return {
+        deps,
+        matchStrings: config.matchStrings,
+        matchStringsStrategy: config.matchStringsStrategy,
+      };
+    }
+    return {
+      deps,
+      matchStrings: config.matchStrings,
+    };
   }
+
   return null;
 }