diff --git a/lib/modules/datasource/api.ts b/lib/modules/datasource/api.ts
index 1f1949acd4bfa8fd4f8fd100e52e0d654ec9474b..45592575d9f69b5f386c08a0949bcdbf113f3bc0 100644
--- a/lib/modules/datasource/api.ts
+++ b/lib/modules/datasource/api.ts
@@ -11,6 +11,7 @@ import { CondaDatasource } from './conda';
 import { CpanDatasource } from './cpan';
 import { CrateDatasource } from './crate';
 import { DartDatasource } from './dart';
+import { DartVersionDatasource } from './dart-version';
 import { DenoDatasource } from './deno';
 import { DockerDatasource } from './docker';
 import { DotnetDatasource } from './dotnet';
@@ -67,6 +68,7 @@ api.set(CondaDatasource.id, new CondaDatasource());
 api.set(CpanDatasource.id, new CpanDatasource());
 api.set(CrateDatasource.id, new CrateDatasource());
 api.set(DartDatasource.id, new DartDatasource());
+api.set(DartVersionDatasource.id, new DartVersionDatasource());
 api.set(DenoDatasource.id, new DenoDatasource());
 api.set(DockerDatasource.id, new DockerDatasource());
 api.set(DotnetDatasource.id, new DotnetDatasource());
diff --git a/lib/modules/datasource/dart-version/__fixtures__/beta.json b/lib/modules/datasource/dart-version/__fixtures__/beta.json
new file mode 100644
index 0000000000000000000000000000000000000000..8e2c28bc7e9d8ea175cacc1f363c7c1cdbc876f7
--- /dev/null
+++ b/lib/modules/datasource/dart-version/__fixtures__/beta.json
@@ -0,0 +1,15 @@
+{
+	"kind": "storage#objects",
+	"prefixes": [
+		"channels/beta/release/2.17.0-69.2.beta/",
+		"channels/beta/release/2.17.0/",
+		"channels/beta/release/2.17.1/",
+		"channels/beta/release/2.18.0-271.8.beta/",
+		"channels/beta/release/2.18.0-44.1.beta/",
+		"channels/beta/release/2.18.0/",
+		"channels/beta/release/2.19.0-255.2.beta/",
+		"channels/beta/release/2.19.0-374.1.beta/",
+		"channels/beta/release/2.19.0-374.2.beta/",
+		"channels/beta/release/latest/"
+	]
+}
diff --git a/lib/modules/datasource/dart-version/__fixtures__/dev.json b/lib/modules/datasource/dart-version/__fixtures__/dev.json
new file mode 100644
index 0000000000000000000000000000000000000000..3fdc56abf1dd13188ad8145cdc6a57937dca046e
--- /dev/null
+++ b/lib/modules/datasource/dart-version/__fixtures__/dev.json
@@ -0,0 +1,15 @@
+{
+	"kind": "storage#objects",
+	"prefixes": [
+		"channels/dev/release/2.17.0-7.0.dev/",
+		"channels/dev/release/2.17.0-85.0.dev/",
+		"channels/dev/release/2.17.0-91.0.dev/",
+		"channels/dev/release/2.18.0-82.0.dev/",
+		"channels/dev/release/2.18.0-9.0.dev/",
+		"channels/dev/release/2.18.0-99.0.dev/",
+		"channels/dev/release/2.19.0-59.0.dev/",
+		"channels/dev/release/2.19.0-70.0.dev/",
+		"channels/dev/release/2.19.0-81.0.dev/",
+		"channels/dev/release/latest/"
+	]
+}
diff --git a/lib/modules/datasource/dart-version/__fixtures__/stable.json b/lib/modules/datasource/dart-version/__fixtures__/stable.json
new file mode 100644
index 0000000000000000000000000000000000000000..f5bb8cab7e838d9af9b18857baf0c1bfaccb4331
--- /dev/null
+++ b/lib/modules/datasource/dart-version/__fixtures__/stable.json
@@ -0,0 +1,12 @@
+{
+	"kind": "storage#objects",
+	"prefixes": [
+		"channels/stable/release/2.17.5/",
+		"channels/stable/release/2.17.6/",
+		"channels/stable/release/2.17.7/",
+		"channels/stable/release/2.18.0/",
+		"channels/stable/release/2.18.4/",
+		"channels/stable/release/2.18.5/",
+		"channels/stable/release/latest/"
+	]
+}
diff --git a/lib/modules/datasource/dart-version/index.spec.ts b/lib/modules/datasource/dart-version/index.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..798bab2496f07de88c75be954b61fb9f0519b2a7
--- /dev/null
+++ b/lib/modules/datasource/dart-version/index.spec.ts
@@ -0,0 +1,74 @@
+import { getPkgReleases } from '..';
+import { Fixtures } from '../../../../test/fixtures';
+import * as httpMock from '../../../../test/http-mock';
+import { EXTERNAL_HOST_ERROR } from '../../../constants/error-messages';
+import { DartVersionDatasource } from '.';
+
+const baseUrl = 'https://storage.googleapis.com';
+const urlPath =
+  '/storage/v1/b/dart-archive/o?delimiter=%2F&prefix=channels%2Fstable%2Frelease%2F&alt=json';
+const datasource = DartVersionDatasource.id;
+const depName = 'dart';
+const channels = ['stable', 'beta', 'dev'];
+
+describe('modules/datasource/dart-version/index', () => {
+  describe('getReleases', () => {
+    it('throws for 500', async () => {
+      httpMock.scope(baseUrl).get(urlPath).reply(500);
+      await expect(
+        getPkgReleases({
+          datasource,
+          depName,
+        })
+      ).rejects.toThrow(EXTERNAL_HOST_ERROR);
+    });
+
+    it('returns null for error', async () => {
+      httpMock.scope(baseUrl).get(urlPath).replyWithError('error');
+      expect(
+        await getPkgReleases({
+          datasource,
+          depName,
+        })
+      ).toBeNull();
+    });
+
+    it('returns null for empty 200 OK', async () => {
+      httpMock.scope(baseUrl).get(urlPath).reply(200, []);
+      expect(
+        await getPkgReleases({
+          datasource,
+          depName,
+        })
+      ).toBeNull();
+    });
+
+    it('processes real data', async () => {
+      for (const channel of channels) {
+        httpMock
+          .scope(baseUrl)
+          .get(
+            `/storage/v1/b/dart-archive/o?delimiter=%2F&prefix=channels%2F${channel}%2Frelease%2F&alt=json`
+          )
+          .reply(200, Fixtures.get(`${channel}.json`));
+      }
+
+      const res = await getPkgReleases({
+        datasource,
+        depName,
+      });
+
+      expect(res).toBeDefined();
+      expect(res?.sourceUrl).toBe('https://github.com/dart-lang/sdk');
+      expect(res?.releases).toHaveLength(21);
+      expect(res?.releases).toIncludeAllPartialMembers([
+        { version: '2.18.0', isStable: true },
+        { version: '2.17.7', isStable: true },
+        { version: '2.19.0-374.2.beta', isStable: false },
+        { version: '2.18.0-44.1.beta', isStable: false },
+        { version: '2.19.0-81.0.dev', isStable: false },
+        { version: '2.18.0-99.0.dev', isStable: false },
+      ]);
+    });
+  });
+});
diff --git a/lib/modules/datasource/dart-version/index.ts b/lib/modules/datasource/dart-version/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b350f562b2a26ee662d2fee5260da033790f9e4b
--- /dev/null
+++ b/lib/modules/datasource/dart-version/index.ts
@@ -0,0 +1,80 @@
+import is from '@sindresorhus/is';
+import { regEx } from '../../../util/regex';
+import { Datasource } from '../datasource';
+import type { GetReleasesConfig, Release, ReleaseResult } from '../types';
+import type { DartResponse } from './types';
+
+export const stableVersionRegex = regEx(/^\d+\.\d+\.\d+$/);
+
+export class DartVersionDatasource extends Datasource {
+  static readonly id = 'dart-version';
+
+  constructor() {
+    super(DartVersionDatasource.id);
+  }
+
+  override readonly customRegistrySupport = false;
+
+  override readonly defaultRegistryUrls = ['https://storage.googleapis.com'];
+
+  override readonly caching = true;
+
+  private readonly channels = ['stable', 'beta', 'dev'];
+
+  async getReleases({
+    registryUrl,
+  }: GetReleasesConfig): Promise<ReleaseResult | null> {
+    // istanbul ignore if
+    if (!registryUrl) {
+      return null;
+    }
+    const result: ReleaseResult = {
+      homepage: 'https://dart.dev/',
+      sourceUrl: 'https://github.com/dart-lang/sdk',
+      registryUrl,
+      releases: [],
+    };
+    try {
+      for (const channel of this.channels) {
+        const resp = (
+          await this.http.getJson<DartResponse>(
+            `${registryUrl}/storage/v1/b/dart-archive/o?delimiter=%2F&prefix=channels%2F${channel}%2Frelease%2F&alt=json`
+          )
+        ).body;
+        const releases = this.getReleasesFromResponse(channel, resp.prefixes);
+        result.releases.push(...releases);
+      }
+    } catch (err) {
+      this.handleGenericErrors(err);
+    }
+
+    return result.releases.length ? result : null;
+  }
+
+  private getReleasesFromResponse(
+    channel: string,
+    prefixes: string[]
+  ): Release[] {
+    return prefixes
+      .map((prefix) => this.getVersionFromPrefix(prefix))
+      .filter(is.string)
+      .filter((version) => {
+        if (
+          version === 'latest' ||
+          // The API response contains a stable version being released as a non-stable
+          // release. So we filter out these releases here.
+          (channel !== 'stable' && stableVersionRegex.test(version))
+        ) {
+          return false;
+        }
+        return true;
+      })
+      .map((version) => ({ version, isStable: channel === 'stable' }));
+  }
+
+  // Prefix should have a format of "channels/stable/release/2.9.3/"
+  private getVersionFromPrefix(prefix: string): string | undefined {
+    const parts = prefix.split('/');
+    return parts[parts.length - 2];
+  }
+}
diff --git a/lib/modules/datasource/dart-version/types.ts b/lib/modules/datasource/dart-version/types.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8061750f2e4595fce991626b6046edcd767be973
--- /dev/null
+++ b/lib/modules/datasource/dart-version/types.ts
@@ -0,0 +1,4 @@
+export interface DartResponse {
+  kind: string;
+  prefixes: string[];
+}