Playwright in a single file dotnet app
One of the recent additions in .NET is that you can now have single file projects. In this article we’ll explore how to use Playwright in such file.

TL;DR: Full example at the end of this page.
Why?
More and more I use Playwright not only for testing but also for small automation scripts and to quickly make demos using it’s handy built-in recorder. Before .NET 10 that would required a C# project, a directory with a csproj file a cs file and the Playwright package installed.
How does dotnet run apps.cs work?
It’s straightforward, create a single file like below and run it using dotnet run app.cs, or whatever name you gave the file.
Console.WriteLine("Hello World!");
For simplicity you can also omit run and just type dotnet app.cs.
Using Playwright in a single file app
To use Playwirght you will nee the package installed though. Since there is not csproj there now is a different way to do so. Use #:package Microsoft.Playwright@1.56.0 to specify the package and version.
#:package Microsoft.Playwright@1.56.0
using Microsoft.Playwright;
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync(
new BrowserTypeLaunchOptions { Headless = false });
But above code will not run. It will result in a ` System.InvalidOperationException because Reflection-based serialization has been disabled for this applicatio`. The reason is that Playwright uses reflection to serialize the browser object and that by default AOT is enabled for single files apps. We need one more line to disable AOT:
#:property PublishAot=false
#:package Microsoft.Playwright@1.56.0
using Microsoft.Playwright;
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync(
new BrowserTypeLaunchOptions { Headless = false });
Now is you did not have Playwright 1.56.0 installed before you will get thi error:
Unhandled exception. Microsoft.Playwright.PlaywrightException: Executable doesn't exist at /Users/jhendriks/Library/Caches/ms-playwright/chromium-1194/chrome-mac/Chromium.app/Contents/MacOS/Chromium
╔════════════════════════════════════════════════════════════╗
║ Looks like Playwright was just installed or updated. ║
║ Please run the following command to download new browsers: ║
║ ║
║ pwsh bin/Debug/netX/playwright.ps1 install ║
║ ║
║ <3 Playwright Team ║
╚════════════════════════════════════════════════════════════╝
at Microsoft.Playwright.Transport.Connection.InnerSendMessageToServerAsync[T](ChannelOwner object, String method, Dictionary`2 dictionary, Boolean keepNulls) in /_/src/Playwright/Transport/Connection.cs:line 201
at Microsoft.Playwright.Transport.Connection.WrapApiCallAsync[T](Func`1 action, Boolean isInternal, String title) in /_/src/Playwright/Transport/Connection.cs:line 499
at Microsoft.Playwright.Core.BrowserType.LaunchAsync(BrowserTypeLaunchOptions options) in /_/src/Playwright/Core/BrowserType.cs:line 56
at Program.<Main>$(String[] args)
at Program.<Main>(String[] args)
Luckily Playwright also allows you to install browsers through the API:
#:property PublishAot=false
#:package Microsoft.Playwright@1.56.0
using Microsoft.Playwright;
var exitCode = Microsoft.Playwright.Program.Main(new[] { "install" });
if (exitCode != 0)
throw new Exception("Failed to install playwright");
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync(
new BrowserTypeLaunchOptions { Headless = false });
Then finally you start adding your Playwright instructions.
Full example
Here is an example on who you can use the recorder easily create a video of your browser interaction: