Run a C# file directly using dotnet run app.cs
306 comments
·May 29, 2025jbverschoor
Kuinox
Where does your half a second number come from ? I ran a hello world to test, the overhead is 63ms.
neuecc ran benchmark on CLI libs overhead, none reach half a second: https://neuecc.medium.com/consoleappframework-v5-zero-overhe...
> Swift does a much better job at this as interprets by default
The .NET JIT is a tiered JIT, it doesn't immediatly emit code immediatly.
bouke
Not GP, but can confirm on my M3 Max using the hello world sample:
$ time dotnet run hello-world.cs > /dev/null
real 0m1.161s
user 0m0.849s
sys 0m0.122s
$ time dotnet run hello-world.cs > /dev/null
real 0m0.465s
user 0m0.401s
sys 0m0.065s
jaredpar
There are a lot of optimizations that we plan to add to this path. The intent of this preview was getting a functional version of `dotnet run app.cs` out the door. Items like startup optimization are going to be coming soon.
viraptor
If you're trying things like that in a Mac, watch out for the notary check delay https://eclecticlight.co/2025/04/30/why-some-apps-sometimes-...
It can easily add hundreds of milliseconds in various situations you can't easily control.
masfuerte
This is nuts. More than a decade ago Microsoft made a big deal of startup optimisations they had made in the .Net framework.
I had some Windows command-line apps written in C# that always took at least 0.5s to run. It was an annoying distraction. After Microsoft's improvements the same code was running in 0.2s. Still perceptible, but a great improvement. This was on a cheap laptop bought in 2009.
I'm aware that .Net is using a different runtime now, but I'm amazed that it so slow on a high-end modern laptop.
null
andix
I can also confirm the overhead on Windows 11 (it's a simple Console.WriteLine)
> Measure-Command { dotnet run run.cs }
Days : 0
Hours : 0
Minutes : 0
Seconds : 2
Milliseconds : 451
Ticks : 24511653
TotalDays : 2,836996875E-05
TotalHours : 0,00068087925
TotalMinutes : 0,040852755
TotalSeconds : 2,4511653
TotalMilliseconds : 2451,1653
First run was around 2500ms, consecutive runs around 1300ms.mystified5016
IME, windows defender hates compilers. When I run my big C++ project, Defender consumes at least 60% of the CPU. Even when exempting every relevant file, directory, and process.
Task manager doesn't show it, but process explorer shows kernel processes and the story is quite clear.
jbverschoor
I run in a Debian arm64 container. I get 500ms consistently. It is using a cached binary, because when I add —no-build, it used the previous version. I’m not sure where it stores cached versions though.
I’ll try to compare with explicitly compiling to a binary later today.
But that’s the thing. It’s a JIT, running a VM. Swift emits native code. Big difference.
Maybe I’ll add AOT compilation for dotnet then.. Strange they didnt incorporate that though.
Kuinox
What command do you use ?
> But that’s the thing. It’s a JIT, running a VM. Swift emits native code. Big difference.
It's not only a JIT, you can preJIT with R2R if you need, or precompile with NativeAOT, or i think you can fully interpret with Mono.
Edit: it looks like the issue with the dotnet cli itself, which until now was not on a 'hot path'. `dotnet help` also take half a second to show up. When running a dll directly, I think it doesn't load the cli app and just run the code necessary to start the dll.
bmacho
Tangential, but Windows Powershell kept nagging me to download PS6, so I did it, then I had to revert it to 5.1, because running a script had a ~1 second overhead. Very annoying. For one-off runs it's often the starting time what's matter, and Powershell just got worse at that. (In the end, I settled for .bat files in a cmd.exe window, chatGPT can write any of them anyway.)
PaulWaldman
Powershell 7 was released 5 years ago, was this not an option?
utf_8x
On my M2 Air:
508ms with caching, 1090ms with `--no-cache`
But as others already mentioned, optimizing this seems to be pretty high priority...
bencyoung
Dotnet is getting a fully interpreted mode in 10 or 11 so I wonder if they'll switch to that for things like this
high_na_euv
>Great, but unfortunately, even when compiled, the startup overhead is about half a second, which makes it unsuitable for many applications
So why python is this popular in this domain?
jbverschoor
Python has replaced Java in many universities, and is used in other domains than CS.
Python caches compiled versions by default. (__pycache__) and simply starts faster.
Python is more a scripting language, similar to Ruby. Swift was late to the game, and is quite strict.
*performance is a feature*
And in particular perceived performance and startup performance (“lag”)
It’s one of the reasons for the success of Chrome, MySQL, Mongodb, and many others.
ptx
A Python script can start and finish in less than 10 ms on my machine.
high_na_euv
Even with installing dependencies?
Because that's what dotnet run does
rprouse
This is still in early preview. They acknowledged the startup speed in several presentations I saw and said that they are working on speeding it up.
opendomain
It may be that they are speeding it up by keeping the .net runtime resident in memory. They used to do this with Visual Basic runtime
I ran norton utilities on my pc yesterday and noticed a new service - it was .net runtime. Please note that I am a developer so this may be just to help launch the tools.
smileybarry
That’s probably just a non-Visual Studio version of what VS already does with reusing .NET-hosting processes when you run an app in debug mode.
davidgl
If you want it to start up quickly, you can easily covert it to native code using https://learn.microsoft.com/en-us/dotnet/core/deploying/
motorest
> Great, but unfortunately, even when compiled, the startup overhead is about half a second, which makes it unsuitable for many applications.
Which applications are those? I mean, one example they showcase is launching a basic web service.
jbverschoor
I’d say anything except long running processes or scripts that take 5+ second to complete.
Cli scripts/apps should simply be responsive, just like websites and apps shouldn’t be slow to open.
Slower scripts result in distraction, which ultimately leads to hackernews being in front of your nose again.
A few of my examples:
Resizing/positioning windows using shortcut keys. Unbearable if it’s not instantaneous.
Open a terminal based on some criteria. Annoying if I have to wait.
motorest
> I’d say anything except long running processes or scripts that take 5+ second to complete.
I don't think you're presenting a valid scenario. I mean, the dotnet run file.cs workflow is suited for one-off runs, but even if you're somehow assuming that these hypothetical cold start times are impossible to optimize (big, unrealistic if) then it seems you're missing the fact that this feature also allows you to build the app and generate a stand-alone binary.
So exactly what's the problem?
alkonaut
Does this recompile each time? It should be simple to cache the binary on the hash of the input? A sub second first run followed by instant rerun seems acceptable.
wiso
Binaries are cached and next runs are much faster
jbverschoor
The dotnet run command caches. However, even with the cached version, you have a startup overhead of about half a second on my M1.
My "Swift Script Caching Compiler" compiles and caches, but will stay in interpreted mode the first three runs when you're in an interactive terminal. This allows for a faster dev-run cycle.
Koshkin
I use “tcc -run” instead. It’s instantaneous.
WuxiFingerHold
>> Install Visual Studio Code (recommended) If you’re using Visual Studio Code, install the C# Dev Kit
I wish Microsoft would just provide a LSP server for C#. Not just a half proprietary extension for VS Code.
_betty_
would they still be able to charge for it if it was an lsp?
andix
This feature is probably a big thing for .NET developer productivity. It's quite a shame, that it only came now.
There is another thing I'm really missing for .NET projects. The possibility to easily define project-specific commands. Something like "npm run <command>"
smarx007
> This feature is probably a big thing for .NET developer productivity. It's quite a shame, that it only came now.
I am using https://github.com/dotnet-script/dotnet-script without any issues. Skipping an extra step would be cool though.
andix
Is it possible to add those scripts project-scoped like with npm run? They should work for everyone who checks out the repo.
smarx007
I think everyone needs to do `dotnet tool install -g dotnet-script` before running them. This is the most annoying part where .NET 10 announcement would be really appreciated.
But then each script has an individual list of dependencies so there should be no need for further scoping like in npm (as in, the compilation of the script is always scoped behind the scenes). In this regard, both should be similar to https://docs.astral.sh/uv/guides/scripts/#declaring-script-d... which I absolutely love.
ryanbuening
Are you talking about this?: https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-r...
Inception
This would be great! I'm currently using make files to accomplish this: https://www.gnu.org/software/make/
tylerflick
I remember using LINQPad when I needed this functionality filled.
notnmeyer
you’re better off using a separate task runner like make or task.
andix
I don't think make and task are suited very well for running scripts that are not part of the build process. Something like scaffolding, or starting a dev dependency. Also it requires the developers to install additional tools to get started with the project.
mystified5016
Nah, we've been doing this for years. At least ten years ago I built myself a little console based on Roslyn that would evaluate any C# snippets I gave it. C# scripts were pretty well supported, and it was not hard to throw one together. The engine of my console was a couple dozen lines mostly just processing the string.
I'm sure the tooling is better now, though. I seem to recall visual studio and/or Rider also supporting something like this natively at the time.
donatj
It's interesting that they're actively promoting using it with a shebang. I find it pretty appealing.
Go prior to modules worked really well this way and I believe Ubuntu was using it like this, but the Go authors came out against using it as a scripting language like this.
kardianos
The author's didn't come out against it; they came out in favor of using it as a programming language first and foremost. Tools like gorun https://github.com/erning/gorun have existing for almost as long as Go has, so if you want to use Go that way, it is easy to do. They recently added in support to do this: go run github.com/kardianos/json/cmd/jsondiff@v1.0.1 Which pulls a tag and runs it directly, which is also kinda cool.
flmontpetit
I used to work for a .NET shop that randomly wrote some automation scripts in bash. The expertise to maintain them long term (and frankly, write them half-decently to begin with) simply wasn't there. Never understood why they didn't just write their tooling in C#.
Maybe this will make it seem like a more viable approach.
JamesSwift
Or just use powershell. It has some idiosyncrasies but its a pretty nice platform for scripting
shagmin
Especially for C# developers. You can use any CLR (e.g. C#) objects in powershell, for prototyping, automation, proof of concept, etc.,.
moomin
Here’s the really annoying thing with powershell: it doesn’t have a module distribution model. Like, at all. A csharp script, on the other hand, gets NuGet out of the box.
noodletheworld
It is reasonably unlikely that bash scripts are easily replaceable by powershell scripts.
Theres a fair argument that complex scripts require a complex scripting language, but you have to have a good reason to pick powershell.
Typically, on non-windows, there is not one.
Its the same “tier” as bash; the thing you use because its there and then reach past for hard things. The same reason as bash.
Theres no realistic situation I would (and Ive written a lot of powershell) go, “gee, this bash script/makefile is too big and complex, lets rewrite it in powershell!”
psyclobe
Bash is the tool that’s already there; that is always a real good reason to use it.
Dotnet is a pig with its dependencies by comparison.
crote
Sure, but these days so is Python. And you've got a dozen other languages available after a single command. You wouldn't recommend using a kitchen knife instead of a chainsaw to cut down a tree just because it's already there, would you?
Bash has a huge number of footguns, and a rather unusual syntax. It's not a language where you can safely let a junior developer tweak something in a script and expect it to go well. Using a linter like ShellCheck is essentially a hard requirement.
If you're working in a team where 99.9% of the code you're maintaining is C#, having a handful of load-bearing Bash scripts lying around is probably a Really Bad Idea. Just convert it to C# as well and save everyone a lot of trouble.
dragonwriter
> Bash is the tool that’s already there; that is always a real good reason to use it.
If you are a dotnet dev shop, it is quite likely that dotnet is also a tool that is already there the places you need automation.
Plus, its also the tool that is already there in your team’s skillset.
Ray20
>Dotnet is a pig with its dependencies by comparison.
Dotnet with all dependencies you will get in how much time? In like 6 minutes including all the preparations? So the difference between "already there" and dotnet - is 6 minutes. It's hard to imagine a case where this difference matters.
jayd16
Its trivial to install a consistent PowerShell environment on the major OSes. Not so for Bash.
Meph504
I wonder where the divide of "shebang" vs "hashbang" lands geographically and chronologically, During college and for many years in the early 90s and 2000s in the south it commonly called hashbang, didn't hear shebang until C# became a thing, I know it predates that, just never heard it before then.
nkozyra
I believe the dividing moment came with Ricky Martin circa 2000.
Lame joke aside, I only heard "shebang" prior to around that time, then "hashbang" and now I get a mix of it. Google trends indicates "shebang" always dominated.
xeromal
It's kind of the same with the # symbol. I call it the pound sign but some people call it hash.
bjoli
In my head I translate an old Swedish term: "timber yard" (from Brädgård). Everything to make interacting with other hard I guess. As a kid we also called it staket, which translates to "fence".
kevinherron
Interesting, I’ve never even heard it called “hashbang” until you just did.
California, 40yo fwiw
cheschire
I was a Unix sysadmin back in the late 90’s in east coast US and we called it a shebang when writing shell or perl scripts
Meph504
I always found it interesting as the sharp term including C# was odd because it isn't the sharp symbol, which is ♯. All of them use the # hash character, so calling it sharp always seemed odd to me, though C-Hash also doesn't roll of the tongue admittedly. It is also interesting how hash is correctly used in some places "Hash Tag" but not others.
sureglymop
This can also be done with Rusts cargo. Though it's not yet stabilized: https://rust-lang.github.io/rfcs/3424-cargo-script.html
Arnavion
The builtin subcommand is unstable, but a long time ago a dev I knew at the time maintained an external subcommand for it. https://crates.io/crates/cargo-script
Although it's old and its dependencies are old, it doesn't have a dependency on cargo (it spawns cargo as a subprocess instead of via cargo API directly), so it might still work fine with latest toolchain. I haven't tried myself.
pjmlp
I find it a pity the lack of acknowledgement of the CSX/VBX effort.
https://ttu.github.io/dotnet-script/
Or that they on the wisdom of the C# Language Runtime, decided on an incompatible approach to how F# references dependencies on its scripts.
https://learn.microsoft.com/en-us/dotnet/fsharp/tools/fsharp...
HumanOstrich
> I find it a pity the lack of acknowledgement of the CSX/VBX effort.
They do acknowledge it and other efforts:
https://devblogs.microsoft.com/dotnet/announcing-dotnet-run-...
pjmlp
On the BUILD talk I certainly don't remember that, and I am wondering if that was part of the original blog post, or a reaction to several people complaining since then.
sedatk
They added it after the reactions I believe. Source: https://bsky.app/profile/davidfowl.com/post/3lq3zfjo6gk2d
janjones
What do you mean by incompatible? If you mean syntax, that's different intentionally for clarity and also we don't want to create a new C# scripting dialect hence it isn't possible to "import" other files (that's not how C# works).
debugnik
You were already using F#'s syntax for C# NuGet references in .NET Interactive. Even NuGet itself labels this syntax "Script & Interactive" in its picker.
https://github.com/dotnet/interactive/blob/main/docs/nuget-o...
Now you've created a new dialect.
janjones
.NET interactive uses a dialect of C# - the script dialect. With file based apps, we strive to use the standard C#, so you can convert file based apps to full projects at any time.
occz
This also exists for Kotlin: https://github.com/Kotlin/kotlin-script-examples/blob/master... (note that the file extension is load bearing in this case, if you don't name it "*.main.kts", it will not work).
It's excellent for writing small scripts/prototyping where you need access to some Kotlin/JVM feature.
Ruby is still my preferred language for small scripts though - the backticks for running external programs is remarkably ergonomic
carstenhag
It's not going away entirely, but its future is also not so shiny:
https://blog.jetbrains.com/kotlin/2024/11/state-of-kotlin-sc...
pragmatic
Seems like a great PowerShell replacement.
PowerShell is the ultimate Chatgpt language. For better or worse. Usually worse as most shops end up with "write only" PowerShell scripts running all the glue/infrastructure stuff.
motorest
> Seems like a great PowerShell replacement.
It sounds like it can potentially replace way more than PowerShell. I mean, why would a .NET shop even bother with Python or any form of shell scripts if they can attach a shebang on top of an ad-hoc snippet? And does anyone need to crank out express.js for a test service if they can simply put together a ASP.NET minimal API in a script?
trog
I've been writing shell scripts in PHP for more than 20 years for this reason. Don't work on a lot of PHP sites any more but I still do most of my shell scripting in it. I think this'll be a big win for C# users once they get used to the paradigm shift.
I notice another poster said it's a bit slow but for many common use cases even half a second startup time is probably a small price to pay to be able to write in the language you're familiar with, use your standard libraries, etc.
pragmatic
Python has a lot of libraries (ai, machinelearning, data stuff, whatever) that no one has bothered porting to .net (or other platforms).
.Net is usually a second tier target but python ALWAYS has first tier support (along with java and usually go).
pjmlp
Ecosystem, people keep forgetting syntax, grammar and standard library isn't everything.
That is why even the languages I dislike and am not a big fan of, have a little place on my toolbox.
motorest
> Ecosystem, people keep forgetting syntax, grammar and standard library isn't everything.
Ecosystem means nothing if you have comparable or even better alternatives in a framework of choice.
Also, it's not like the likes of Python don't have their warts. Anyone with a cursory experience with Python is aware of all the multiplatform gotchas it has with basic things like file handing.
int_19h
I don't think ecosystem or people forgetting syntax would be an issue in a .NET shop.
replwoacause
I love PowerShell. It’s amazing the things I’ve been able to accomplish with it. Hands down my favorite language.
andix
I think you're the only one.
pjmlp
On polyglot, OS agnostic agencies, I bet there are plenty of Powershell folks.
replwoacause
BS. There are dozens of us ;)
bob1029
You can invoke C# from PS if you want:
https://learn.microsoft.com/en-us/powershell/module/microsof...
d0gsg0w00f
Oh God. I hadn't considered that windows sysadmins are likely the most prolific ChatGPT scripters. If I was still one, given the state of the MS docs, I would be guilty for sure.
pragmatic
I think most people would be shocked to know how much glue code is in powershell or bash/perl that kind of keeps everything running.
I remember looking on in horror as a QA person who was responsible for the install/deploy of some banking software scrolled through the bash/perl script that installed this thing. I think it had to be 20k+ lines of the gnarliest code I've ever seen. I was the java/.net integration guy who worked with larger customers to integrate systems.
My group insisted we should do single sign in in perl script but I couldn't get the CPAN package working. I had a prototype in java done in an afternoon. I never understood why people loved perl so much. Same with powershell. Shell scripters are a different breed.
pjmlp
On the other hand, I was once tasked to rewrite a couple of Korn shell scripts, initially written for Aix, ported to Red-Hat, into Java.
The reason being the lack of UNIX skills on the new team, and apparently it was easier to pay for the development effort.
Afterwards there were some questions about the performance decrease.
I had to patiently explain the difference between having a set of scripts orchestrating a workflow of native code applications written in C, and having the JVM do the same work, never long enough for the JIT C2 to kick in.
Hilift
> PowerShell scripts running all the glue/infrastructure stuff.
I'm pleased to report it is usually not possible to do that. It would only create a huge mess. C# is more conducive for anything more than a few methods. And there is almost no barrier. PS is great for smaller ad-hoc stuff, and it is the "script that is on every Windows platform" component similar to what VBScript was a few years ago.
jayd16
Seeing as Powershell can run .net code I wonder if this actually augments Powershell.
pjmlp
Only if you enjoy coding the low level stuff, instead of the higher level cmdlets.
wiso
You can also use shebang to run C# scripts like bash scripts https://devblogs.microsoft.com/dotnet/announcing-dotnet-run-...
max23_
I couldn't get the shebang to work by running the file directly with .net10 preview 4 sdk image.
It works if I run `dotnet run <file>`.
Update: It is working now, the file was using CRLF instead of LF.
bouke
That's great; now I can finally have scripts with type-safety. Note that on macOS the shebang either reads `#!/usr/local/share/dotnet/dotnet run` or `#!/usr/bin/env -S dotnet run`.
moogly
Kind of obsoletes NetPad, and as soon as there's debugging, LINQPad can be put out to pasture. LINQPad was instrumental for me many years ago, and I appreciate that, but that stone-age text editor is not usable for actually writing/editing code in this decade.
pragmatic
My main usecase for linqpad is database interactive stuff or exploratory code with .dump().
I see this as more of a complement to that. However I have worked at places that HATED powershell and we used linqpad for almost all scripting. It worked ok.
pletnes
Linqpad is super cool in certain .net ways, but oh man the text editor component is the worst one I interact with on a regular basis. I wish that part would be replaced by neovim or monoaco or, basically, anything. The snappiness, the table visualizations and so forth - very nice.
It’s also been unable to keep up with notebook tech for many potential use cases. I guess it’s a one man show and it shows.
Still, massive hat tip - I use Linqpad every day because it’s super useful for playing with your SQL data.
gwbas1c
I dunno about obsoleting LINQPad yet. Half the power on LINQPad is its UI; I'd like to see how comparable VSCode / VS are with dotnet run vs LINQPad.
IE: LINQPad has a great way to visualize results. If dotnet run only outputs text, or otherwise requires a lot of plugins to visualize an object graph, there will still be quite a niche for LINQPad.
In contrast, if all you're using LINQPad for is to double-check syntax, then dotnet run might be a better option. (Sometimes if I'm "in the zone" and unsure about syntax that I use infrequently, I'll write a test LINQPad script.)
pjmlp
Only if they do all GUI features and extension points, which I doubt pretty much.
Salgat
Looks like they will be adding support for VS Code, including for debugging.
"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."
pjmlp
Still, it isn't like graphically dump a data structure like in LinQPad.
moogly
There's very useful stuff there for sure, just gated behind an unfathomably deficient code editor. IMO Albahari should just embed Monaco in it.
mrcsharp
I'm excited for this one. I can see it replacing some of the powershell scripts I have in CI/CD pipelines.
As much as I like Powershell and Bash, there are some tasks that my brain is wired to solve more efficiently with a C-like syntax language and this fill that gap for me.
adzm
There is even more info in the proposal itself https://github.com/dotnet/sdk/blob/main/documentation/genera... specifically things about multiple files and more specifics of the implementation and capabilities (implicit project file etc)
adzm
Finally! Perfect for making a quick utility to use in a script. There have been third party solutions but having to install something to do this was always another obstacle / headache
motorest
I feel like top level statements were created specifically to open the door to C# scripts. The syntactic sugar of top level statements doesn't make sense in regular .NET production apps that you need to build and run, but for quick scripts they do represent important improvements in DX. Well done.
oaiey
Their argumentation for both is accessibility for learning environments. Python and node were eating the cake there with ease of first use (python file.py). And what the academia is using today's is next year's company language
pjmlp
As someone mostly focused on JVM, .NET and nodejs ecosystems, this won't cut it.
The problem with UNIX culture shops not picking up .NET has everything to do with the Microsoft stigma, and everything the management keeps doing against .NET team efforts, like VSCode vs VS tooling features, C# DevKit license, what frameworks get to be on GNU/Linux, and the current ongoing issues with FOSS on .NET and the role of .NET Foundation.
Minimal APIs and now scripting, which already existed as third party solutions (search for csx), won't sort out those issues.
They can even start by going into Azure and check why there are so many projects now chosing other languages instead of .NET, when working on the open.
This would already be the first place to promote .NET adoption.
GoblinSlayer
AFAIK, you could always dotnet run app/app.csproj since 2016. Obviously you needed dotnet sdk installed.
Incipient
Installing the full dotnet sdk was very high friction, in addition to the full csproj scaffolding. Running a single cs file is a HUGE ux improvement.
If python hadn't (nearly) caught up to c# in typing support, I'd seriously consider moving or at least running it...but as it stands, python has established itself too well for me.
motorest
> Installing the full dotnet sdk was very high friction, in addition to the full csproj scaffolding.
What's the difference between installing .NET or, say, python of node?
noworriesnate
Python typing hasn’t nearly caught up with C#. I regularly use both and c#’s type system is pragmatic and very helpful in avoiding bugs, whereas Python has no types by default and doesn’t check them by default when it does have them. It’s worse than typescript because at least typescript fails to compile if you have a type error.
GoblinSlayer
You still need full dotnet sdk, the tool merely automates full csproj scaffolding, which is then compiled with full dotnet sdk, roslyn, nuget, compiler server and everything, and allows to customize msbuild project properties with pragmas in code. The only difference is that before you had sdk+folder+my.cs+my.csproj, now you have sdk+folder+my.cs
Digit-Al
Yes, but this change now also allows you to do the same with, say, script.cs file.
Great, but unfortunately, even when compiled, the startup overhead is about half a second, which makes it unsuitable for many applications. Still I applaud it, as Shell scripting is finicky, people thend to rely on bash features, and perl is kind of over. Ruby was, and still is, my go-to language for this purpose, but I've recently migrated some scripts over to Swift.
Swift does a much better job at this as interprets by default, and a compiled version starts instantaneously. I made a transparent caching layer for your Swift cli apps.Result: instant native tools in one of the best languages out there.
Swift Script Caching Compiler (https://github.com/jrz/tools)
dotnet run doesn't need it, as it already caches the compiled version (you can disable with --no-build or inspect the binaries with --artifacts-path)