diff --git a/lib/manager/api.ts b/lib/manager/api.ts
index 76fad55f08a9088063d4097785025a803f0900eb..3f45b28b1b1380eaab073ca49e5cb91774765b3d 100644
--- a/lib/manager/api.ts
+++ b/lib/manager/api.ts
@@ -21,6 +21,7 @@ import * as dockerCompose from './docker-compose';
 import * as dockerfile from './dockerfile';
 import * as droneci from './droneci';
 import * as flux from './flux';
+import * as fvm from './fvm';
 import * as gitSubmodules from './git-submodules';
 import * as githubActions from './github-actions';
 import * as gitlabci from './gitlabci';
@@ -93,6 +94,7 @@ api.set('docker-compose', dockerCompose);
 api.set('dockerfile', dockerfile);
 api.set('droneci', droneci);
 api.set('flux', flux);
+api.set('fvm', fvm);
 api.set('git-submodules', gitSubmodules);
 api.set('github-actions', githubActions);
 api.set('gitlabci', gitlabci);
diff --git a/lib/manager/fvm/extract.spec.ts b/lib/manager/fvm/extract.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..18cfcd257b2d35a5a58d52026b6f35a06485c0e1
--- /dev/null
+++ b/lib/manager/fvm/extract.spec.ts
@@ -0,0 +1,52 @@
+import { extractPackageFile } from '.';
+
+const packageFile = 'packageFile';
+
+describe('manager/fvm/extract', () => {
+  describe('extractPackageFile()', () => {
+    it('returns null for invalid json', () => {
+      expect(
+        extractPackageFile('clearly invalid json', packageFile)
+      ).toBeNull();
+    });
+    it('returns null for empty flutter sdk version', () => {
+      expect(extractPackageFile('{}', packageFile)).toBeNull();
+    });
+    it('returns null for non string flutter sdk version', () => {
+      expect(
+        extractPackageFile(
+          '{"flutterSdkVersion": 2.1, "flavors": {}}',
+          packageFile
+        )
+      ).toBeNull();
+    });
+    it('returns a result', () => {
+      const res = extractPackageFile(
+        '{"flutterSdkVersion": "2.10.1", "flavors": {}}',
+        packageFile
+      );
+      expect(res.deps).toEqual([
+        {
+          currentValue: '2.10.1',
+          datasource: 'github-tags',
+          depName: 'flutter',
+          lookupName: 'flutter/flutter',
+        },
+      ]);
+    });
+    it('supports non range', () => {
+      const res = extractPackageFile(
+        '{"flutterSdkVersion": "stable", "flavors": {}}',
+        packageFile
+      );
+      expect(res.deps).toEqual([
+        {
+          currentValue: 'stable',
+          datasource: 'github-tags',
+          depName: 'flutter',
+          lookupName: 'flutter/flutter',
+        },
+      ]);
+    });
+  });
+});
diff --git a/lib/manager/fvm/extract.ts b/lib/manager/fvm/extract.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5ecf17dc9695eefbf8c7f62271e2bde8c7113e79
--- /dev/null
+++ b/lib/manager/fvm/extract.ts
@@ -0,0 +1,40 @@
+import is from '@sindresorhus/is';
+import { GithubTagsDatasource } from '../../datasource/github-tags';
+import { logger } from '../../logger';
+import type { PackageDependency, PackageFile } from '../types';
+
+interface FvmConfig {
+  flutterSdkVersion: string;
+}
+
+export function extractPackageFile(
+  content: string,
+  packageFile: string
+): PackageFile | null {
+  let fvmConfig: FvmConfig;
+  try {
+    fvmConfig = JSON.parse(content);
+  } catch (err) {
+    logger.debug({ packageFile, err }, 'Invalid FVM config');
+    return null;
+  }
+
+  if (!fvmConfig.flutterSdkVersion) {
+    logger.debug(
+      { contents: fvmConfig },
+      'FVM config does not have flutterSdkVersion specified'
+    );
+    return null;
+  } else if (!is.string(fvmConfig.flutterSdkVersion)) {
+    logger.debug({ contents: fvmConfig }, 'flutterSdkVersion must be a string');
+    return null;
+  }
+
+  const dep: PackageDependency = {
+    depName: 'flutter',
+    currentValue: fvmConfig.flutterSdkVersion,
+    datasource: GithubTagsDatasource.id,
+    lookupName: 'flutter/flutter',
+  };
+  return { deps: [dep] };
+}
diff --git a/lib/manager/fvm/index.ts b/lib/manager/fvm/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d656241074fec6604b0906bf4856177b55d3aa75
--- /dev/null
+++ b/lib/manager/fvm/index.ts
@@ -0,0 +1,11 @@
+import { GithubTagsDatasource } from '../../datasource/github-tags';
+import * as semverVersioning from '../../versioning/semver';
+
+export { extractPackageFile } from './extract';
+
+export const supportedDatasources = [GithubTagsDatasource.id];
+
+export const defaultConfig = {
+  fileMatch: ['(^|\\/)\\.fvm\\/fvm_config\\.json$'],
+  versioning: semverVersioning.id,
+};
diff --git a/lib/manager/fvm/readme.md b/lib/manager/fvm/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..5d4f3ab310c1a3445f90761a0462fe087673a827
--- /dev/null
+++ b/lib/manager/fvm/readme.md
@@ -0,0 +1 @@
+Keeps the `.fvm/fvm_config.json` file updated.
diff --git a/tsconfig.strict.json b/tsconfig.strict.json
index c2583384fca8c1a3c979bce3222aa10af18dba50..25201cde3a32bd02cb07d92e7212b551cf47233d 100644
--- a/tsconfig.strict.json
+++ b/tsconfig.strict.json
@@ -145,6 +145,8 @@
     "lib/manager/flux/artifacts.ts",
     "lib/manager/flux/extract.ts",
     "lib/manager/flux/index.ts",
+    "lib/manager/fvm/extract.ts",
+    "lib/manager/fvm/index.ts",
     "lib/manager/git-submodules/artifacts.ts",
     "lib/manager/git-submodules/extract.ts",
     "lib/manager/git-submodules/index.ts",