en

Migrating from CPM

Convert an existing solution (with or without CPM) into a PCPM workspace in one command.

If you already have a .NET solution with or without Central Package Management, pcpm convert migrates it in place.

What it does

pcpm convert walks your workspace, looks at every <PackageReference /> in every .csproj, and:

  1. Adopts your existing Directory.Packages.props if you have one, and rewrites every <PackageReference Include="X" Version="1.2.3" /> to <PackageReference Include="X" /> (no version, since the version now lives in CPM).
  2. Creates Directory.Packages.props if you don’t have one, and hoists every per-project version into a <PackageVersion /> entry.
  3. Writes pcpm.json and, in monorepo mode, pcpm-workspace.yaml.
  4. Runs pcpm install to materialise the store and produce the initial pcpm.lock.

The whole thing is a no-op if the workspace is already in PCPM’s expected shape.

Running it

pcpm convert

In a monorepo:

pcpm convert --workspace

The --workspace flag tells PCPM to write a pcpm-workspace.yaml that covers all discovered projects. Without it, PCPM only looks at the .sln in the current directory (or one level up).

What it does NOT do

pcpm convert is conservative by design. It does not:

  • Touch your .csproj files beyond the version-stripping described above. Project structure, SDKs, and properties are all left alone.
  • Change your NuGet feed configuration. Existing NuGet.config files are kept as-is; PCPM reads them and writes the same feeds into pcpm.json for its own use.
  • Update packages. pcpm convert only normalises your existing versions into CPM. To bump versions, run pcpm update <pkg> after the convert.

Example

Starting state:

<!-- src/Api/Api.csproj -->
<ItemGroup>
  <PackageReference Include="Serilog" Version="3.1.1" />
  <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
</ItemGroup>

After pcpm convert:

<!-- Directory.Packages.props (created) -->
<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
  </PropertyGroup>
  <ItemGroup>
    <PackageVersion Include="Serilog" Version="3.1.1" />
    <PackageVersion Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
  </ItemGroup>
</Project>

<!-- src/Api/Api.csproj (modified) -->
<ItemGroup>
  <PackageReference Include="Serilog" />
  <PackageReference Include="Microsoft.Extensions.Hosting" />
</ItemGroup>

And the new files:

  • pcpm.json
  • pcpm.lock (after pcpm install)

Rolling back

pcpm convert is not destructive — it only edits files under the workspace root, and those edits are diff-friendly. To roll back:

git restore .

That reverts every file PCPM touched, including the new manifests. pcpm.lock and pcpm.json will disappear from the diff.

Tips for a smooth conversion

  • Do it in a branch. Always. The diff is small but the implications for the rest of your team are not.
  • Run dotnet build after the convert. If anything is wrong, it’ll show up as a missing <PackageVersion /> or a project that wasn’t picked up by the discovery.
  • Don’t combine the convert with version bumps. First get the shape right, then pcpm update deliberately.