diff --git a/lib/manager/helmv3/__snapshots__/extract.spec.ts.snap b/lib/manager/helmv3/__snapshots__/extract.spec.ts.snap
new file mode 100644
index 0000000000000000000000000000000000000000..624293839e15afb4a863197b0c696431188c4095
--- /dev/null
+++ b/lib/manager/helmv3/__snapshots__/extract.spec.ts.snap
@@ -0,0 +1,90 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`lib/manager/helm-requirements/extract extractPackageFile() parses simple Chart.yaml correctly 1`] = `
+Object {
+  "datasource": "helm",
+  "deps": Array [
+    Object {
+      "currentValue": "0.9.0",
+      "depName": "redis",
+      "registryUrls": Array [
+        "https://kubernetes-charts.storage.googleapis.com/",
+      ],
+    },
+    Object {
+      "currentValue": "0.8.1",
+      "depName": "postgresql",
+      "registryUrls": Array [
+        "https://kubernetes-charts.storage.googleapis.com/",
+      ],
+    },
+  ],
+}
+`;
+
+exports[`lib/manager/helm-requirements/extract extractPackageFile() resolves aliased registry urls 1`] = `
+Object {
+  "datasource": "helm",
+  "deps": Array [
+    Object {
+      "currentValue": "0.9.0",
+      "depName": "redis",
+      "registryUrls": Array [
+        "https://my-registry.gcr.io/",
+      ],
+    },
+  ],
+}
+`;
+
+exports[`lib/manager/helm-requirements/extract extractPackageFile() skips invalid registry urls 1`] = `
+Object {
+  "datasource": "helm",
+  "deps": Array [
+    Object {
+      "currentValue": "0.9.0",
+      "depName": "redis",
+      "registryUrls": Array [
+        "@placeholder",
+      ],
+      "skipReason": "placeholder-url",
+    },
+    Object {
+      "currentValue": "0.8.1",
+      "depName": "postgresql",
+      "registryUrls": Array [
+        "nope",
+      ],
+      "skipReason": "invalid-url",
+    },
+    Object {
+      "currentValue": "0.8.1",
+      "depName": "broken",
+      "skipReason": "no-repository",
+    },
+  ],
+}
+`;
+
+exports[`lib/manager/helm-requirements/extract extractPackageFile() skips local dependencies 1`] = `
+Object {
+  "datasource": "helm",
+  "deps": Array [
+    Object {
+      "currentValue": "0.9.0",
+      "depName": "redis",
+      "registryUrls": Array [
+        "https://kubernetes-charts.storage.googleapis.com/",
+      ],
+    },
+    Object {
+      "currentValue": "0.8.1",
+      "depName": "postgresql",
+      "registryUrls": Array [
+        "file:///some/local/path/",
+      ],
+      "skipReason": "local-dependency",
+    },
+  ],
+}
+`;
diff --git a/lib/manager/helmv3/extract.spec.ts b/lib/manager/helmv3/extract.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8a1185a4f74a66b8839374cfebce2bf1c4c770fd
--- /dev/null
+++ b/lib/manager/helmv3/extract.spec.ts
@@ -0,0 +1,229 @@
+import { fs } from '../../../test/util';
+import { extractPackageFile } from './extract';
+
+jest.mock('../../util/fs');
+
+describe('lib/manager/helm-requirements/extract', () => {
+  describe('extractPackageFile()', () => {
+    beforeEach(() => {
+      jest.resetAllMocks();
+      fs.readLocalFile = jest.fn();
+    });
+    it('skips invalid registry urls', () => {
+      const content = `
+      apiVersion: v2
+      appVersion: "1.0"
+      description: A Helm chart for Kubernetes
+      name: example
+      version: 0.1.0
+      dependencies:
+        - name: redis
+          version: 0.9.0
+          repository: '@placeholder'
+        - name: postgresql
+          version: 0.8.1
+          repository: nope
+        - name: broken
+          version: 0.8.1
+      `;
+      const fileName = 'Chart.yaml';
+      const result = extractPackageFile(content, fileName, {
+        aliases: {
+          stable: 'https://kubernetes-charts.storage.googleapis.com/',
+        },
+      });
+      expect(result).not.toBeNull();
+      expect(result).toMatchSnapshot();
+      expect(result.deps.every((dep) => dep.skipReason)).toEqual(true);
+    });
+    it('parses simple Chart.yaml correctly', () => {
+      const content = `
+      apiVersion: v2
+      appVersion: "1.0"
+      description: A Helm chart for Kubernetes
+      name: example
+      version: 0.1.0
+      dependencies:
+        - name: redis
+          version: 0.9.0
+          repository: https://kubernetes-charts.storage.googleapis.com/
+          enabled: true
+        - name: postgresql
+          version: 0.8.1
+          repository: https://kubernetes-charts.storage.googleapis.com/
+          condition: postgresql.enabled
+      `;
+      const fileName = 'Chart.yaml';
+      const result = extractPackageFile(content, fileName, {
+        aliases: {
+          stable: 'https://kubernetes-charts.storage.googleapis.com/',
+        },
+      });
+      expect(result).not.toBeNull();
+      expect(result).toMatchSnapshot();
+    });
+    it('resolves aliased registry urls', () => {
+      const content = `
+      apiVersion: v2
+      appVersion: "1.0"
+      description: A Helm chart for Kubernetes
+      name: example
+      version: 0.1.0
+      dependencies:
+        - name: redis
+          version: 0.9.0
+          repository: '@placeholder'
+      `;
+      const fileName = 'Chart.yaml';
+      const result = extractPackageFile(content, fileName, {
+        aliases: {
+          placeholder: 'https://my-registry.gcr.io/',
+        },
+      });
+      expect(result).not.toBeNull();
+      expect(result).toMatchSnapshot();
+      expect(result.deps.every((dep) => dep.skipReason)).toEqual(false);
+    });
+    it("doesn't fail if Chart.yaml is invalid", () => {
+      const content = `
+      Invalid Chart.yaml content.
+      arr:
+      [
+      `;
+      const fileName = 'Chart.yaml';
+      const result = extractPackageFile(content, fileName, {
+        aliases: {
+          stable: 'https://kubernetes-charts.storage.googleapis.com/',
+        },
+      });
+      expect(result).toBeNull();
+    });
+    it('skips local dependencies', () => {
+      const content = `
+      apiVersion: v2
+      appVersion: "1.0"
+      description: A Helm chart for Kubernetes
+      name: example
+      version: 0.1.0
+      dependencies:
+        - name: redis
+          version: 0.9.0
+          repository: https://kubernetes-charts.storage.googleapis.com/
+        - name: postgresql
+          version: 0.8.1
+          repository: file:///some/local/path/
+      `;
+      const fileName = 'Chart.yaml';
+      const result = extractPackageFile(content, fileName, {
+        aliases: {
+          stable: 'https://kubernetes-charts.storage.googleapis.com/',
+        },
+      });
+      expect(result).not.toBeNull();
+      expect(result).toMatchSnapshot();
+    });
+    it('returns null if no dependencies key', () => {
+      fs.readLocalFile.mockResolvedValueOnce(`
+      `);
+      const content = `
+      apiVersion: v2
+      appVersion: "1.0"
+      description: A Helm chart for Kubernetes
+      name: example
+      version: 0.1.0
+      hello: world
+      `;
+      const fileName = 'Chart.yaml';
+      const result = extractPackageFile(content, fileName, {
+        aliases: {
+          stable: 'https://kubernetes-charts.storage.googleapis.com/',
+        },
+      });
+      expect(result).toBeNull();
+    });
+    it('returns null if dependencies are an empty list', () => {
+      fs.readLocalFile.mockResolvedValueOnce(`
+      `);
+      const content = `
+      apiVersion: v2
+      appVersion: "1.0"
+      description: A Helm chart for Kubernetes
+      name: example
+      version: 0.1.0
+      dependencies: []
+      `;
+      const fileName = 'Chart.yaml';
+      const result = extractPackageFile(content, fileName, {
+        aliases: {
+          stable: 'https://kubernetes-charts.storage.googleapis.com/',
+        },
+      });
+      expect(result).toBeNull();
+    });
+    it('returns null if dependencies key is invalid', () => {
+      const content = `
+      apiVersion: v2
+      appVersion: "1.0"
+      description: A Helm chart for Kubernetes
+      name: example
+      version: 0.1.0
+      dependencies:
+        Invalid dependencies content.
+        [
+      `;
+      const fileName = 'Chart.yaml';
+      const result = extractPackageFile(content, fileName, {
+        aliases: {
+          stable: 'https://kubernetes-charts.storage.googleapis.com/',
+        },
+      });
+      expect(result).toBeNull();
+    });
+    it('returns null if Chart.yaml is empty', () => {
+      const content = '';
+      const fileName = 'Chart.yaml';
+      const result = extractPackageFile(content, fileName, {
+        aliases: {
+          stable: 'https://kubernetes-charts.storage.googleapis.com/',
+        },
+      });
+      expect(result).toBeNull();
+    });
+    it('returns null if Chart.yaml uses an unsupported apiVersion', () => {
+      const content = `
+      apiVersion: v1
+      appVersion: "1.0"
+      description: A Helm chart for Kubernetes
+      name: example
+      version: 0.1.0
+      `;
+      const fileName = 'Chart.yaml';
+      const result = extractPackageFile(content, fileName, {
+        aliases: {
+          stable: 'https://kubernetes-charts.storage.googleapis.com/',
+        },
+      });
+      expect(result).toBeNull();
+    });
+    it('returns null if name and version are missing for all dependencies', () => {
+      const content = `
+      apiVersion: v2
+      appVersion: "1.0"
+      description: A Helm chart for Kubernetes
+      name: example
+      version: 0.1.0
+      dependencies:
+        - repository: "test"
+        - repository: "test"
+          alias: "test"
+      `;
+      const fileName = 'Chart.yaml';
+      const result = extractPackageFile(content, fileName, {
+        aliases: {
+          stable: 'https://kubernetes-charts.storage.googleapis.com/',
+        },
+      });
+      expect(result).toBeNull();
+    });
+  });
+});
diff --git a/lib/manager/helmv3/extract.ts b/lib/manager/helmv3/extract.ts
new file mode 100644
index 0000000000000000000000000000000000000000..01ae9f4bdd6d51f28fa065e6c9149b2f040f9e6e
--- /dev/null
+++ b/lib/manager/helmv3/extract.ts
@@ -0,0 +1,88 @@
+import is from '@sindresorhus/is';
+import yaml from 'js-yaml';
+import * as datasourceHelm from '../../datasource/helm';
+import { logger } from '../../logger';
+import { SkipReason } from '../../types';
+import { ExtractConfig, PackageDependency, PackageFile } from '../common';
+
+export function extractPackageFile(
+  content: string,
+  fileName: string,
+  config: ExtractConfig
+): PackageFile | null {
+  let chart: {
+    apiVersion: string;
+    name: string;
+    version: string;
+    dependencies: Array<{ name: string; version: string; repository: string }>;
+  };
+  try {
+    chart = yaml.safeLoad(content, { json: true });
+    if (!(chart?.apiVersion && chart.name && chart.version)) {
+      logger.debug(
+        { fileName },
+        'Failed to find required fields in Chart.yaml'
+      );
+      return null;
+    }
+    if (chart.apiVersion !== 'v2') {
+      logger.debug(
+        { fileName },
+        'Unsupported Chart apiVersion. Only v2 is supported.'
+      );
+      return null;
+    }
+  } catch (err) {
+    logger.debug({ fileName }, 'Failed to parse helm Chart.yaml');
+    return null;
+  }
+  let deps: PackageDependency[] = [];
+  if (!is.nonEmptyArray(chart?.dependencies)) {
+    logger.debug({ fileName }, 'Chart has no dependencies');
+    return null;
+  }
+  const validDependencies = chart.dependencies.filter(
+    (dep) => is.nonEmptyString(dep.name) && is.nonEmptyString(dep.version)
+  );
+  if (!is.nonEmptyArray(validDependencies)) {
+    logger.debug('Name and/or version missing for all dependencies');
+    return null;
+  }
+  deps = validDependencies.map((dep) => {
+    const res: PackageDependency = {
+      depName: dep.name,
+      currentValue: dep.version,
+    };
+    if (dep.repository) {
+      res.registryUrls = [dep.repository];
+      if (dep.repository.startsWith('@')) {
+        const repoWithAtRemoved = dep.repository.slice(1);
+        const alias = config.aliases[repoWithAtRemoved];
+        if (alias) {
+          res.registryUrls = [alias];
+          return res;
+        }
+
+        res.skipReason = SkipReason.PlaceholderUrl;
+      } else {
+        try {
+          const url = new URL(dep.repository);
+          if (url.protocol === 'file:') {
+            res.skipReason = SkipReason.LocalDependency;
+          }
+        } catch (err) {
+          logger.debug({ err }, 'Error parsing url');
+          res.skipReason = SkipReason.InvalidUrl;
+        }
+      }
+    } else {
+      res.skipReason = SkipReason.NoRepository;
+    }
+    return res;
+  });
+  const res = {
+    deps,
+    datasource: datasourceHelm.id,
+  };
+  return res;
+}
diff --git a/lib/manager/helmv3/index.ts b/lib/manager/helmv3/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0660e2e055846b79d4fcc18952d1eddbc1bd17ae
--- /dev/null
+++ b/lib/manager/helmv3/index.ts
@@ -0,0 +1,9 @@
+export { extractPackageFile } from './extract';
+
+export const defaultConfig = {
+  aliases: {
+    stable: 'https://kubernetes-charts.storage.googleapis.com/',
+  },
+  commitMessageTopic: 'helm chart {{depName}}',
+  fileMatch: ['(^|/)Chart.yaml$'],
+};
diff --git a/lib/manager/helmv3/readme.md b/lib/manager/helmv3/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..7c0cd6e68b343da06659fe82cd37db2734616ee7
--- /dev/null
+++ b/lib/manager/helmv3/readme.md
@@ -0,0 +1,3 @@
+Renovate supports updating Helm Chart references within `requirements.yaml` (Helm v2) and `Chart.yaml` (Helm v3) files.
+
+If your Helm charts make use of Aliases then you will need to configure an `aliases` object in your config to tell Renovate where to look for them.