File-Based Applications in .NET 10
Run C# scripts without a project or solution - this changes how we write throwaway code and quick scripts.
Connect with me:
Introduction
How many times have you needed a quick C# script - something to parse a file, hit an API, or test a bit of logic - and immediately found yourself creating a full project, adding a .csproj, setting up a solution, just to run 10 lines of code?
.NET 10 changes that. File-based applications let you write a single .cs file and run it directly with dotnet run demo.cs. No project, no solution, no ceremony.
This is a genuine shift in how .NET developers can handle scripting, quick tools, and lightweight utilities. Let me walk you through what it can do.
🎬 Watch the full video here:
Prerequisites
Before anything else, make sure you have the .NET 10 SDK installed. Run this to check:
dotnet --list-sdksYou need .NET 10 in the output. If it is not there, download it from the Microsoft website.
To verify the feature works, create a demo.cs file with:
Console.WriteLine("Hello, World!");Then run:
dotnet run demo.csIf you are using .NET 8 or 9 as your SDK in that directory, you will get an error like “couldn’t find the project to run.” Switch to .NET 10 and it works immediately.
Using NuGet Packages
File-based applications support NuGet packages via a special #:package directive at the top of the file.
#:package Newtonsoft.Json@13.0.*
using Newtonsoft.Json;
var x = new { Name = "John", Age = 18 };
var serialized = JsonConvert.SerializeObject(x);
Console.WriteLine(serialized);Key points:
#:packagefollowed by the package name and version (wildcards supported, e.g.,13.0.*resolves to the latest 13.0.x)You can pin an exact version like
@13.0.1or use wildcards for flexibilityWorks just like adding a NuGet reference in a regular project
MSBuild Properties
By default, file-based applications have Native AOT publishing enabled. If you use libraries that depend on reflection (like Newtonsoft.Json), this will cause warnings and potentially broken behavior when publishing.
You can override MSBuild properties with the #:property directive:
#:property PublishAot=falseOther useful properties:
#:property LangVersion=preview // unlock C# preview features
#:property Nullable=false // disable nullable reference types (enabled by default)Key points:
PublishAot=trueis the default - set tofalseif you are using reflection-based librariesNullable reference types are enabled by default in file-based apps
LangVersioncan be set to a specific version (e.g.,14) orpreviewfor the latest features
Specifying the SDK
You are not limited to the default SDK. You can target a specific .NET SDK using the #:sdk directive. This is what unlocks building a full Minimal API from a single file:
#:property PublishAot=false
#:sdk Microsoft.NET.Sdk.Web
#:package Microsoft.AspNetCore.OpenApi@*-*
#:package Scalar.AspNetCore@*-*
using Scalar.AspNetCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenApi();
builder.Services.AddHttpClient();
var app = builder.Build();
app.MapOpenApi();
app.MapScalarApiReference();
app.MapGet("/weather/{city}", async (string city, HttpClient http) =>
{
var data = await http.GetFromJsonAsync<object>($"https://wttr.in/{city}?format=j1");
return data;
});
app.Run();26 lines. A fully working Minimal API with Scalar UI, HTTP client, and an external API call.
Key points:
#:sdk Microsoft.NET.Sdk.Webswitches the SDK exactly like changing the SDK in a.csprojOpenAPI and Scalar packages are added the same way as any other NuGet package
Run with
dotnet run demo.cs- the web server starts just as it would in a regular project
Publishing a File-Based Application
You can publish a file-based application to a single executable:
#:property PublishAot=false
#:property PublishSingleFile=true
#:property EnableStaticWebAssetsIfNecessary=falseThen run:
dotnet publish demo.csThe output lands in artifacts/demo/. With PublishAot=false, you get four files (including the in-process handler and web.config for web SDK apps). With PublishAot=true, you get just two files - the .pdb and the executable.
Key points:
PublishSingleFile=truebundles everything into one executableEnableStaticWebAssetsIfNecessary=falsereduces unnecessary file generation for API-only appsThe published executable runs independently, no SDK required on the target machine
Converting to a Full Project
When your script outgrows a single file, you can convert it to a proper .csproj-based project:
dotnet project convert demo.cs --output demoFlags to know:
--outputspecifies the output directory (defaults to a folder named after the file)--delete-sourceremoves the original.csfile after conversionWithout
--delete-source, both the original and the generated project are kept
The result is a .csproj file with all the NuGet references, SDK, and properties you defined via directives - automatically converted.
Current Limitation
Right now you can only convert a single file at a time. .NET 11 is expected to support multi-file conversion, which will make this much more practical for slightly larger scripts.
Key Takeaways
File-based applications in .NET 10 let you run a single
.csfile withdotnet run demo.cs- no project or solution needed.Use
#:package,#:property, and#:sdkdirectives to configure NuGet packages, MSBuild properties, and the target SDK from inside the file.Native AOT is enabled by default - set
#:property PublishAot=falsewhen using reflection-based libraries like Newtonsoft.Json.You can build a fully functional Minimal API with Scalar UI in under 30 lines using
#:sdk Microsoft.NET.Sdk.Web.Publishing produces a self-contained executable with
dotnet publish demo.cs.Use
dotnet project convert demo.csto graduate a script into a full project when it outgrows a single file.
Connect with me:
