Skip to main content
SEMastery
Data Accessbeginner

The New .slnx Solution Format: A Simple Migration Guide for .NET 10

Learn the new XML-based .slnx solution format in .NET 10, why it beats the old .sln file, and how to migrate safely with one CLI command.

12 min readUpdated December 28, 2025

Think about a class attendance register. The old register was a fat notebook full of secret codes, page numbers, and student ID numbers written in a strange order. Only the head teacher could read it. Every time two teachers wrote in it on the same day, the entries clashed and someone had to fix the mess by hand.

Now imagine a new register: a clean sheet that simply lists each student's name, one per line, in plain words. Anyone can read it. When two teachers add a new name, the two lines almost never clash.

That is exactly the change happening in .NET. The old .sln file is the fat notebook full of secret codes. The new .slnx file is the clean, plain sheet. In .NET 10, the clean sheet becomes the default. This guide shows you what changed, why it is better, and how to move over safely in one command.

What is a solution file, anyway?

When you build a real app, you rarely have just one project. You might have a web API, a class library for your database code, and a test project. A solution is a small file that ties these projects together so your tools know they belong to the same app.

The solution file answers three simple questions:

  • Which projects are part of this app?
  • How are they grouped into folders?
  • Which build settings (like Debug and Release) should they use?

For over twenty years, this file was called .sln. It worked, but it was never meant for humans to read or edit by hand.

A solution file ties several projects together so your tools treat them as one app.

The old .sln file: why it hurt

Open an old .sln file in Notepad and you will see something scary. Here is a small piece of one.

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApi", "WebApi\WebApi.csproj", "{A1B2C3D4-1111-2222-3333-444455556666}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
		Release|Any CPU = Release|Any CPU
	EndGlobalSection
EndGlobal

Look at those long codes inside the curly braces. Those are GUIDs (globally unique identifiers). They are long random labels the tools use to tell projects apart. A human cannot read them, and a human should never edit them.

The format had three real pains:

  1. It was hard to read. Lines were long, repeated, and full of GUIDs.
  2. It caused Git merge conflicts. When two people added a project at the same time, Git often got confused and you had to untangle it by hand.
  3. It was long. A solution with three projects could take 35 lines or more.

The old .sln pain cycle

Edit .sln
Push to Git
Conflict
Fix by hand

Steps

1

Edit .sln

Two devs add projects

2

Push to Git

Both touch the same lines

3

Conflict

Git cannot auto-merge

4

Fix by hand

Slow and risky

Why merge conflicts were so common with the old format.

The new .slnx file: clean and simple

The .slnx file does the exact same job, but it is written in XML. XML is a simple way to describe things with tags, a bit like labelled boxes. Here is a full .slnx file for the same three projects.

<Solution>
  <Project Path="WebApi/WebApi.csproj" />
  <Project Path="DataAccess/DataAccess.csproj" />
  <Project Path="Tests/Tests.csproj" />
</Solution>

That is the whole file. No GUIDs. No secret codes. Just three lines that say "here are my projects." You can read it, a teammate can read it, and Git can merge it easily.

The table below shows the difference at a glance.

PointOld .slnNew .slnx
File typeCustom text with GUIDsPlain XML
Easy to readNoYes
Lines for 3 projectsAbout 35About 5
Git merge conflictsCommonRare
Edit by handRiskySafe and simple
The same solution stored in two ways: heavy and noisy versus light and clear.

When did this become the default?

This is the key date for you to remember. Starting with .NET 10, when you run dotnet new sln, the CLI creates a .slnx file by default instead of a .sln file. This is a small breaking change, but a friendly one. Older SDKs still create the old .sln file.

So in .NET 10 you get the new format for free on any brand-new solution. For your existing solutions, you migrate them with one command, which we will cover next.

ToolFirst version with full .slnx support
.NET CLI / SDK9.0.200
Visual Studio 202217.13
JetBrains Rider2024.3
VS Code (C# Dev Kit)Supported
MSBuild17.12

How to migrate: one command

Migration is short and safe. Open a terminal in the folder that holds your .sln file and run this.

dotnet sln MySolution.sln migrate

That is it. The command reads your old MySolution.sln and writes a new MySolution.slnx right next to it. The best part: your original .sln file is not deleted. It stays exactly where it was. So if anything looks wrong, you simply keep using the old file and try again later.

Here is the flow in plain steps.

Safe migration path

Check SDK
Run migrate
Open .slnx
Build & test
Delete .sln

Steps

1

Check SDK

Need 9.0.200+

2

Run migrate

dotnet sln migrate

3

Open .slnx

Verify projects

4

Build & test

Make sure it works

5

Delete .sln

Only when happy

A calm, step-by-step move with an easy rollback.

Let me walk through each step like a checklist.

Step 1: Check your SDK version

You need .NET SDK 9.0.200 or newer for the migrate command. Check what you have.

dotnet --version

If the number is older than 9.0.200, install a newer SDK first. In .NET 10 you are already past this line.

Step 2: Run the migrate command

Move into the folder with your solution and run the migrate command shown above. If your solution file has a different name, use that name. After it finishes, you should see a new file named MySolution.slnx appear.

Step 3: Open the new file and check it

Open MySolution.slnx in your editor. You should see one <Project> line for each project that was in the old solution. If you used solution folders to group projects, you will see <Folder> tags too. Here is what a grouped solution looks like.

<Solution>
  <Folder Name="/src/">
    <Project Path="src/WebApi/WebApi.csproj" />
    <Project Path="src/DataAccess/DataAccess.csproj" />
  </Folder>
  <Folder Name="/tests/">
    <Project Path="tests/Tests/Tests.csproj" />
  </Folder>
</Solution>

Notice how the folders read like a real folder tree. This is far clearer than the old format, where folders were just more GUIDs hidden in the text.

Step 4: Build and test

Now prove it works. Point your build at the new file and run it.

dotnet build MySolution.slnx
dotnet test MySolution.slnx

If both succeed, your migration is good. Open the solution in Visual Studio or Rider too, just to be sure the IDE is happy.

Step 5: Delete the old .sln (only when you are happy)

Once the new file builds, tests pass, and your IDE opens it cleanly, you can delete the old .sln file. Do this as a separate, calm step. There is no rush.

The decision flow: only remove the old file after everything passes.

Updating your build pipeline (CI)

If you have a CI pipeline (the robot that builds and tests your code when you push), check whether it names the solution file directly. Many pipelines have a line like this.

- run: dotnet build MyApp.sln

After migrating, point it at the new file.

- run: dotnet build MyApp.slnx

A small but important tip: do not keep both MyApp.sln and MyApp.slnx in the same folder long-term if you also use bare commands like dotnet build with no file name. When two solution files sit side by side, some tools will not know which one to pick and may stop with an error. During migration this overlap is fine for a short while, but tidy it up once you trust the new file.

What does .slnx not change?

This is good news for nervous beginners. The .slnx file only changes how the solution is written down. It does not change your projects, your code, your NuGet packages, or how your app runs.

  • Your .csproj files stay the same.
  • Your build still produces the same output.
  • Your tests run the same way.
  • Your code does not change at all.

Think of it like rewriting the attendance register in neat handwriting. The students are the same. Only the page looks better.

A quick before-and-after example

Suppose you start with this old layout.

MyApp.sln
src/WebApi/WebApi.csproj
src/DataAccess/DataAccess.csproj
tests/Tests/Tests.csproj

You run one command.

dotnet sln MyApp.sln migrate

Now you have MyApp.slnx sitting next to MyApp.sln, with this clean content.

<Solution>
  <Project Path="src/WebApi/WebApi.csproj" />
  <Project Path="src/DataAccess/DataAccess.csproj" />
  <Project Path="tests/Tests/Tests.csproj" />
</Solution>

You build, you test, you delete the old file. Done. The whole thing takes a couple of minutes for most projects.

Common questions and small gotchas

A few practical notes that save you time:

  • Older teammates. If a teammate is still on an SDK older than 9.0.200, they cannot open .slnx. Make sure the whole team upgrades before you delete the old .sln.
  • Add and remove still work. You can run dotnet sln MyApp.slnx add SomeProject.csproj and remove just like before. The commands work on both formats.
  • Hand editing is now safe. Because the file is simple XML, you can add a <Project> line by hand if you want. This was a bad idea with the old format.
  • Source control is happier. Commit the .slnx file and your future merges will be far cleaner. This is the biggest day-to-day win.

Why the team will thank you

Let me explain the Git win a little more, because it is the reason most teams switch. Git is the tool that saves every version of your code and lets many people work together. When two people change the same file in the same place, Git asks a human to sort it out. This is called a merge conflict, and it is slow and easy to get wrong.

The old .sln file was a magnet for these conflicts. Adding a project meant touching several lines, all near each other, all full of GUIDs. Two people adding two projects on the same day almost always clashed.

The new .slnx file fixes this by being short and orderly. Adding a project usually means adding just one tidy line. Two people adding two different projects now touch two different lines, so Git merges them on its own. No human has to step in.

Two developers add projects at the same time and Git merges cleanly with .slnx.

Over a year, on a busy team, this saves real hours and real headaches. It is a small file change that pays back every single week.

What if I am not on .NET 10 yet?

You do not have to wait for .NET 10 to enjoy the new format. As long as you have SDK 9.0.200 or later, the dotnet sln migrate command works and the .slnx file builds. The only thing .NET 10 adds is making .slnx the default for brand-new solutions.

So a sensible plan for an older team is:

  1. Upgrade everyone to SDK 9.0.200 or later.
  2. Migrate one small repository first as a test.
  3. Once it feels safe, migrate the bigger repositories.
  4. Move fully to .NET 10 when you are ready, with the format already in place.

This way the solution-format change and the framework upgrade do not pile onto the same risky afternoon. You take them one calm step at a time.

Quick recap

  • A solution file lists the projects in your app and how they are grouped.
  • The old .sln format was hard to read, full of GUIDs, and caused Git merge conflicts.
  • The new .slnx format is plain XML: short, clear, and easy to merge.
  • In .NET 10, dotnet new sln creates a .slnx file by default.
  • Migrate with one command: dotnet sln MySolution.sln migrate. Your old file is kept, so rollback is easy.
  • You need SDK 9.0.200+; Visual Studio 17.13+, Rider 2024.3+, and VS Code all support it.
  • Migration changes only the solution file, not your code, projects, or builds.
  • Update your CI pipeline to point at the .slnx file, then delete the old .sln once everything passes.

References and further reading

Related Posts