diff --git a/lib/datasource/api.ts b/lib/datasource/api.ts
index b6c3d5113721390bb923d2e5ff7a60b4169c021f..356af4bc8a106f33f534d509ffd805078a22d0ae 100644
--- a/lib/datasource/api.ts
+++ b/lib/datasource/api.ts
@@ -11,6 +11,7 @@ import * as gitRefs from './git-refs';
 import * as gitTags from './git-tags';
 import * as githubReleases from './github-releases';
 import * as githubTags from './github-tags';
+import { GitlabReleasesDatasource } from './gitlab-releases';
 import * as gitlabTags from './gitlab-tags';
 import * as go from './go';
 import { GradleVersionDatasource } from './gradle-version';
@@ -50,6 +51,7 @@ api.set('git-tags', gitTags);
 api.set('github-releases', githubReleases);
 api.set('github-tags', githubTags);
 api.set('gitlab-tags', gitlabTags);
+api.set(GitlabReleasesDatasource.id, new GitlabReleasesDatasource());
 api.set('go', go);
 api.set('gradle-version', new GradleVersionDatasource());
 api.set('helm', new HelmDatasource());
diff --git a/lib/datasource/gitlab-releases/__snapshots__/index.spec.ts.snap b/lib/datasource/gitlab-releases/__snapshots__/index.spec.ts.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f39b80f4c89cfb92d1d24783708be5d89171380a
--- /dev/null
+++ b/lib/datasource/gitlab-releases/__snapshots__/index.spec.ts.snap
@@ -0,0 +1,43 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`datasource/gitlab-releases/index getReleases returns releases from custom registry 1`] = `
+Object {
+  "registryUrl": "https://gitlab.company.com",
+  "releases": Array [
+    Object {
+      "gitRef": "v1.0.0",
+      "registryUrl": "https://gitlab.company.com",
+      "releaseTimestamp": "2021-01-01T00:00:00.000Z",
+      "version": "v1.0.0",
+    },
+    Object {
+      "gitRef": "v1.1.0",
+      "registryUrl": "https://gitlab.company.com",
+      "releaseTimestamp": "2021-03-01T00:00:00.000Z",
+      "version": "v1.1.0",
+    },
+  ],
+  "sourceUrl": "https://gitlab.company.com/some/dep2",
+}
+`;
+
+exports[`datasource/gitlab-releases/index getReleases returns releases from default registry 1`] = `
+Object {
+  "registryUrl": "https://gitlab.com",
+  "releases": Array [
+    Object {
+      "gitRef": "v1.0.0",
+      "registryUrl": "https://gitlab.com",
+      "releaseTimestamp": "2021-01-01T00:00:00.000Z",
+      "version": "v1.0.0",
+    },
+    Object {
+      "gitRef": "v1.1.0",
+      "registryUrl": "https://gitlab.com",
+      "releaseTimestamp": "2021-03-01T00:00:00.000Z",
+      "version": "v1.1.0",
+    },
+  ],
+  "sourceUrl": "https://gitlab.com/some/dep2",
+}
+`;
diff --git a/lib/datasource/gitlab-releases/index.spec.ts b/lib/datasource/gitlab-releases/index.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e4a438d007619acd322c0156465c33404dc24fe9
--- /dev/null
+++ b/lib/datasource/gitlab-releases/index.spec.ts
@@ -0,0 +1,58 @@
+import { getPkgReleases } from '..';
+import * as httpMock from '../../../test/http-mock';
+import { GitlabReleasesDatasource } from '.';
+
+describe('datasource/gitlab-releases/index', () => {
+  describe('getReleases', () => {
+    const body = [
+      {
+        tag_name: 'v1.0.0',
+        released_at: '2021-01-01T00:00:00.000Z',
+      },
+      {
+        tag_name: 'v1.1.0',
+        released_at: '2021-03-01T00:00:00.000Z',
+      },
+    ];
+
+    it('returns releases from custom registry', async () => {
+      httpMock
+        .scope('https://gitlab.company.com')
+        .get('/api/v4/projects/some%2Fdep2/releases')
+        .reply(200, body);
+      const res = await getPkgReleases({
+        datasource: GitlabReleasesDatasource.id,
+        registryUrls: ['https://gitlab.company.com'],
+        depName: 'some/dep2',
+      });
+      expect(res).toMatchSnapshot();
+      expect(res.releases).toHaveLength(2);
+    });
+
+    it('returns releases from default registry', async () => {
+      httpMock
+        .scope('https://gitlab.com')
+        .get('/api/v4/projects/some%2Fdep2/releases')
+        .reply(200, body);
+      const res = await getPkgReleases({
+        datasource: GitlabReleasesDatasource.id,
+        depName: 'some/dep2',
+      });
+      expect(res).toMatchSnapshot();
+      expect(res.releases).toHaveLength(2);
+    });
+
+    it('return null if not found', async () => {
+      httpMock
+        .scope('https://gitlab.com')
+        .get('/api/v4/projects/some%2Fdep2/releases')
+        .reply(404);
+      expect(
+        await getPkgReleases({
+          datasource: GitlabReleasesDatasource.id,
+          depName: 'some/dep2',
+        })
+      ).toBeNull();
+    });
+  });
+});
diff --git a/lib/datasource/gitlab-releases/index.ts b/lib/datasource/gitlab-releases/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6a4cec10bf410c0594ab9db83454635ef217658b
--- /dev/null
+++ b/lib/datasource/gitlab-releases/index.ts
@@ -0,0 +1,54 @@
+import { cache } from '../../util/cache/package/decorator';
+import { GitlabHttp } from '../../util/http/gitlab';
+import { Datasource } from '../datasource';
+import type { GetReleasesConfig, Release, ReleaseResult } from '../types';
+import type { GitlabRelease } from './types';
+
+export class GitlabReleasesDatasource extends Datasource {
+  static readonly id = 'gitlab-releases';
+
+  override readonly defaultRegistryUrls = ['https://gitlab.com'];
+
+  static readonly registryStrategy = 'first';
+
+  constructor() {
+    super(GitlabReleasesDatasource.id);
+    this.http = new GitlabHttp(GitlabReleasesDatasource.id);
+  }
+
+  @cache({
+    namespace: `datasource-${GitlabReleasesDatasource.id}`,
+    key: ({ registryUrl, lookupName }: GetReleasesConfig) =>
+      `${registryUrl}/${lookupName}`,
+  })
+  async getReleases({
+    registryUrl,
+    lookupName,
+  }: GetReleasesConfig): Promise<ReleaseResult | null> {
+    const urlEncodedRepo = encodeURIComponent(lookupName);
+    const apiUrl = `${registryUrl}/api/v4/projects/${urlEncodedRepo}/releases`;
+
+    try {
+      const gitlabReleasesResponse = (
+        await this.http.getJson<GitlabRelease[]>(apiUrl)
+      ).body;
+
+      return {
+        sourceUrl: `${registryUrl}/${lookupName}`,
+        releases: gitlabReleasesResponse.map(({ tag_name, released_at }) => {
+          const release: Release = {
+            registryUrl,
+            gitRef: tag_name,
+            version: tag_name,
+            releaseTimestamp: released_at,
+          };
+          return release;
+        }),
+      };
+    } catch (e) {
+      this.handleGenericErrors(e);
+    }
+    /* istanbul ignore next */
+    return null;
+  }
+}
diff --git a/lib/datasource/gitlab-releases/types.ts b/lib/datasource/gitlab-releases/types.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d6b4cab4fbe72ed87ba06f770dcdc4976dac49ef
--- /dev/null
+++ b/lib/datasource/gitlab-releases/types.ts
@@ -0,0 +1,5 @@
+export interface GitlabRelease {
+  name: string;
+  tag_name: string;
+  released_at: string;
+}
diff --git a/lib/datasource/gitlab-tags/index.ts b/lib/datasource/gitlab-tags/index.ts
index bf3355c07b6f18194a06c5db9b8b044e7056b100..fde3a5f86974b596cfb0a81faf17749e7dfe7950 100644
--- a/lib/datasource/gitlab-tags/index.ts
+++ b/lib/datasource/gitlab-tags/index.ts
@@ -4,9 +4,9 @@ import { joinUrlParts } from '../../util/url';
 import type { GetReleasesConfig, ReleaseResult } from '../types';
 import type { GitlabTag } from './types';
 
-const gitlabApi = new GitlabHttp();
-
 export const id = 'gitlab-tags';
+const gitlabApi = new GitlabHttp(id);
+
 export const customRegistrySupport = true;
 export const defaultRegistryUrls = ['https://gitlab.com'];
 export const registryStrategy = 'first';
diff --git a/lib/types/platform/gitlab/index.spec.ts b/lib/types/platform/gitlab/index.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..945f2e4476ccd053cf2b3cf4cb5684f906b8a73a
--- /dev/null
+++ b/lib/types/platform/gitlab/index.spec.ts
@@ -0,0 +1,25 @@
+import {
+  PLATFORM_TYPE_GITHUB,
+  PLATFORM_TYPE_GITLAB,
+} from '../../../constants/platforms';
+import { GitlabReleasesDatasource } from '../../../datasource/gitlab-releases';
+import { id as GL_TAGS_DS } from '../../../datasource/gitlab-tags';
+import { GITLAB_API_USING_HOST_TYPES } from './index';
+
+describe('types/platform/gitlab/index', () => {
+  it('should be part of the GITLAB_API_USING_HOST_TYPES', () => {
+    expect(GITLAB_API_USING_HOST_TYPES.includes(GL_TAGS_DS)).toBeTrue();
+    expect(
+      GITLAB_API_USING_HOST_TYPES.includes(GitlabReleasesDatasource.id)
+    ).toBeTrue();
+    expect(
+      GITLAB_API_USING_HOST_TYPES.includes(PLATFORM_TYPE_GITLAB)
+    ).toBeTrue();
+  });
+
+  it('should be not part of the GITLAB_API_USING_HOST_TYPES ', () => {
+    expect(
+      GITLAB_API_USING_HOST_TYPES.includes(PLATFORM_TYPE_GITHUB)
+    ).toBeFalse();
+  });
+});
diff --git a/lib/types/platform/gitlab/index.ts b/lib/types/platform/gitlab/index.ts
index a67df13e1ae81c1c0443e9f0c7fba585a246f1a9..999f9149b1818982571747cdbfa8ccbaa1c742cf 100644
--- a/lib/types/platform/gitlab/index.ts
+++ b/lib/types/platform/gitlab/index.ts
@@ -1,3 +1,4 @@
+import { PLATFORM_TYPE_GITLAB } from '../../../constants/platforms';
 import { GitTreeNode } from '../../git';
 
 export type GitLabBranch = {
@@ -12,3 +13,9 @@ export type GitlabTreeNode = {
   id: string;
   name: string;
 } & GitTreeNode;
+
+export const GITLAB_API_USING_HOST_TYPES = [
+  PLATFORM_TYPE_GITLAB,
+  'gitlab-releases',
+  'gitlab-tags',
+];
diff --git a/lib/util/http/__snapshots__/gitlab.spec.ts.snap b/lib/util/http/__snapshots__/gitlab.spec.ts.snap
index 8b1f605d78788afd2933ef42d1f9e579b68e4f80..56e7c378c343d3e3a0a8055de56b10ecc0ad9683 100644
--- a/lib/util/http/__snapshots__/gitlab.spec.ts.snap
+++ b/lib/util/http/__snapshots__/gitlab.spec.ts.snap
@@ -107,3 +107,18 @@ Array [
   },
 ]
 `;
+
+exports[`util/http/gitlab supports different datasources 1`] = `
+Array [
+  Object {
+    "headers": Object {
+      "accept-encoding": "gzip, deflate, br",
+      "authorization": "Bearer def",
+      "host": "gitlab.com",
+      "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
+    },
+    "method": "GET",
+    "url": "https://gitlab.com/api/v4/some-url",
+  },
+]
+`;
diff --git a/lib/util/http/auth.ts b/lib/util/http/auth.ts
index 0c14ca7092f71685849db9c42d2d2650337a9688..b3a5383dfc5c421276818b1c8a1a1ac3f9a57191 100644
--- a/lib/util/http/auth.ts
+++ b/lib/util/http/auth.ts
@@ -1,10 +1,8 @@
 import is from '@sindresorhus/is';
 import { NormalizedOptions } from 'got';
-import {
-  PLATFORM_TYPE_GITEA,
-  PLATFORM_TYPE_GITLAB,
-} from '../../constants/platforms';
+import { PLATFORM_TYPE_GITEA } from '../../constants/platforms';
 import { GITHUB_API_USING_HOST_TYPES } from '../../types';
+import { GITLAB_API_USING_HOST_TYPES } from '../../types/platform/gitlab';
 import { GotOptions } from './types';
 
 export function applyAuthorization(inOptions: GotOptions): GotOptions {
@@ -29,7 +27,7 @@ export function applyAuthorization(inOptions: GotOptions): GotOptions {
           );
         }
       }
-    } else if (options.hostType === PLATFORM_TYPE_GITLAB) {
+    } else if (GITLAB_API_USING_HOST_TYPES.includes(options.hostType)) {
       // GitLab versions earlier than 12.2 only support authentication with
       // a personal access token, which is 20 characters long.
       if (options.token.length === 20) {
diff --git a/lib/util/http/gitlab.spec.ts b/lib/util/http/gitlab.spec.ts
index acd7c6d9892eeeeeb5d2625de1f9f69fc8240ce2..13f6a3962f6c3511c91dcafd9a566e805deef336 100644
--- a/lib/util/http/gitlab.spec.ts
+++ b/lib/util/http/gitlab.spec.ts
@@ -1,14 +1,10 @@
 import * as httpMock from '../../../test/http-mock';
 import { EXTERNAL_HOST_ERROR } from '../../constants/error-messages';
 import { PLATFORM_TYPE_GITLAB } from '../../constants/platforms';
+import { GitlabReleasesDatasource } from '../../datasource/gitlab-releases';
 import * as hostRules from '../host-rules';
 import { GitlabHttp, setBaseUrl } from './gitlab';
 
-hostRules.add({
-  hostType: PLATFORM_TYPE_GITLAB,
-  token: 'abc123',
-});
-
 const gitlabApiHost = 'https://gitlab.com';
 const selfHostedUrl = 'http://mycompany.com/gitlab';
 
@@ -19,10 +15,17 @@ describe('util/http/gitlab', () => {
     gitlabApi = new GitlabHttp();
     setBaseUrl(`${gitlabApiHost}/api/v4/`);
     delete process.env.GITLAB_IGNORE_REPO_URL;
+
+    hostRules.add({
+      hostType: PLATFORM_TYPE_GITLAB,
+      token: 'abc123',
+    });
   });
 
   afterEach(() => {
     jest.resetAllMocks();
+
+    hostRules.clear();
   });
 
   it('paginates', async () => {
@@ -68,6 +71,26 @@ describe('util/http/gitlab', () => {
     expect(trace).toHaveLength(3);
     expect(trace).toMatchSnapshot();
   });
+
+  it('supports different datasources', async () => {
+    const gitlabApiDatasource = new GitlabHttp(GitlabReleasesDatasource.id);
+    hostRules.add({ hostType: PLATFORM_TYPE_GITLAB, token: 'abc' });
+    hostRules.add({
+      hostType: GitlabReleasesDatasource.id,
+      token: 'def',
+    });
+    httpMock
+      .scope(gitlabApiHost, { reqheaders: { authorization: 'Bearer def' } })
+      .get('/api/v4/some-url')
+      .reply(200);
+    const response = await gitlabApiDatasource.get('/some-url');
+    expect(response).not.toBeNull();
+
+    const trace = httpMock.getTrace();
+    expect(trace).toHaveLength(1);
+    expect(trace).toMatchSnapshot();
+  });
+
   it('attempts to paginate', async () => {
     httpMock.scope(gitlabApiHost).get('/api/v4/some-url').reply(200, ['a'], {
       link: '<https://gitlab.com/api/v4/some-url&page=3>; rel="last"',
diff --git a/lib/util/http/gitlab.ts b/lib/util/http/gitlab.ts
index a9ca70f00c883d6b674211cf2a87c70ef4aeb16a..18eacdd2240f81e1f1132af1225866ea6cac87e7 100644
--- a/lib/util/http/gitlab.ts
+++ b/lib/util/http/gitlab.ts
@@ -20,8 +20,11 @@ export interface GitlabHttpOptions extends InternalHttpOptions {
 }
 
 export class GitlabHttp extends Http<GitlabHttpOptions, GitlabHttpOptions> {
-  constructor(options?: GitlabHttpOptions) {
-    super(PLATFORM_TYPE_GITLAB, options);
+  constructor(
+    type: string = PLATFORM_TYPE_GITLAB,
+    options?: GitlabHttpOptions
+  ) {
+    super(type, options);
   }
 
   protected override async request<T>(