diff --git a/lib/datasource/api.ts b/lib/datasource/api.ts
index 599a700acb5b7837b6961f073de5b6fc9f4b6ccf..430805cbdd54346fdf0f072c5d75fcc50dd81940 100644
--- a/lib/datasource/api.ts
+++ b/lib/datasource/api.ts
@@ -28,7 +28,7 @@ import { NodeDatasource } from './node';
 import * as npm from './npm';
 import * as nuget from './nuget';
 import { OrbDatasource } from './orb';
-import * as packagist from './packagist';
+import { PackagistDatasource } from './packagist';
 import { PodDatasource } from './pod';
 import { PypiDatasource } from './pypi';
 import * as repology from './repology';
@@ -73,7 +73,7 @@ api.set(NodeDatasource.id, new NodeDatasource());
 api.set('npm', npm);
 api.set('nuget', nuget);
 api.set(OrbDatasource.id, new OrbDatasource());
-api.set('packagist', packagist);
+api.set(PackagistDatasource.id, new PackagistDatasource());
 api.set(PodDatasource.id, new PodDatasource());
 api.set(PypiDatasource.id, new PypiDatasource());
 api.set('repology', repology);
diff --git a/lib/datasource/index.spec.ts b/lib/datasource/index.spec.ts
index 1a135fef2b6781f8cadf3e43bbdce4ea2197ef38..165247f86fdbb27a7b31a0e31f38406413ce5199 100644
--- a/lib/datasource/index.spec.ts
+++ b/lib/datasource/index.spec.ts
@@ -1,4 +1,5 @@
 import fs from 'fs-extra';
+import { mockFn } from 'jest-mock-extended';
 import * as httpMock from '../../test/http-mock';
 import { logger, mocked } from '../../test/util';
 import {
@@ -13,19 +14,32 @@ import { GalaxyDatasource } from './galaxy';
 import * as datasourceGithubTags from './github-tags';
 import * as datasourceMaven from './maven';
 import * as datasourceNpm from './npm';
-import * as datasourcePackagist from './packagist';
-import type { DatasourceApi } from './types';
+import { PackagistDatasource } from './packagist';
+import type { DatasourceApi, GetReleasesConfig } from './types';
 import * as datasource from '.';
 
 jest.mock('./docker');
 jest.mock('./maven');
 jest.mock('./npm');
-jest.mock('./packagist');
+
+const packagistDatasourceGetReleasesMock =
+  mockFn<DatasourceApi['getReleases']>();
+
+jest.mock('./packagist', () => {
+  return {
+    __esModule: true,
+    PackagistDatasource: class extends jest.requireActual<
+      typeof import('./packagist')
+    >('./packagist').PackagistDatasource {
+      override getReleases = (_: GetReleasesConfig) =>
+        packagistDatasourceGetReleasesMock(_);
+    },
+  };
+});
 
 const dockerDatasource = mocked(datasourceDocker);
 const mavenDatasource = mocked(datasourceMaven);
 const npmDatasource = mocked(datasourceNpm);
-const packagistDatasource = mocked(datasourcePackagist);
 
 describe('datasource/index', () => {
   beforeEach(() => {
@@ -179,51 +193,52 @@ describe('datasource/index', () => {
     expect(res).toBeNull();
   });
   it('hunts registries and returns success', async () => {
-    packagistDatasource.getReleases.mockResolvedValueOnce(null);
-    packagistDatasource.getReleases.mockResolvedValueOnce({
-      releases: [{ version: '1.0.0' }],
-    });
+    packagistDatasourceGetReleasesMock
+      .mockResolvedValueOnce(null)
+      .mockResolvedValueOnce({
+        releases: [{ version: '1.0.0' }],
+      });
     const res = await datasource.getPkgReleases({
-      datasource: datasourcePackagist.id,
+      datasource: PackagistDatasource.id,
       depName: 'something',
       registryUrls: ['https://reg1.com', 'https://reg2.io'],
     });
     expect(res).not.toBeNull();
   });
   it('returns null for HOST_DISABLED', async () => {
-    packagistDatasource.getReleases.mockImplementationOnce(() => {
+    packagistDatasourceGetReleasesMock.mockImplementationOnce(() => {
       throw new ExternalHostError(new Error(HOST_DISABLED));
     });
     expect(
       await datasource.getPkgReleases({
-        datasource: datasourcePackagist.id,
+        datasource: PackagistDatasource.id,
         depName: 'something',
         registryUrls: ['https://reg1.com'],
       })
     ).toBeNull();
   });
   it('hunts registries and aborts on ExternalHostError', async () => {
-    packagistDatasource.getReleases.mockImplementationOnce(() => {
-      throw new ExternalHostError(new Error());
-    });
+    packagistDatasourceGetReleasesMock.mockRejectedValue(
+      new ExternalHostError(new Error())
+    );
     await expect(
       datasource.getPkgReleases({
-        datasource: datasourcePackagist.id,
+        datasource: PackagistDatasource.id,
         depName: 'something',
         registryUrls: ['https://reg1.com', 'https://reg2.io'],
       })
     ).rejects.toThrow(EXTERNAL_HOST_ERROR);
   });
   it('hunts registries and returns null', async () => {
-    packagistDatasource.getReleases.mockImplementationOnce(() => {
+    packagistDatasourceGetReleasesMock.mockImplementationOnce(() => {
       throw new Error('a');
     });
-    packagistDatasource.getReleases.mockImplementationOnce(() => {
+    packagistDatasourceGetReleasesMock.mockImplementationOnce(() => {
       throw new Error('b');
     });
     expect(
       await datasource.getPkgReleases({
-        datasource: datasourcePackagist.id,
+        datasource: PackagistDatasource.id,
         depName: 'something',
         registryUrls: ['https://reg1.com', 'https://reg2.io'],
       })
diff --git a/lib/datasource/packagist/index.spec.ts b/lib/datasource/packagist/index.spec.ts
index edf010c4c9f06b3a0bfceb054331af6433fec57b..359d43d9b658de42404002d90ec1e809a28625f4 100644
--- a/lib/datasource/packagist/index.spec.ts
+++ b/lib/datasource/packagist/index.spec.ts
@@ -4,7 +4,7 @@ import { loadJsonFixture } from '../../../test/util';
 import * as _hostRules from '../../util/host-rules';
 import * as composerVersioning from '../../versioning/composer';
 import { id as versioning } from '../../versioning/loose';
-import { id as datasource } from '.';
+import { PackagistDatasource } from '.';
 
 jest.mock('../../util/host-rules');
 
@@ -15,6 +15,7 @@ const beytJson: any = loadJsonFixture('1beyt.json');
 const mailchimpJson: any = loadJsonFixture('mailchimp-api.json');
 
 const baseUrl = 'https://packagist.org';
+const datasource = PackagistDatasource.id;
 
 describe('datasource/packagist/index', () => {
   describe('getReleases', () => {
diff --git a/lib/datasource/packagist/index.ts b/lib/datasource/packagist/index.ts
index 605662dcc3efa4c35b881d41f07d3a83bb12429f..6e820b70bb99af68f7ce4a96b9b83094e25bf085 100644
--- a/lib/datasource/packagist/index.ts
+++ b/lib/datasource/packagist/index.ts
@@ -2,13 +2,14 @@ import URL from 'url';
 import pAll from 'p-all';
 import { logger } from '../../logger';
 import { ExternalHostError } from '../../types/errors/external-host-error';
-import * as memCache from '../../util/cache/memory';
 import * as packageCache from '../../util/cache/package';
+import { cache } from '../../util/cache/package/decorator';
 import * as hostRules from '../../util/host-rules';
-import { Http, HttpOptions } from '../../util/http';
+import type { HttpOptions } from '../../util/http';
 import { regEx } from '../../util/regex';
 import { ensureTrailingSlash } from '../../util/url';
 import * as composerVersioning from '../../versioning/composer';
+import { Datasource } from '../datasource';
 import type { GetReleasesConfig, ReleaseResult } from '../types';
 import type {
   AllPackages,
@@ -18,263 +19,266 @@ import type {
   RegistryMeta,
 } from './types';
 
-export const id = 'packagist';
-export const customRegistrySupport = true;
-export const defaultRegistryUrls = ['https://packagist.org'];
-export const defaultVersioning = composerVersioning.id;
-export const registryStrategy = 'hunt';
+export class PackagistDatasource extends Datasource {
+  static readonly id = 'packagist';
 
-const http = new Http(id);
+  constructor() {
+    super(PackagistDatasource.id);
+  }
+
+  override readonly defaultRegistryUrls = ['https://packagist.org'];
+
+  override readonly defaultVersioning = composerVersioning.id;
 
-// We calculate auth at this datasource layer so that we can know whether it's safe to cache or not
-function getHostOpts(url: string): HttpOptions {
-  let opts: HttpOptions = {};
-  const { username, password } = hostRules.find({
-    hostType: id,
-    url,
-  });
-  if (username && password) {
-    opts = { ...opts, username, password };
+  override readonly registryStrategy = 'hunt';
+
+  public override getReleases({
+    lookupName,
+    registryUrl,
+  }: GetReleasesConfig): Promise<ReleaseResult> {
+    logger.trace(`getReleases(${lookupName})`);
+    return this.packageLookup(registryUrl, lookupName);
   }
-  return opts;
-}
 
-async function getRegistryMeta(regUrl: string): Promise<RegistryMeta | null> {
-  const url = URL.resolve(ensureTrailingSlash(regUrl), 'packages.json');
-  const opts = getHostOpts(url);
-  const res = (await http.getJson<PackageMeta>(url, opts)).body;
-  const meta: RegistryMeta = {
-    providerPackages: {},
-  };
-  meta.packages = res.packages;
-  if (res.includes) {
-    meta.includesFiles = [];
-    for (const [name, val] of Object.entries(res.includes)) {
-      const file = {
-        key: name.replace(val.sha256, '%hash%'),
-        sha256: val.sha256,
-      };
-      meta.includesFiles.push(file);
+  // We calculate auth at this datasource layer so that we can know whether it's safe to cache or not
+  private static getHostOpts(url: string): HttpOptions {
+    let opts: HttpOptions = {};
+    const { username, password } = hostRules.find({
+      hostType: PackagistDatasource.id,
+      url,
+    });
+    if (username && password) {
+      opts = { ...opts, username, password };
     }
+    return opts;
   }
-  if (res['providers-url']) {
-    meta.providersUrl = res['providers-url'];
-  }
-  if (res['providers-lazy-url']) {
-    meta.providersLazyUrl = res['providers-lazy-url'];
-  }
-  if (res['provider-includes']) {
-    meta.files = [];
-    for (const [key, val] of Object.entries(res['provider-includes'])) {
-      const file = {
-        key,
-        sha256: val.sha256,
-      };
-      meta.files.push(file);
+
+  private async getRegistryMeta(regUrl: string): Promise<RegistryMeta | null> {
+    const url = URL.resolve(ensureTrailingSlash(regUrl), 'packages.json');
+    const opts = PackagistDatasource.getHostOpts(url);
+    const res = (await this.http.getJson<PackageMeta>(url, opts)).body;
+    const meta: RegistryMeta = {
+      providerPackages: {},
+    };
+    meta.packages = res.packages;
+    if (res.includes) {
+      meta.includesFiles = [];
+      for (const [name, val] of Object.entries(res.includes)) {
+        const file = {
+          key: name.replace(val.sha256, '%hash%'),
+          sha256: val.sha256,
+        };
+        meta.includesFiles.push(file);
+      }
     }
-  }
-  if (res.providers) {
-    for (const [key, val] of Object.entries(res.providers)) {
-      meta.providerPackages[key] = val.sha256;
+    if (res['providers-url']) {
+      meta.providersUrl = res['providers-url'];
     }
-  }
-  return meta;
-}
-
-async function getPackagistFile(
-  regUrl: string,
-  file: RegistryFile
-): Promise<PackagistFile> {
-  const { key, sha256 } = file;
-  const fileName = key.replace('%hash%', sha256);
-  const opts = getHostOpts(regUrl);
-  if (opts.password || opts.headers?.authorization) {
-    return (await http.getJson<PackagistFile>(regUrl + '/' + fileName, opts))
-      .body;
-  }
-  const cacheNamespace = 'datasource-packagist-files';
-  const cacheKey = regUrl + key;
-  // Check the persistent cache for public registries
-  const cachedResult = await packageCache.get(cacheNamespace, cacheKey);
-  // istanbul ignore if
-  if (cachedResult && cachedResult.sha256 === sha256) {
-    return cachedResult.res as Promise<PackagistFile>;
-  }
-  const res = (await http.getJson<PackagistFile>(regUrl + '/' + fileName, opts))
-    .body;
-  const cacheMinutes = 1440; // 1 day
-  await packageCache.set(
-    cacheNamespace,
-    cacheKey,
-    { res, sha256 },
-    cacheMinutes
-  );
-  return res;
-}
-
-function extractDepReleases(versions: RegistryFile): ReleaseResult {
-  const dep: ReleaseResult = { releases: null };
-  // istanbul ignore if
-  if (!versions) {
-    dep.releases = [];
-    return dep;
-  }
-  dep.releases = Object.keys(versions).map((version) => {
-    const release = versions[version];
-    dep.homepage = release.homepage || dep.homepage;
-    if (release.source?.url) {
-      dep.sourceUrl = release.source.url;
+    if (res['providers-lazy-url']) {
+      meta.providersLazyUrl = res['providers-lazy-url'];
     }
-    return {
-      version: version.replace(regEx(/^v/), ''),
-      gitRef: version,
-      releaseTimestamp: release.time,
-    };
-  });
-  return dep;
-}
-
-async function getAllPackages(regUrl: string): Promise<AllPackages | null> {
-  const registryMeta = await getRegistryMeta(regUrl);
-  const {
-    packages,
-    providersUrl,
-    providersLazyUrl,
-    files,
-    includesFiles,
-    providerPackages,
-  } = registryMeta;
-  if (files) {
-    const queue = files.map(
-      (file) => (): Promise<PackagistFile> => getPackagistFile(regUrl, file)
-    );
-    const resolvedFiles = await pAll(queue, { concurrency: 5 });
-    for (const res of resolvedFiles) {
-      for (const [name, val] of Object.entries(res.providers)) {
-        providerPackages[name] = val.sha256;
+    if (res['provider-includes']) {
+      meta.files = [];
+      for (const [key, val] of Object.entries(res['provider-includes'])) {
+        const file = {
+          key,
+          sha256: val.sha256,
+        };
+        meta.files.push(file);
       }
     }
-  }
-  const includesPackages: Record<string, ReleaseResult> = {};
-  if (includesFiles) {
-    for (const file of includesFiles) {
-      const res = await getPackagistFile(regUrl, file);
-      if (res.packages) {
-        for (const [key, val] of Object.entries(res.packages)) {
-          const dep = extractDepReleases(val);
-          includesPackages[key] = dep;
-        }
+    if (res.providers) {
+      for (const [key, val] of Object.entries(res.providers)) {
+        meta.providerPackages[key] = val.sha256;
       }
     }
+    return meta;
   }
-  const allPackages: AllPackages = {
-    packages,
-    providersUrl,
-    providersLazyUrl,
-    providerPackages,
-    includesPackages,
-  };
-  return allPackages;
-}
 
-function getAllCachedPackages(regUrl: string): Promise<AllPackages | null> {
-  const cacheKey = `packagist-${regUrl}`;
-  const cachedResult = memCache.get<Promise<AllPackages | null>>(cacheKey);
-  // istanbul ignore if
-  if (cachedResult !== undefined) {
-    return cachedResult;
+  private async getPackagistFile(
+    regUrl: string,
+    file: RegistryFile
+  ): Promise<PackagistFile> {
+    const { key, sha256 } = file;
+    const fileName = key.replace('%hash%', sha256);
+    const opts = PackagistDatasource.getHostOpts(regUrl);
+    if (opts.password || opts.headers?.authorization) {
+      return (
+        await this.http.getJson<PackagistFile>(regUrl + '/' + fileName, opts)
+      ).body;
+    }
+    const cacheNamespace = 'datasource-packagist-files';
+    const cacheKey = regUrl + key;
+    // Check the persistent cache for public registries
+    const cachedResult = await packageCache.get(cacheNamespace, cacheKey);
+    // istanbul ignore if
+    if (cachedResult && cachedResult.sha256 === sha256) {
+      return cachedResult.res as Promise<PackagistFile>;
+    }
+    const res = (
+      await this.http.getJson<PackagistFile>(regUrl + '/' + fileName, opts)
+    ).body;
+    const cacheMinutes = 1440; // 1 day
+    await packageCache.set(
+      cacheNamespace,
+      cacheKey,
+      { res, sha256 },
+      cacheMinutes
+    );
+    return res;
   }
-  const promisedRes = getAllPackages(regUrl);
-  memCache.set(cacheKey, promisedRes);
-  return promisedRes;
-}
 
-async function packagistOrgLookup(name: string): Promise<ReleaseResult> {
-  const cacheNamespace = 'datasource-packagist-org';
-  const cachedResult = await packageCache.get<ReleaseResult>(
-    cacheNamespace,
-    name
-  );
-  // istanbul ignore if
-  if (cachedResult) {
-    return cachedResult;
-  }
-  let dep: ReleaseResult = null;
-  const regUrl = 'https://packagist.org';
-  const pkgUrl = URL.resolve(regUrl, `/p/${name}.json`);
-  // TODO: fix types (#9610)
-  const res = (await http.getJson<any>(pkgUrl)).body.packages[name];
-  if (res) {
-    dep = extractDepReleases(res);
-    logger.trace({ dep }, 'dep');
+  private static extractDepReleases(versions: RegistryFile): ReleaseResult {
+    const dep: ReleaseResult = { releases: null };
+    // istanbul ignore if
+    if (!versions) {
+      dep.releases = [];
+      return dep;
+    }
+    dep.releases = Object.keys(versions).map((version) => {
+      const release = versions[version];
+      dep.homepage = release.homepage || dep.homepage;
+      if (release.source?.url) {
+        dep.sourceUrl = release.source.url;
+      }
+      return {
+        version: version.replace(regEx(/^v/), ''),
+        gitRef: version,
+        releaseTimestamp: release.time,
+      };
+    });
+    return dep;
   }
-  const cacheMinutes = 10;
-  await packageCache.set(cacheNamespace, name, dep, cacheMinutes);
-  return dep;
-}
 
-async function packageLookup(
-  regUrl: string,
-  name: string
-): Promise<ReleaseResult | null> {
-  try {
-    if (regUrl === 'https://packagist.org') {
-      const packagistResult = await packagistOrgLookup(name);
-      return packagistResult;
-    }
-    const allPackages = await getAllCachedPackages(regUrl);
+  @cache({
+    namespace: `datasource-${PackagistDatasource.id}`,
+    key: (regUrl: string) => regUrl,
+  })
+  async getAllPackages(regUrl: string): Promise<AllPackages | null> {
+    const registryMeta = await this.getRegistryMeta(regUrl);
     const {
       packages,
       providersUrl,
       providersLazyUrl,
+      files,
+      includesFiles,
       providerPackages,
-      includesPackages,
-    } = allPackages;
-    if (packages?.[name]) {
-      const dep = extractDepReleases(packages[name]);
-      return dep;
+    } = registryMeta;
+    if (files) {
+      const queue = files.map(
+        (file) => (): Promise<PackagistFile> =>
+          this.getPackagistFile(regUrl, file)
+      );
+      const resolvedFiles = await pAll(queue, { concurrency: 5 });
+      for (const res of resolvedFiles) {
+        for (const [name, val] of Object.entries(res.providers)) {
+          providerPackages[name] = val.sha256;
+        }
+      }
     }
-    if (includesPackages?.[name]) {
-      return includesPackages[name];
+    const includesPackages: Record<string, ReleaseResult> = {};
+    if (includesFiles) {
+      for (const file of includesFiles) {
+        const res = await this.getPackagistFile(regUrl, file);
+        if (res.packages) {
+          for (const [key, val] of Object.entries(res.packages)) {
+            const dep = PackagistDatasource.extractDepReleases(val);
+            includesPackages[key] = dep;
+          }
+        }
+      }
     }
-    let pkgUrl;
-    if (name in providerPackages) {
-      pkgUrl = URL.resolve(
-        regUrl,
-        providersUrl
-          .replace('%package%', name)
-          .replace('%hash%', providerPackages[name])
-      );
-    } else if (providersLazyUrl) {
-      pkgUrl = URL.resolve(regUrl, providersLazyUrl.replace('%package%', name));
-    } else {
-      return null;
+    const allPackages: AllPackages = {
+      packages,
+      providersUrl,
+      providersLazyUrl,
+      providerPackages,
+      includesPackages,
+    };
+    return allPackages;
+  }
+
+  async packagistOrgLookup(name: string): Promise<ReleaseResult> {
+    const cacheNamespace = 'datasource-packagist-org';
+    const cachedResult = await packageCache.get<ReleaseResult>(
+      cacheNamespace,
+      name
+    );
+    // istanbul ignore if
+    if (cachedResult) {
+      return cachedResult;
     }
-    const opts = getHostOpts(regUrl);
+    let dep: ReleaseResult = null;
+    const regUrl = 'https://packagist.org';
+    const pkgUrl = URL.resolve(regUrl, `/p/${name}.json`);
     // TODO: fix types (#9610)
-    const versions = (await http.getJson<any>(pkgUrl, opts)).body.packages[
-      name
-    ];
-    const dep = extractDepReleases(versions);
-    logger.trace({ dep }, 'dep');
+    const res = (await this.http.getJson<any>(pkgUrl)).body.packages[name];
+    if (res) {
+      dep = PackagistDatasource.extractDepReleases(res);
+      logger.trace({ dep }, 'dep');
+    }
+    const cacheMinutes = 10;
+    await packageCache.set(cacheNamespace, name, dep, cacheMinutes);
     return dep;
-  } catch (err) /* istanbul ignore next */ {
-    if (err.host === 'packagist.org') {
-      if (err.code === 'ECONNRESET' || err.code === 'ETIMEDOUT') {
-        throw new ExternalHostError(err);
+  }
+
+  private async packageLookup(
+    regUrl: string,
+    name: string
+  ): Promise<ReleaseResult | null> {
+    try {
+      if (regUrl === 'https://packagist.org') {
+        const packagistResult = await this.packagistOrgLookup(name);
+        return packagistResult;
       }
-      if (err.statusCode && err.statusCode >= 500 && err.statusCode < 600) {
-        throw new ExternalHostError(err);
+      const allPackages = await this.getAllPackages(regUrl);
+      const {
+        packages,
+        providersUrl,
+        providersLazyUrl,
+        providerPackages,
+        includesPackages,
+      } = allPackages;
+      if (packages?.[name]) {
+        const dep = PackagistDatasource.extractDepReleases(packages[name]);
+        return dep;
       }
+      if (includesPackages?.[name]) {
+        return includesPackages[name];
+      }
+      let pkgUrl;
+      if (name in providerPackages) {
+        pkgUrl = URL.resolve(
+          regUrl,
+          providersUrl
+            .replace('%package%', name)
+            .replace('%hash%', providerPackages[name])
+        );
+      } else if (providersLazyUrl) {
+        pkgUrl = URL.resolve(
+          regUrl,
+          providersLazyUrl.replace('%package%', name)
+        );
+      } else {
+        return null;
+      }
+      const opts = PackagistDatasource.getHostOpts(regUrl);
+      // TODO: fix types (#9610)
+      const versions = (await this.http.getJson<any>(pkgUrl, opts)).body
+        .packages[name];
+      const dep = PackagistDatasource.extractDepReleases(versions);
+      logger.trace({ dep }, 'dep');
+      return dep;
+    } catch (err) /* istanbul ignore next */ {
+      if (err.host === 'packagist.org') {
+        if (err.code === 'ECONNRESET' || err.code === 'ETIMEDOUT') {
+          throw new ExternalHostError(err);
+        }
+        if (err.statusCode && err.statusCode >= 500 && err.statusCode < 600) {
+          throw new ExternalHostError(err);
+        }
+      }
+      throw err;
     }
-    throw err;
   }
 }
-
-export function getReleases({
-  lookupName,
-  registryUrl,
-}: GetReleasesConfig): Promise<ReleaseResult> {
-  logger.trace(`getReleases(${lookupName})`);
-  return packageLookup(registryUrl, lookupName);
-}
diff --git a/lib/manager/composer/artifacts.spec.ts b/lib/manager/composer/artifacts.spec.ts
index 15b24d72c460aed934d924fd1a6ef8e17b475b9d..8e6be19076b1b200b5a96cd25dda7cdbbed4e7e9 100644
--- a/lib/manager/composer/artifacts.spec.ts
+++ b/lib/manager/composer/artifacts.spec.ts
@@ -5,7 +5,7 @@ import { GlobalConfig } from '../../config/global';
 import type { RepoGlobalConfig } from '../../config/types';
 import { PlatformId } from '../../constants';
 import * as _datasource from '../../datasource';
-import * as datasourcePackagist from '../../datasource/packagist';
+import { PackagistDatasource } from '../../datasource/packagist';
 import * as docker from '../../util/exec/docker';
 import type { StatusResult } from '../../util/git/types';
 import * as hostRules from '../../util/host-rules';
@@ -109,24 +109,24 @@ describe('manager/composer/artifacts', () => {
       token: 'gitlab-token',
     });
     hostRules.add({
-      hostType: datasourcePackagist.id,
+      hostType: PackagistDatasource.id,
       matchHost: 'packagist.renovatebot.com',
       username: 'some-username',
       password: 'some-password',
     });
     hostRules.add({
-      hostType: datasourcePackagist.id,
+      hostType: PackagistDatasource.id,
       matchHost: 'https://artifactory.yyyyyyy.com/artifactory/api/composer/',
       username: 'some-other-username',
       password: 'some-other-password',
     });
     hostRules.add({
-      hostType: datasourcePackagist.id,
+      hostType: PackagistDatasource.id,
       username: 'some-other-username',
       password: 'some-other-password',
     });
     hostRules.add({
-      hostType: datasourcePackagist.id,
+      hostType: PackagistDatasource.id,
       matchHost: 'https://packages-bearer.example.com/',
       token: 'abcdef0123456789',
     });
diff --git a/lib/manager/composer/artifacts.ts b/lib/manager/composer/artifacts.ts
index 1ab1152a5090dbaddb100008bddf880968a68ba8..5ad9b98c6541c487ad764e6cbbcf53626911e84f 100644
--- a/lib/manager/composer/artifacts.ts
+++ b/lib/manager/composer/artifacts.ts
@@ -5,7 +5,7 @@ import {
   SYSTEM_INSUFFICIENT_DISK_SPACE,
   TEMPORARY_ERROR,
 } from '../../constants/error-messages';
-import * as datasourcePackagist from '../../datasource/packagist';
+import { PackagistDatasource } from '../../datasource/packagist';
 import { logger } from '../../logger';
 import { exec } from '../../util/exec';
 import type { ExecOptions, ToolConstraint } from '../../util/exec/types';
@@ -59,7 +59,7 @@ function getAuthJson(): string | null {
     });
 
   hostRules
-    .findAll({ hostType: datasourcePackagist.id })
+    .findAll({ hostType: PackagistDatasource.id })
     ?.forEach((hostRule) => {
       const { resolvedHost, username, password, token } = hostRule;
       if (resolvedHost && username && password) {
diff --git a/lib/manager/composer/extract.ts b/lib/manager/composer/extract.ts
index 068be967c805c413f0a7a2777db43519205f0b91..60efb5631d50effe2b44968e59c2e8d62e34d183 100644
--- a/lib/manager/composer/extract.ts
+++ b/lib/manager/composer/extract.ts
@@ -1,6 +1,6 @@
 import is from '@sindresorhus/is';
 import { GitTagsDatasource } from '../../datasource/git-tags';
-import * as datasourcePackagist from '../../datasource/packagist';
+import { PackagistDatasource } from '../../datasource/packagist';
 import { logger } from '../../logger';
 import { readLocalFile } from '../../util/fs';
 import { regEx } from '../../util/regex';
@@ -124,7 +124,7 @@ export async function extractPackageFile(
         )) {
           const currentValue = version.trim();
           // Default datasource and lookupName
-          let datasource = datasourcePackagist.id;
+          let datasource = PackagistDatasource.id;
           let lookupName = depName;
 
           // Check custom repositories by type
diff --git a/lib/manager/composer/index.ts b/lib/manager/composer/index.ts
index 5295d55db7ea26ddfd8e299c0b441856eab31fc9..e269db86e505dc94da21c28ba58c3815da3e9208 100644
--- a/lib/manager/composer/index.ts
+++ b/lib/manager/composer/index.ts
@@ -1,6 +1,6 @@
 import { ProgrammingLanguage } from '../../constants';
 import { GitTagsDatasource } from '../../datasource/git-tags';
-import * as datasourcePackagist from '../../datasource/packagist';
+import { PackagistDatasource } from '../../datasource/packagist';
 import { updateArtifacts } from './artifacts';
 import { extractPackageFile } from './extract';
 import { getRangeStrategy } from './range';
@@ -25,5 +25,5 @@ export const defaultConfig = {
 
 export const supportedDatasources = [
   GitTagsDatasource.id,
-  datasourcePackagist.id,
+  PackagistDatasource.id,
 ];
diff --git a/lib/workers/repository/process/lookup/index.spec.ts b/lib/workers/repository/process/lookup/index.spec.ts
index 4b174f05515eb2cae61eb920560af64185dbb43c..1afcb616b05ee3a666804b328cfb455df17385ec 100644
--- a/lib/workers/repository/process/lookup/index.spec.ts
+++ b/lib/workers/repository/process/lookup/index.spec.ts
@@ -13,7 +13,7 @@ import { GitDatasource } from '../../../../datasource/git-refs/base';
 import * as datasourceGithubReleases from '../../../../datasource/github-releases';
 import { id as datasourceGithubTagsId } from '../../../../datasource/github-tags';
 import { id as datasourceNpmId } from '../../../../datasource/npm';
-import { id as datasourcePackagistId } from '../../../../datasource/packagist';
+import { PackagistDatasource } from '../../../../datasource/packagist';
 import { PypiDatasource } from '../../../../datasource/pypi';
 import { id as dockerVersioningId } from '../../../../versioning/docker';
 import { id as gitVersioningId } from '../../../../versioning/git';
@@ -1220,7 +1220,7 @@ describe('workers/repository/process/lookup/index', () => {
     });
     it('handles packagist', async () => {
       config.depName = 'foo/bar';
-      config.datasource = datasourcePackagistId;
+      config.datasource = PackagistDatasource.id;
       config.packageFile = 'composer.json';
       config.currentValue = '1.0.0';
       config.registryUrls = ['https://packagist.org'];