diff --git a/lib/modules/manager/composer/__fixtures__/composer6.json b/lib/modules/manager/composer/__fixtures__/composer6.json
new file mode 100644
index 0000000000000000000000000000000000000000..d0376da5da6a9a0fd96a1b52f15591274f6c0734
--- /dev/null
+++ b/lib/modules/manager/composer/__fixtures__/composer6.json
@@ -0,0 +1,31 @@
+{
+  "name": "acme/git-sources",
+  "description": "Fetch Packages via bitbucket-tags",
+  "repositories": [
+    {
+      "name": "awesome/bitbucket-repo1",
+      "type": "vcs",
+      "url": "https://bitbucket.org/awesome/bitbucket-repo1.git"
+    },
+    {
+      "name": "awesome/bitbucket-repo2",
+      "type": "vcs",
+      "url": "git@bitbucket.org/awesome/bitbucket-repo2.git"
+    },
+    {
+      "name": "awesome/bitbucket-repo3",
+      "type": "vcs",
+      "url": "git@bitbucket.org/awesome/bitbucket-repo3"
+    }
+  ],
+  "require": {
+    "awesome/bitbucket-repo1": "dev-trunk",
+    "awesome/bitbucket-repo2": "dev-trunk",
+    "awesome/bitbucket-repo3": "dev-trunk"
+  },
+  "autoload": {
+    "psr-0": {
+      "Acme": "src/"
+    }
+  }
+}
diff --git a/lib/modules/manager/composer/extract.spec.ts b/lib/modules/manager/composer/extract.spec.ts
index bb32a14e4d77664be485dca0049fe6734f1293da..9cccbb73dea575f4c5c9d48564e1fbadb78b2936 100644
--- a/lib/modules/manager/composer/extract.spec.ts
+++ b/lib/modules/manager/composer/extract.spec.ts
@@ -10,6 +10,7 @@ const requirements2 = Fixtures.get('composer2.json');
 const requirements3 = Fixtures.get('composer3.json');
 const requirements4 = Fixtures.get('composer4.json');
 const requirements5 = Fixtures.get('composer5.json');
+const requirements6 = Fixtures.get('composer6.json');
 const requirements5Lock = Fixtures.get('composer5.lock');
 
 describe('modules/manager/composer/extract', () => {
@@ -215,6 +216,35 @@ describe('modules/manager/composer/extract', () => {
       });
     });
 
+    it('extracts bitbucket repositories and registryUrls', async () => {
+      const res = await extractPackageFile(requirements6, packageFile);
+      expect(res).toEqual({
+        deps: [
+          {
+            currentValue: 'dev-trunk',
+            datasource: 'bitbucket-tags',
+            depName: 'awesome/bitbucket-repo1',
+            depType: 'require',
+            packageName: 'awesome/bitbucket-repo1',
+          },
+          {
+            currentValue: 'dev-trunk',
+            datasource: 'bitbucket-tags',
+            depName: 'awesome/bitbucket-repo2',
+            depType: 'require',
+            packageName: 'awesome/bitbucket-repo2',
+          },
+          {
+            currentValue: 'dev-trunk',
+            datasource: 'bitbucket-tags',
+            depName: 'awesome/bitbucket-repo3',
+            depType: 'require',
+            packageName: 'awesome/bitbucket-repo3',
+          },
+        ],
+      });
+    });
+
     it('extracts object repositories and registryUrls with lock file', async () => {
       fs.readLocalFile.mockResolvedValue(requirements5Lock);
       const res = await extractPackageFile(requirements5, packageFile);
diff --git a/lib/modules/manager/composer/index.ts b/lib/modules/manager/composer/index.ts
index 9561047cc2ee778a50ac6a71ce12f76154f4c3cb..2402f2f201c1c66dcd1e39eaa7a00999ed3120d5 100644
--- a/lib/modules/manager/composer/index.ts
+++ b/lib/modules/manager/composer/index.ts
@@ -1,4 +1,5 @@
 import type { Category } from '../../../constants';
+import { BitbucketTagsDatasource } from '../../datasource/bitbucket-tags';
 import { GitTagsDatasource } from '../../datasource/git-tags';
 import { PackagistDatasource } from '../../datasource/packagist';
 import { updateArtifacts } from './artifacts';
@@ -24,6 +25,7 @@ export const defaultConfig = {
 export const categories: Category[] = ['php'];
 
 export const supportedDatasources = [
+  BitbucketTagsDatasource.id,
   GitTagsDatasource.id,
   PackagistDatasource.id,
 ];
diff --git a/lib/modules/manager/composer/schema.ts b/lib/modules/manager/composer/schema.ts
index 6dbcfbec67568ee692c6ebf01516effd4464dfa7..e8e12e3f9c7e7c3331b06242eafe4ebdcdf0dbba 100644
--- a/lib/modules/manager/composer/schema.ts
+++ b/lib/modules/manager/composer/schema.ts
@@ -3,6 +3,7 @@ import { logger } from '../../../logger';
 import { readLocalFile } from '../../../util/fs';
 import { regEx } from '../../../util/regex';
 import { Json, LooseArray, LooseRecord } from '../../../util/schema-utils';
+import { BitbucketTagsDatasource } from '../../datasource/bitbucket-tags';
 import { GitTagsDatasource } from '../../datasource/git-tags';
 import { GithubTagsDatasource } from '../../datasource/github-tags';
 import { PackagistDatasource } from '../../datasource/packagist';
@@ -60,6 +61,10 @@ export type NamedRepo = z.infer<typeof NamedRepo>;
 const DisablePackagist = z.object({ type: z.literal('disable-packagist') });
 export type DisablePackagist = z.infer<typeof DisablePackagist>;
 
+const bitbucketUrlRegex = regEx(
+  /^(?:https:\/\/|git@)bitbucket\.org[/:](?<packageName>[^/]+\/[^/]+?)(?:\.git)?$/
+);
+
 export const ReposRecord = LooseRecord(z.union([Repo, z.literal(false)]), {
   onError: ({ error: err }) => {
     logger.debug({ err }, 'Composer: error parsing repositories object');
@@ -304,6 +309,17 @@ export const ComposerExtract = z
 
         const gitRepo = gitRepos[depName];
         if (gitRepo) {
+          const bitbucketMatchGroups = bitbucketUrlRegex.exec(
+            gitRepo.url
+          )?.groups;
+
+          if (bitbucketMatchGroups) {
+            dep.datasource = BitbucketTagsDatasource.id;
+            dep.packageName = bitbucketMatchGroups.packageName;
+            deps.push(dep);
+            continue;
+          }
+
           dep.datasource = GitTagsDatasource.id;
           dep.packageName = gitRepo.url;
           deps.push(dep);