The new Visual Studio Solution File Format: Goodbye .SLN, Welcome .SLNX!

With the launch of Visual Studio .NET in the year 2002, the solution file .sln was introduced. And since then, we were using that custom format to manage the projects that belong together to build an application. But with .NET 10 and Visual Studio 2026, times have changed: The new .slnx format is here!

Solutions in .NET

When you build a more complex application with .NET and C#, you usually structure your code into separate projects. Maybe you have a project for the user interface, another one for core business logic and another one for infrastructure code like data access code. For C#, these projects are defined with .csproj files.

To manage and build all projects required for your application, you usually create a solution. A solution is actually a solution file (.sln) that contains references to the project files. Since Visual Studio .NET was introduced in 2002, you can open these .sln files with Visual Studio. When you do that, Visual Studio shows the solution and its projects in the Solution Explorer:

Solution with three projects: UI, Core, and Tests

What’s the Issue with .sln?

The .sln format is a custom format. Let’s take the solution from above as an example. It is a very simple solution that has just three projects for UI, Core, and Tests. In addition, the Tests project is in a Tests solution folder. And this is the content of the .sln file:

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 18
VisualStudioVersion = 18.6.11819.183
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThomasApp.UI", "ThomasApp.UI\ThomasApp.UI.csproj", "{4C945E5C-C0EC-31C6-88D4-652B1A66C2C9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThomasApp.Tests", "ThomasApp.Tests\ThomasApp.Tests.csproj", "{85C191E0-F7F1-9D1F-3F77-C7B45BEDA62B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThomasApp.Core", "ThomasApp.Core\ThomasApp.Core.csproj", "{6745AC1A-B639-46DA-DA9A-8D38BB03144A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{0E3B5453-F60E-45DF-840D-DEB42D76F9E6}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
		Release|Any CPU = Release|Any CPU
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{4C945E5C-C0EC-31C6-88D4-652B1A66C2C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{4C945E5C-C0EC-31C6-88D4-652B1A66C2C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{4C945E5C-C0EC-31C6-88D4-652B1A66C2C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{4C945E5C-C0EC-31C6-88D4-652B1A66C2C9}.Release|Any CPU.Build.0 = Release|Any CPU
		{85C191E0-F7F1-9D1F-3F77-C7B45BEDA62B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{85C191E0-F7F1-9D1F-3F77-C7B45BEDA62B}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{85C191E0-F7F1-9D1F-3F77-C7B45BEDA62B}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{85C191E0-F7F1-9D1F-3F77-C7B45BEDA62B}.Release|Any CPU.Build.0 = Release|Any CPU
		{6745AC1A-B639-46DA-DA9A-8D38BB03144A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{6745AC1A-B639-46DA-DA9A-8D38BB03144A}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{6745AC1A-B639-46DA-DA9A-8D38BB03144A}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{6745AC1A-B639-46DA-DA9A-8D38BB03144A}.Release|Any CPU.Build.0 = Release|Any CPU
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
	GlobalSection(NestedProjects) = preSolution
		{85C191E0-F7F1-9D1F-3F77-C7B45BEDA62B} = {0E3B5453-F60E-45DF-840D-DEB42D76F9E6}
	EndGlobalSection
EndGlobal

As you can see, this is a custom file format. It’s not based on JSON or XML, but just a custom text file. At the top, you can see the references to the .csproj files. For the projects, there are Project and EndProject markers. But wait, there are four of these markers, but we have only three projects? Ah, one of those Project and EndProject markers is for the Tests solution folder.

There are also several magic GUIDs in the file. Then there is solution configuration for debug and release builds. These are all default values, as I didn’t configure anything special for this solution.

Now, as you can imagine, with bigger solutions, this custom format with GUIDs and other text content is quite hard to handle when multiple developers work on the solution. When you build software for enterprises and when you use domain-driven design, you usually end up with solutions that contain far more than 10 projects, sometimes 50+, sometimes even more. When you then change something at the solution-level, like adding a project, adding a solution folder etc. and you get a merge conflict, it’s sometimes not obvious how to solve it. Because of this, in more complex solutions, developers often don’t do a real merge of the .sln file when things are not obvious. Instead, they take the incoming .sln file from the main branch and manually re-do their changes again in the Solution Explorer. This could be re-adding a new project or re-creating a solution folder and moving files or projects into it. Then they have the latest .sln file with their changes included. But this is a tedious task to merge the latest changes from the main branch into your feature branch.

Also manual editing of the .sln file is not straight-forward. The custom format and the GUIDs make manual editing complicated.

The new .slnx format

With .NET 10 and Visual Studio 2026, Microsoft introduced the new .slnx format for solution files. This format is XML-based. When you create a new project with Visual Studio 2026, you automatically get a solution file in the .slnx format.

For the solution used in this blog post with the three projects for UI, Core, and Tests, and the Tests solution folder, the .slnx file has this compact and nicely readable content:

<Solution>
  <Folder Name="/Tests/">
    <Project Path="ThomasApp.Tests/ThomasApp.Tests.csproj" />
  </Folder>
  <Project Path="ThomasApp.Core/ThomasApp.Core.csproj" />
  <Project Path="ThomasApp.UI/ThomasApp.UI.csproj" />
</Solution>

This looks amazing, doesn’t it? It contains all the information that was also stored in the old format. The old format stored many default values that are not explicitly part of this file, because, well, they are default values. This makes this file more compact. Also no GUIDs are in this file. But no information is lost, everything that is needed is there.

Now you can clearly see the Tests solution folder that contains the ThomasApp.Tests.csproj and also the other two projects for the UI and Core part of the solution.

As you can imagine, when you merge solution changes, this new .slnx format is way easier to merge than the old .sln format.

Why XML and not JSON or something else?

In my opinion, XML is a great choice here. First, elements with attributes and nested sub-elements are powerful to describe the structure of a solution. Second, the .csproj file format is also XML-based, so an XML-based solution file aligns very well with what’s already there for projects.

As you might remember, with .NET Core 1.0 Microsoft used JSON for the project file format. Instead of .csproj we had project.json. But it didn’t work well with MSBuild, and it turned out that XML is the better choice, and so they made the switch from JSON to XML, which was already the project format for .NET Framework projects.

In case of the .slnx file, I think XML is also the right move for this file format. In the end, XML is easy to read and easy to merge.

Converting from .sln to .slnx with Visual Studio

When you open an existing, old-school .sln file in Visual Studio, you can select the solution in the Solution Explorer, and then you navigate to the File menu to use there the “Save .sln As…” option like you see below.

Use “Save .sln As…” to save it in the .slnx format

In the Save File dialog, you can select as a type the new .slnx format like in the screenshot below.

In the Save File dialog you can select the .slnx format

Then save the file, and you have the new format. That’s it!

Converting via .NET CLI

Instead of using Visual Studio to generate a .slnx file from a .sln file, you can also use the .NET command line interface (CLI) and this command:

dotnet sln migrate

When you run this command, you get like below the information that the .slnx file was generated. When you then list the names of files and folders via ls -n command, you can see that you have now besides the .sln file also an .slnx file.

Migrate to .slnx via .NET CLI

Remove the .sln file after migration

After you migrated to .slnx, either with Visual Studio or the .NET CLI, that new .slnx file sits beside the old .sln file. When multiple developers work on your solution, you need to ensure in which solution file changes are made. So, it’s best practice to have not both files in your repository. Usually, after generating the .slnx file, you should delete the old .sln file. Then you can ensure that everybody works with the correct solution file.

What about compatibility?

Maybe not all developers of your team are ready to switch to Visual Studio 2026. Microsoft ensured that the new format is compatible down to Visual Studio 2022 version 17.14.

Summary

The new solution file format is a great improvement to manage multiple projects that belong together. It makes manual editing and merging changes at the solution level way easier than it used to be with the old format.

Want to read more? Check out this blog post from Microsoft.

Thanks for reading,
Thomas

Share this post

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.