diff --git a/.github/workflows/quick-jobs.yml b/.github/workflows/quick-jobs.yml
index 0759f91163134c7660988a2dc8a6107fa97fdb9f..87204a291f1de44faa644426a2ecda76ef483209 100644
--- a/.github/workflows/quick-jobs.yml
+++ b/.github/workflows/quick-jobs.yml
@@ -20,7 +20,7 @@ jobs:
     runs-on: ubuntu-latest
     env:
       cabal_build: >-
-        cabal build --builddir=dist-newstyle-meta --project-file=cabal.project.meta
+        cabal build --builddir=dist-newstyle-meta --project-file=cabal.meta.project
         gen-cabal-macros
         gen-paths-module
         gen-spdx
@@ -137,6 +137,6 @@ jobs:
         run: cabal v2-update
       - uses: actions/checkout@v4
       - name: Check Release with Pinned Hackage
-        run: cabal build all --dry-run --project-file=cabal.project.release
+        run: cabal build all --dry-run --project-file=cabal.release.project
       - name: Check Release with Latest Hackage
-        run: cabal build all --dry-run --project-file=cabal.project.release --index-state="hackage.haskell.org HEAD"
+        run: cabal build all --dry-run --project-file=cabal.release.project --index-state="hackage.haskell.org HEAD"
diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml
index 1144323d995c7248339f0e232900e0fde43c6c26..bc765b59ba93b9eaec464aaa976e0261de3b3ad2 100644
--- a/.github/workflows/validate.yml
+++ b/.github/workflows/validate.yml
@@ -96,8 +96,8 @@ jobs:
       - name: Manually supplied constraints/allow-newer
         if: github.event_name == 'workflow_dispatch'
         run: |
-          echo "allow-newer: ${ALLOWNEWER}"  >> cabal.project.validate
-          echo "constraints: ${CONSTRAINTS}" >> cabal.project.validate
+          echo "allow-newer: ${ALLOWNEWER}"  >> cabal.validate.project
+          echo "constraints: ${CONSTRAINTS}" >> cabal.validate.project
 
       - uses: haskell-actions/setup@v2
         id: setup-haskell
@@ -156,7 +156,7 @@ jobs:
       - name: Tar cabal head executable
         if: matrix.ghc == env.GHC_FOR_RELEASE
         run: |
-          CABAL_EXEC=$(cabal list-bin --builddir=dist-newstyle-validate-ghc-${{ matrix.ghc }} --project-file=cabal.project.validate cabal-install:exe:cabal)
+          CABAL_EXEC=$(cabal list-bin --builddir=dist-newstyle-validate-ghc-${{ matrix.ghc }} --project-file=cabal.validate.project cabal-install:exe:cabal)
           # We have to tar the executable to preserve executable permissions
           # see https://github.com/actions/upload-artifact/issues/38
           if [[ "${{ runner.os }}" == "Windows" ]]; then
@@ -288,8 +288,8 @@ jobs:
       - name: Manually supplied constraints/allow-newer
         if: github.event_name == 'workflow_dispatch'
         run: |
-          echo "allow-newer: ${ALLOWNEWER}"  >> cabal.project.validate
-          echo "constraints: ${CONSTRAINTS}" >> cabal.project.validate
+          echo "allow-newer: ${ALLOWNEWER}"  >> cabal.validate.project
+          echo "constraints: ${CONSTRAINTS}" >> cabal.validate.project
 
       - uses: haskell-actions/setup@v2
         id: setup-haskell
@@ -310,14 +310,14 @@ jobs:
 
       - name: Enable statically linked executables
         run: |
-          echo 'executable-static: true' >> cabal.project.validate
+          echo 'executable-static: true' >> cabal.validate.project
 
       - name: Build
         run: sh validate.sh $FLAGS -s build
 
       - name: Tar cabal head executable
         run: |
-          CABAL_EXEC=$(cabal list-bin --builddir=dist-newstyle-validate-ghc-${{ env.GHC_FOR_RELEASE }} --project-file=cabal.project.validate cabal-install:exe:cabal)
+          CABAL_EXEC=$(cabal list-bin --builddir=dist-newstyle-validate-ghc-${{ env.GHC_FOR_RELEASE }} --project-file=cabal.validate.project cabal-install:exe:cabal)
           # We have to tar the executable to preserve executable permissions
           # see https://github.com/actions/upload-artifact/issues/38
           DIR=$(dirname "$CABAL_EXEC")
diff --git a/.gitlab/ci.sh b/.gitlab/ci.sh
index 9966bb86f6658be16da54dbf7f793334d5551c0d..1515a6afe227ea460f5968b4622ad80ee6937071 100755
--- a/.gitlab/ci.sh
+++ b/.gitlab/ci.sh
@@ -31,7 +31,7 @@ mkdir -p "$CABAL_DIR"
 #
 # $PLATFORM comes from CI.
 if [ "$(getconf LONG_BIT)" = "32" -o "${PLATFORM:=xxx}" = "x86_64-linux-centos7" ] ; then
-    echo 'constraints: lukko -ofd-locking' >> cabal.project.release.local
+    echo 'constraints: lukko -ofd-locking' >> cabal.release.project.local
 fi
 
 # In February 2024, cabal started using zlib-0.7.0.0, which uses pkg-config by
@@ -39,21 +39,21 @@ fi
 # does just fine without it on modern GHCs. That said, the CI environment
 # probably *should* have pkg-config installed. See
 # https://github.com/haskell/cabal/issues/9774.
-echo 'constraints: zlib -pkg-config' >> cabal.project.release.local
+echo 'constraints: zlib -pkg-config' >> cabal.release.project.local
 # Furthermore, on Windows, zlib claims that libz is shipped with GHC, so it just
 # uses @extra-libraries: z@ if pkg-config is False. If you are reading this
 # comment, however, this didn't work. Thus we switch to using the bundled libz,
 # as was done in zlib <0.7.0.0.
 case "$(uname)" in
     MSYS_*|MINGW*)
-        echo 'constraints: zlib +bundled-c-zlib' >> cabal.project.release.local
+        echo 'constraints: zlib +bundled-c-zlib' >> cabal.release.project.local
     ;;
 esac
 
 args=(
     --disable-profiling
     --enable-executable-stripping
-    --project-file=cabal.project.release
+    --project-file=cabal.release.project
     ${ADD_CABAL_ARGS}
 )
 
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 5ca5544106b033b4cca3033c3a8c618b0326ed17..db9a546693968e2dd05406b63c1e8da10b987fdf 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -12,7 +12,7 @@ cabal build cabal
 If not, you aren't able to build the testsuite, so you need to disable the default `cabal.project` that implies configuring the testsuite, e.g., with:
 
 ```
-cabal build --project-file=cabal.project.release cabal
+cabal build --project-file=cabal.release.project cabal
 ```
 
 > **Note**
diff --git a/Makefile b/Makefile
index 5b5f1e21fff0b6afc12e49efcabbd4096512f568..d305ca16353acb60bb75d3d8cf83f7e2d1893a6e 100644
--- a/Makefile
+++ b/Makefile
@@ -58,10 +58,10 @@ spdx : $(SPDX_LICENSE_HS) $(SPDX_EXCEPTION_HS)
 SPDX_LICENSE_VERSIONS:=3.0 3.2 3.6 3.9 3.10 3.16 3.23
 
 $(SPDX_LICENSE_HS) : templates/SPDX.LicenseId.template.hs cabal-dev-scripts/src/GenUtils.hs cabal-dev-scripts/src/GenSPDX.hs license-list-data/licenses-3.0.json license-list-data/licenses-3.2.json
-	cabal run --builddir=dist-newstyle-meta --project-file=cabal.project.meta gen-spdx -- templates/SPDX.LicenseId.template.hs $(SPDX_LICENSE_VERSIONS:%=license-list-data/licenses-%.json) $(SPDX_LICENSE_HS)
+	cabal run --builddir=dist-newstyle-meta --project-file=cabal.meta.project gen-spdx -- templates/SPDX.LicenseId.template.hs $(SPDX_LICENSE_VERSIONS:%=license-list-data/licenses-%.json) $(SPDX_LICENSE_HS)
 
 $(SPDX_EXCEPTION_HS) : templates/SPDX.LicenseExceptionId.template.hs cabal-dev-scripts/src/GenUtils.hs cabal-dev-scripts/src/GenSPDXExc.hs license-list-data/exceptions-3.0.json license-list-data/exceptions-3.2.json
-	cabal run --builddir=dist-newstyle-meta --project-file=cabal.project.meta gen-spdx-exc -- templates/SPDX.LicenseExceptionId.template.hs $(SPDX_LICENSE_VERSIONS:%=license-list-data/exceptions-%.json) $(SPDX_EXCEPTION_HS)
+	cabal run --builddir=dist-newstyle-meta --project-file=cabal.meta.project gen-spdx-exc -- templates/SPDX.LicenseExceptionId.template.hs $(SPDX_LICENSE_VERSIONS:%=license-list-data/exceptions-%.json) $(SPDX_EXCEPTION_HS)
 
 # source generation: templates
 
@@ -75,10 +75,10 @@ TEMPLATE_PATHS:=Cabal/src/Distribution/Simple/Build/PathsModule/Z.hs
 templates : $(TEMPLATE_MACROS) $(TEMPLATE_PATHS)
 
 $(TEMPLATE_MACROS) : templates/cabal_macros.template.h cabal-dev-scripts/src/GenCabalMacros.hs
-	cabal run --builddir=dist-newstyle-meta --project-file=cabal.project.meta gen-cabal-macros -- $< $@
+	cabal run --builddir=dist-newstyle-meta --project-file=cabal.meta.project gen-cabal-macros -- $< $@
 
 $(TEMPLATE_PATHS) : templates/Paths_pkg.template.hs cabal-dev-scripts/src/GenPathsModule.hs
-	cabal run --builddir=dist-newstyle-meta --project-file=cabal.project.meta gen-paths-module -- $< $@
+	cabal run --builddir=dist-newstyle-meta --project-file=cabal.meta.project gen-paths-module -- $< $@
 
 # generated docs
 # Use cabal build before cabal run to avoid output of the build on stdout when running
@@ -93,7 +93,7 @@ doc/buildinfo-fields-reference.rst : \
 
 .PHONY: analyse-imports
 analyse-imports :
-	find Cabal-syntax/src Cabal/src cabal-install/src -type f -name '*.hs' | xargs cabal run --builddir=dist-newstyle-meta --project-file=cabal.project.meta analyse-imports --
+	find Cabal-syntax/src Cabal/src cabal-install/src -type f -name '*.hs' | xargs cabal run --builddir=dist-newstyle-meta --project-file=cabal.meta.project analyse-imports --
 
 # ghcid
 
@@ -190,7 +190,7 @@ validate-dockerfiles : .docker/validate-8.4.4.dockerfile
 validate-dockerfiles : .docker/validate-8.2.2.dockerfile
 
 .docker/validate-%.dockerfile : .docker/validate.dockerfile.zinza cabal-dev-scripts/src/GenValidateDockerfile.hs
-	cabal run --builddir=dist-newstyle-meta --project-file=cabal.project.meta gen-validate-dockerfile -- $* $< $@
+	cabal run --builddir=dist-newstyle-meta --project-file=cabal.meta.project gen-validate-dockerfile -- $* $< $@
 
 # This is good idea anyway
 # and we have a test relying on this limit being sufficiently small
@@ -229,7 +229,7 @@ tags :
 ##############################################################################
 
 bootstrap-json-%: phony
-	cabal build --project-file=cabal.project.bootstrap --with-compiler=ghc-$* --dry-run cabal-install:exe:cabal
+	cabal build --project-file=cabal.bootstrap.project --with-compiler=ghc-$* --dry-run cabal-install:exe:cabal
 	cp dist-newstyle/cache/plan.json bootstrap/linux-$*.plan.json
 	@# -v0 to avoid build output on stdout
 	cd bootstrap && cabal run -v0 cabal-bootstrap-gen -- linux-$*.plan.json \
diff --git a/README.md b/README.md
index bf6ea795060fea1ce95d6705ae198f3eea92576e..4697cf2b2c6a706df43e180ec20a80a071bc0cb0 100644
--- a/README.md
+++ b/README.md
@@ -84,7 +84,7 @@ Ways to build `cabal-install` for everyday use
     Git repository, move to its root, and run:
 
     ```
-    cabal install --project-file=cabal.project.release cabal-install
+    cabal install --project-file=cabal.release.project cabal-install
     ```
 
 3. _Bootstrapping_:
diff --git a/bootstrap/generate_bootstrap_plans b/bootstrap/generate_bootstrap_plans
index ff5af4e85fb1d0d86aa2a697a79fbde1bd9e474a..4357a7a9843faba2813c92feebc30c8b6b6c7143 100755
--- a/bootstrap/generate_bootstrap_plans
+++ b/bootstrap/generate_bootstrap_plans
@@ -10,7 +10,7 @@ run() {
   local drv="ghc-$ver"
   echo "$ver"
   nix build -f "$ghcs_nix" $drv
-  (cd ../; rm -r dist-bootstrap; cabal --distdir=dist-bootstrap build --project-file=cabal.project.release --dry-run cabal-install:exe:cabal -w bootstrap/result/bin/ghc)
+  (cd ../; rm -r dist-bootstrap; cabal --distdir=dist-bootstrap build --project-file=cabal.release.project --dry-run cabal-install:exe:cabal -w bootstrap/result/bin/ghc)
   jq --sort-keys < ../dist-bootstrap/cache/plan.json > "plan-$ver.json"
   cabal run --with-ghc-pkg $PWD/boot_ghc/bin/ghc-pkg -w $PWD/boot_ghc/bin/ghc -v0 cabal-bootstrap-gen -- "plan-$ver.json" | jq --sort-keys | tee "linux-$(echo $ver | tr "_" ".").json"
 }
diff --git a/cabal-testsuite/README.md b/cabal-testsuite/README.md
index afe08e499dc198f4e63ab7de324207f7b17ced7b..79b9185fecbf06eccab6169347501c02a4750292 100644
--- a/cabal-testsuite/README.md
+++ b/cabal-testsuite/README.md
@@ -65,7 +65,7 @@ cabal install doctest --overwrite-policy=always --ignore-project
 After that you can run doctests for a component of your choice via the following command:
 
 ``` shellsession
-cabal repl --with-ghc=doctest --build-depends=QuickCheck --build-depends=template-haskell --repl-options="-w" --project-file="cabal.project.validate" Cabal-syntax
+cabal repl --with-ghc=doctest --build-depends=QuickCheck --build-depends=template-haskell --repl-options="-w" --project-file="cabal.validate.project" Cabal-syntax
 ```
 
 In this example we have run doctests in `Cabal-syntax`. Notice, that some
diff --git a/cabal.project.bootstrap b/cabal.bootstrap.project
similarity index 100%
rename from cabal.project.bootstrap
rename to cabal.bootstrap.project
diff --git a/cabal.project.meta b/cabal.meta.project
similarity index 100%
rename from cabal.project.meta
rename to cabal.meta.project
diff --git a/cabal.project.release b/cabal.release.project
similarity index 100%
rename from cabal.project.release
rename to cabal.release.project
diff --git a/cabal.project.validate.libonly b/cabal.validate-libonly.project
similarity index 100%
rename from cabal.project.validate.libonly
rename to cabal.validate-libonly.project
diff --git a/cabal.project.validate b/cabal.validate.project
similarity index 100%
rename from cabal.project.validate
rename to cabal.validate.project
diff --git a/project-cabal/README.md b/project-cabal/README.md
index 03f3dbdaf0248a74eed41cfe25dab3ae63d8e76f..d12a316e3e480cfe89c53c154c5312c7e92dcd14 100644
--- a/project-cabal/README.md
+++ b/project-cabal/README.md
@@ -3,14 +3,14 @@
 We have these projects, all in the root:
 
 ```
-$ tree -P 'cabal.project*' --prune -L 1
+$ tree -P '*.project' --prune -L 1
 .
+├── cabal.bootstrap.project
+├── cabal.meta.project
 ├── cabal.project
-├── cabal.project.libonly
-├── cabal.project.meta
-├── cabal.project.release
-├── cabal.project.validate
-└── cabal.project.validate.libonly
+├── cabal.release.project
+├── cabal.validate-libonly.project
+└── cabal.validate.project
 ```
 
 Projects are expected to pass a `build --dry-run` standalone test,
@@ -85,7 +85,7 @@ package group.
 The `meta` project is a one-liner:
 
 ```
-$ cat cabal.project.meta
+$ cat cabal.meta.project
 packages: cabal-dev-scripts
 ```
 
diff --git a/project-cabal/ghc-latest.config b/project-cabal/ghc-latest.config
index 5132415b48c5afcfc33fd2b02bf0f0ae9f361c98..bff5d80c2412249e60ce9207fe221bfec67d469f 100644
--- a/project-cabal/ghc-latest.config
+++ b/project-cabal/ghc-latest.config
@@ -3,7 +3,7 @@
 -- The file is supposed to be included in the main project files used for
 -- Cabal development:
 --   - cabal.project (day-to-day development),
---   - cabal.project.validate (Cabal CI),
+--   - cabal.validate.project (Cabal CI),
 -- Commented out below are the usual suspects. Feel free to add more.
 
 -- NOTE: don't forget to update the compiler version in the conditional
diff --git a/validate.sh b/validate.sh
index be167d40d438ed8e472cb90d9e7e0fe6a9f01417..3b56a945c8482200cd46b86d36ff7a4b40e095ec 100755
--- a/validate.sh
+++ b/validate.sh
@@ -312,9 +312,9 @@ case "$(uname)" in
 esac
 
 if $LIBONLY; then
-    PROJECTFILE=cabal.project.validate.libonly
+    PROJECTFILE=cabal.validate-libonly.project
 else
-    PROJECTFILE=cabal.project.validate
+    PROJECTFILE=cabal.validate.project
 fi
 
 BASEHC=ghc-$($HC --numeric-version)