We are super excited to introduce a new feature that was released as part of .NET 10 Preview 4 that makes getting started with C# easier than ever. You can now run a C# file directly using dotnet run app.cs
. This means you no longer need to create a project file or scaffold a whole application to run a quick script, test a snippet, or experiment with an idea. It’s simple, intuitive, and designed to streamline the C# development experience, especially for those just getting started.
What is dotnet run app.cs
?
Until now, executing C# code using the dotnet
CLI required a project structure that included a .csproj
file. With this new capability, which we call file-based apps, you can run a standalone .cs
file directly, much like you would with scripting languages such as Python or JavaScript.
This lowers the entry barrier to trying out C# and makes the language a much more attractive choice for learning, prototyping, or automation scenarios.
- Quick Start, No Project File Required – Great for learning, experimentation, and small scripts.
- First-Class CLI Integration – No extra tools, no dependencies, just
dotnet
and your.cs
file. - Scales to Real Applications – This isn’t a separate dialect or runtime. When your script grows up, it can evolve into a full-fledged project using the same language, syntax, and tooling.
New file-level directives for file-based C# apps
With .NET 10 Preview 4, file-based apps also support a set of powerful file-level directives that allow to declare a small number of important things that are stored in project files for project-based apps, all without leaving your single .cs
file. These directives make file-based apps more flexible and expressive while maintaining compatibility with MSBuild concepts.
Referencing NuGet packages with #:package
You can add NuGet package references directly in your .cs
file using the #:package
directive:
#:package Humanizer@2.14.1
using Humanizer;
var dotNet9Released = DateTimeOffset.Parse("2024-12-03");
var since = DateTimeOffset.Now - dotNet9Released;
Console.WriteLine($"It has been {since.Humanize()} since .NET 9 was released.");
Specifying an SDK with #:sdk
By default, file-based apps use the Microsoft.NET.Sdk
SDK. If you’re building something like a web API, you can change the SDK using the #:sdk
directive:
#:sdk Microsoft.NET.Sdk.Web
This tells the tooling to treat the file as if it were part of a web project, enabling features of ASP.NET Core like Minimal APIs and MVC.
Setting MSBuild properties with #:property
You can configure additional build properties using #:property
. For example:
#:property LangVersion preview
This allows your file-based app to opt into advanced language features and platform targeting, without needing a full project file.
Using shebang lines for shell scripts
File-based apps also support shebang lines (#!
), allowing you to write cross-platform C# shell scripts that are executable directly on Unix-like systems. For example:
#!/usr/bin/dotnet run
Console.WriteLine("Hello from a C# script!");
You can make the file executable and run it directly:
chmod +x app.cs
./app.cs
This makes C# a convenient option for CLI utilities, automation scripts, and tooling, no project setup required.
Converting to a project-based app
When your file-based app grows in complexity, or you simply want the extra capabilities afforded in project-based apps, you can convert it to a standard project with:
dotnet project convert app.cs
This command creates a new directory named for your file, scaffolds a .csproj
file, moves your code into a Program.cs
file, and translates any #:
directives into MSBuild properties and references.
Example
Given this file:
#:sdk Microsoft.NET.Sdk.Web
#:package Microsoft.AspNetCore.OpenApi@10.*-*
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi();
var app = builder.Build();
app.MapGet("/", () => "Hello, world!");
app.Run();
The generated .csproj
would be:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.*-*" />
</ItemGroup>
</Project>
This makes the transition seamless, from a single file to a fully functional, buildable, and extensible project.
Existing ways to run C# without projects
This is far from the first time developers have wanted to run C# without a project. Community projects like CS-Script, dotnet-script, Cake, and others have long filled this role, enabling scripting workflows, REPL experiences, and other experiences with C#. Here’s a blog post by Scott Hanselman from 2018 detailing the dotnet-script
global tool.
These tools remain valuable and are worth checking out, especially for more advanced scripting scenarios. However, with this new built-in support, developers can get started immediately: no additional installation, configuration, or discovery steps required.
Equally important: this isn’t a separate dialect or mode of C#. We’re being intentional about making this feature a natural earlier “click-stop” from a regular C# project-based app. You’re writing the same C#, using the same compiler, and when your code grows up, it transitions naturally into a project-based app, if and when you want.
Getting Started
- Install .NET 10 Preview 4 Download and install it from dotnet.microsoft.com.
- Install Visual Studio Code (recommended)
If you’re using Visual Studio Code, install the C# Dev Kit and then follow these instructions to update the C# extension for file-based apps support:
To enable support for file-based apps and directives, you’ll need the latest pre-release version of the C# extension:
- Open the Extensions sidebar (
Ctrl+Shift+X
) - Search for “C#”
- In the extension page, click the Switch to Pre-Release Version button
- Ensure the version installed is at least
2.79.8
- Open the Extensions sidebar (
- Write your code
Create a file called
hello.cs
:Console.WriteLine("Hello, world!");
- Run it!
Open a terminal in the same folder and run:
dotnet run hello.cs
- Convert to a project
To convert the file to a project, run:
dotnet project convert hello.cs
Learn more
Watch this feature in action in this demo session from Microsoft Build:
No projects, just C# with dotnet run app.cs
You’ll see how easy it is to get started, explore directives, and convert to a full project when ready.
You’ll see how easy it is to get started, explore directives, and convert to a full project when ready.
The road ahead
With dotnet run app.cs
, we’re making C# more approachable, while preserving the full power and depth of the .NET ecosystem. Whether you’re prototyping, teaching, or building production systems, this new capability helps you move faster from idea to execution.
In upcoming .NET 10 previews we’re aiming to improve the experience of working with file-based apps in VS Code, with enhnanced IntelliSense for the new file-based directives, improved performance, and support for debugging. At the command line we’re exploring support for file-based apps with multiple files, and ways to make running file-based apps faster.
Try it out today and send your feedback to GitHub as we continue to shape this experience during .NET 10 and beyond.
Very cool. Nice to not have to wrap my C# into PowerShell.
This is effectively a new script engine if it can be run against a single arbitrary file like this going forward.
Are there plans to make this into an Enlightened Script Host so we can treat it appropriately with app control policy? I’d love to not have to block this unilaterally on my endpoints.
https://learn.microsoft.com/en-us/windows/security/application-security/application-control/app-control-for-business/design/script-enforcement
humble share: https://github.com/Beej126/CS_FileBasedApp_AutoExtension addresses the lack of shebang convenience on windows
Why use the : in directives? Why not #package or #sdk?
The `#:` prefix is recognized at the language level (in C# 14) as an “ignored directive” and anything else on the line after that is ignored. This saves us from needing to define every new directive for file-based apps at the lowest level of the language and instead define that at the compiler/CLI/tooling experience level. It’s a technicality to optimize for quick progress independent of the language spec itself.
You can see the spec for ignored directives at https://github.com/dotnet/csharplang/blob/10d5a9248f9212d5fba414d44a6b9bd27525e193/proposals/ignored-directives.md
Hi Damian, great blog post, inspiring!
However, one of my colleagues reminded me about https://learn.microsoft.com/en-us/archive/msdn-magazine/2016/january/essential-net-csharp-scripting C# scripting, could you please highlight the difference between back then and now? Thanks a lot!
What an awesome feature!
This is even more convenient than python or perl, because it can use dependencies. Yet, it has much better performance and type safety.
C# is easily the most polished and well rounded language out there. Decades ahead of others (cough… java).
I can now write a shell script in C#, that is so awesome. Even more awesome, they can use System.CommandLine
I can write a full fledged minimal api in just 5-7 LOC and post it in a gist, perfect for tutorials.
I wouldn't necessarily say better performance. I did a benchmark of the simple `Console.WriteLine()` example, and the startup time of trying to run it is double that of pwsh on linux, and pwsh was already super slow to start up. I did a super quick comparison (using the `hyperfine` benchmark tool with a few warmup rounds for each test) of just printing hello world in a few languages just to show the startup/execution time of the script (which to me, as a shell script, is quite important)
<code>
I think the point was that it gets compiled and run just like any other .NET application, so after that startup period you have much better performance afterwards. Maybe a bit slower to start, but much better for anything longer running that needs to crunch some numbers.
Awesome, this is a great feature indeed. We have long wanted something like this for scripting and automation.
This is absolutely amazing! This feature is going to be incredibly helpful for new developers who want to learn .NET. No more dealing with project files and complex setup just to run a simple “Hello World” – you can jump straight into coding with C#.
I actually built a VS Code extension with autocomplete support for this feature since the tooling is still catching up.
https://marketplace.visualstudio.com/items?itemName=taraskovalenko.csharp-package-autocomplete
This is a really intriguing approach.
That said, I don’t think it’s necessary to go entirely project-free. It might be worth supporting not just PackageReference for NuGet packages, but also ProjectReference for referencing your own code. While some scenarios could be handled using local NuGet packages, I suspect that doesn’t cover all use cases—and in practice, most developers don’t use local NuGet references regularly.
Here are a few examples where direct project references could be especially useful:
1) You maintain a personal code library you'd like to reuse easily across different projects from the command line.
2) You want to analyze a project—for example,...
Support for project references is being considered and tracked in https://github.com/dotnet/sdk/issues/48746
I checked it out and the Feature Request looks good. Please support the request if you think this would be helpful.
Great to hear that. I will be sure to check it out.