CLI tool
dotnet-script/dotnet-script avatar
dotnet-script/dotnet-script

dotnet-script: run C# scripts from the .NET CLI

Run C# scripts from the .NET CLI.

3,011 stars179 forksC#MIT

At a glance

What is it?
dotnet-script turns a single .csx file into a runnable C# program, with inline NuGet references and VS Code debugging. It is aimed at developers who want to try something quickly without creating a project, and the README is clear about how it installs but thin on dependency and rollback behaviour.
Who is it for?
Adopt dotnet-script if you want a single .csx file to run as a program from the command line, especially for build helpers, one-off data work, or VS Code debugging of small C# snippets. Do not adopt it if you need a reproducible, version-pinned build artifact; a normal project with dotnet run gives you that.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 26 days ago.
What is it written in?
Mainly C#, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What dotnet-script removes from the C# workflow

A normal C# program needs a project file, a folder layout, and a build step before anything executes. dotnet-script collapses that into one .csx file. The README's whole example is a single line: Console.WriteLine("Hello world!"), executed with dotnet script helloworld.csx. No .csproj, no solution, no build output directory.

The audience is narrow but real. People writing build steps, quick data transformations, or throwaway experiments in C# get a script runner instead of a project template. The README also frames the tool around editing and debugging in VS Code, with full language services support from OmniSharp, so the intended loop is edit, run, debug, repeat inside an editor rather than a terminal alone.

It is not a replacement for a compiled application. Nothing in the README suggests dotnet-script produces a deployable artifact, and the install instructions are all about the tool itself, not about publishing your script.

How a .csx file becomes a running program

The execution model is Roslyn under the hood: the repository topics list roslyn, csi and csx, and the NuGet package table lists Dotnet.Script.Core alongside Dotnet.Script.DependencyModel and Dotnet.Script.DependencyModel.Nuget. That split is the architecture in miniature. Core holds the scripting host, the dependency model packages resolve what the script needs, and the CLI packages (dotnet-script and Dotnet.Script) put a command in front of it.

A script does not need using directives for the common namespaces. The README lists them explicitly: System, System.IO, System.Collections.Generic, System.Console, System.Diagnostics, System.Dynamic, System.Linq, System.Linq.Expressions, System.Text, System.Threading.Tasks. Everything else you import yourself.

Arguments arrive through a global Args collection. Everything after a double dash is passed to the script rather than consumed by the runner, so dotnet script foo.csx -- arg1 arg2 arg3 leaves Args holding arg1, arg2 and arg3.

Dependency resolution is the part to watch. The dependency model packages exist because scripts can pull NuGet packages, and the README's package table shows Dotnet.Script.DependencyModel.Nuget is a separate package targeting netstandard2.0. That suggests resolution is pluggable rather than hard-wired, but the README does not document the resolution algorithm, cache location, or what happens when two scripts in one session disagree about a package version.

Installing dotnet-script and running a first script

The prerequisite is a .NET SDK: 8.0, 9.0 or 10.0. If you install the SDK somewhere non-default, the README points at the Microsoft documentation note about setting DOTNET_ROOT to the directory containing the dotnet executable.

The recommended install is the .NET global tool, which the README describes as working the same way on every platform.

bash
dotnet tool install -g dotnet-script

You should see the tool report that it was installed and that it can be invoked as dotnet-script. Listing installed tools confirms it:

bash
dotnet tool list -g

Removal is the matching command, dotnet tool uninstall dotnet-script -g. There are also platform-specific paths in the README (a PowerShell installer, a curl-to-bash installer for Linux and macOS, a Dockerfile under build/, and zip archives on the GitHub releases page), but the global tool is the one that stays consistent across systems.

Now write a script. Create helloworld.csx containing one line:

cs
Console.WriteLine("Hello world!");

Run it with either command name. The README states both work:

bash
dotnet script helloworld.csx
dotnet-script helloworld.csx

For anything larger, scaffold a folder instead of hand-writing files. dotnet script init creates main.csx, a .vscode/launch.json for debugging, and an omnisharp.json. Passing a filename, as in dotnet script init custom.csx, produces custom.csx instead of main.csx. One documented caveat: running init in a folder that already contains script files will not create main.csx.

On macOS and Linux you can drop the dotnet prefix entirely. Add the shebang line #!/usr/bin/env dotnet-script, mark the file executable with chmod +x foo.csx, and run it as foo.csx arg1 arg2 arg3. The README notes that a script created by dotnet script init already has the directive and the executable bit. On Windows the equivalent is dotnet script register, which registers dotnet-script in the registry as the handler for .csx files.

Where dotnet-script is the wrong tool

The strongest argument against dotnet-script is reproducibility. A project file pins the target framework, the package versions and the build settings in one place that source control tracks. A .csx file does not carry that by default, and the README does not document a lock file or a pinned dependency manifest for scripts. If two machines resolve a NuGet reference differently, nothing in the documented workflow catches it before runtime.

Startup cost is the second issue. The tool is a global tool that hosts Roslyn and a dependency model, and the README gives no performance figures at all. Anyone choosing between dotnet-script and dotnet run for a long-lived service is comparing a scripting host against a compiled binary, and the compiled binary is the one with predictable startup.

Then there is the versioning of the tool itself. The README's install output shows version 0.22.0 in its example, while the release list shows 2.0.1 as the most recent release, published on 2026-05-28. That gap between documentation and current release is a maintenance smell worth noting. The last push to the repository was on 2026-09-05, so work is ongoing, but the README text has not kept pace with the package.

Finally, the shebang and register features are platform-specific conveniences. The README documents the macOS and Linux path and the Windows registry path, and it does not describe what happens to the registry entry when you uninstall the tool. If you use dotnet script register, plan to check that state yourself.

dotnet-script against dotnet run and the C# REPL

The closest alternative is dotnet run with a console project. The difference is what you maintain. With dotnet run you commit a .csproj, restore packages through it, and get a build artifact; the compiler catches errors across the whole project before execution. With dotnet-script you commit a .csx file, and the script is compiled and executed in one step. For a 30-line utility that reads a CSV and prints a summary, the project file is overhead. For anything with tests, multiple files and a release process, the project file is the point.

Another alternative is csi, the Roslyn C# interactive tool. It is an interactive session rather than a file runner: you type expressions and get results back. dotnet-script is built for the file case, and the README's scaffolding, shebang and VS Code debugging story have no equivalent in a plain REPL session. If your workflow is exploratory typing rather than running a saved script, csi fits better. If you want a saved .csx that runs the same way every time from a shell, dotnet-script is the more direct fit.

A third option worth naming is a small console project with top-level statements, which gives you the single-file feel of a script while keeping the project file, the pinned dependencies and the build step. You trade the script runner for the compiler pipeline. That trade is usually the right one once a script stops being disposable.

Licence and the cost of staying current

dotnet-script is MIT licensed. That is permissive: you can use it, modify it and redistribute it, including in commercial settings, provided the licence notice is preserved. This is not legal advice; check the LICENSE file in the repository for the exact terms and confirm how it interacts with the NuGet packages you pull into your scripts, since those carry their own licences.

Upgrade cost is mostly a tooling concern. Because dotnet-script installs as a global tool, upgrading means reinstalling the tool, and the README documents the uninstall and list commands for exactly that reason. There is no documented side-by-side versioning for the global tool, so a team that needs two versions of dotnet-script on one machine has to manage that itself.

The version history gives a rough sense of cadence. 1.6.0 shipped on 2024-11-13, 2.0.0 on 2025-11-14, and 2.0.1 on 2026-05-28. A major version bump between 1.6.0 and 2.0.0 is the kind of change that can break scripts, and the README does not include a migration guide. If you have scripts in production, read the release notes for 2.0.0 before upgrading rather than assuming the tool command is unchanged.

One concrete thing to verify before you standardise on it: whether the target framework in the package table (net8.0, net9.0, net10.0 for the CLI packages) matches the SDK your build agents actually have. The README lists those frameworks explicitly, and a mismatch there is the failure you will hit first.

Editorial conclusion

Adopt dotnet-script if you want a single .csx file to run as a program from the command line, especially for build helpers, one-off data work, or VS Code debugging of small C# snippets. Do not adopt it if you need a reproducible, version-pinned build artifact; a normal project with dotnet run gives you that. Before committing, verify that dotnet tool install -g dotnet-script resolves on your SDK version, that your scripts still run after a tool upgrade, and how your team will pin the tool version.

Frequently asked questions

How do I install dotnet-script?

Install a .NET 8.0, 9.0 or 10.0 SDK first, then run dotnet tool install -g dotnet-script. The README also gives a PowerShell installer for Windows, a curl-to-bash installer for Linux and macOS, a Dockerfile under build/, and zip archives on the GitHub releases page.

How do I run a C# script from the command line with dotnet-script?

Save the code in a .csx file and run dotnet script helloworld.csx or dotnet-script helloworld.csx. On macOS and Linux you can instead add the shebang #!/usr/bin/env dotnet-script, mark the file executable with chmod +x, and run it directly.

How do I use dotnet-script in VS Code?

Run dotnet script init in a folder. The README states this creates main.csx along with a .vscode/launch.json launch configuration and an omnisharp.json, which is what enables debugging and language services in the editor.

What is dotnet-script?

It is a .NET CLI tool that runs C# scripts, letting you define NuGet packages inline and edit or debug them in VS Code with OmniSharp language services. Scripts are .csx files executed with dotnet script or dotnet-script.

How does dotnet-script differ from dotnet run?

dotnet run executes a console project and needs a project file, which pins the target framework and package versions. dotnet-script executes a single .csx file without a project, but the README does not document a lock file or pinned dependency manifest for scripts.

Official sources

  1. dotnet-script/dotnet-script on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/dotnet-script-dotnet-script.svg)](https://hysenlabs.com/projects/dotnet-script-dotnet-script)