C# / .NET Good First Issues

Leonid Bugaev
|
(Updated August 31, 2026)
|
8 min read
csharp dotnet beginners good-first-issue contributing

The C# evening that fails is not the missing [Fact]. It is dotnet restore dying because the README still shows a PackageReference the feed never shipped, or a pack README that nuget.org never received. Get restore green on the default branch before you open the .cs the issue named.

Generic hunting: how to find good first issues. Multi-language picking: best open source projects for beginners. Merge checks: how to pick an issue that will get merged. This URL is the C# filter. F# is a different language.

Open the C# hub

C# hub

Labeled good-first and help-wanted issues on active GitHub repos whose language is C#. The slug is /language/csharp, not /language/c#. On 2026-08-31: about 1,350 labeled issues at 10+ stars. Snapshot. It moves.

Writing F#, not C#? That is a different hub: F# hub. Separate feed. Do not mix them. An F# ticket will not fix a C# .csproj restore sample, and a C# xUnit hunk does not belong on an F# project.

Not writing C#? The homepage is the language switch.

Read the body. Skip stale, claimed, and repos that have not merged lately. I am not listing famous projects. A leftover label on a well-known name is still leftover. The feed is the hub, ticket by ticket.

NuGet: metadata and a sample that actually restores

In C# / .NET the real first sitting is often dotnet restore. A README still shows Install-Package Foo against an id that shipped as Foo.Core. The sample .csproj still pins a PackageReference the feed dropped. <Description> in the nuspec is empty so nuget.org shows a blank. The issue already named that hole.

Shapes that merge:

Done is: a newcomer can follow that page, restore, and get the same packages the project ships. Done is not a souvenir version bump, a Directory.Packages.props rewrite, or migrating packages.config because you like it.

Do not bump package versions “while you are here.” Do not bump the SDK, the TargetFramework, or a central package version as a drive-by. Version bumps review as policy and stall the restore fix.

CONTRIBUTING will name dotnet restore and dotnet test. Run them on the default branch first. If restore cannot boot on your machine, pick another ticket. Debugging their NuGet feed is two projects.

A green dotnet restore on main is the gate. The code change comes after.

xUnit: one test next to the method

The mergeable first C# PR is usually one xUnit test beside the method the issue named. Same project. Same test project they already use. [Fact] if it is one case. [Theory] only if the ticket named the rows.

If the repo already runs NUnit or MSTest, use that runner. Match what dotnet test already executes. Do not add a second framework.

That is the job. It is not:

FooTests next to Foo. One method. Assert the behavior the issue described. Run that test class, not the universe, unless CONTRIBUTING says otherwise.

If the project tests with xUnit, you test with xUnit. Do not “improve” the harness on issue one.

XML docs: one public API, not the assembly

C# XML docs (/// <summary>) look cheap. A whole-assembly pass is not.

The first merge is docs on one public API the ticket named. The method, the type, the parameter the issue quoted. dotnet build with GenerateDocumentationFile should stop warning on that member.

Out of scope:

If the issue is “add XML docs to Foo.Bar(Baz)”, that is the PR. If you also “fixed” twenty neighbors, reviewers read a docs dump. They will ask you to revert.

IntelliSense on that member is the proof. Not a docs site.

EditorConfig and dotnet format: the hunk

dotnet format will always have opinions. .editorconfig will too. That is not an invitation.

A first-time dotnet format on the solution rewrites files nobody asked you to touch. Maintainers read it as a style crusade. They close it, or they make you revert 90% of the diff, which is the same delay.

Rules:

A formatted test is hygiene. A solution-wide reformat is a closed PR.

Not runtime, not BCL, not ASP.NET Core internals

Skip runtime bring-up, BCL types the rest of the tree trusts, and ASP.NET Core internals on purpose. Hosting pipeline guts, DI container internals, System.* contracts, NativeAOT edges — those review like architecture. A good first issue badge on them is a request for help, not a size.

Your first merge should be a leaf: the restore sample, one xUnit next to the method, XML docs on the public API the ticket named, a small library — not the framework core.

After you have a merge in that repo and have watched how they review internals, issue two can move inward. Not before.

I am not listing famous runtime or ASP.NET repos. Filter the C# hub and judge the file, not the brand.

Ship one ticket

  1. Filter on the C# hub. That slug is /language/csharp, not /language/c#. F# is the F# hub — different language. Drop stale and claimed threads. Confirm recent merged PRs.
  2. Read CONTRIBUTING.md for dotnet restore / dotnet test and format. Get restore green on the default branch.
  3. Comment on one issue. Do not reserve five.
  4. Keep the diff on the ticket. One xUnit (or their runner) next to the method, or XML docs on the named API, or a restore sample. dotnet format only what you touched. No package-version bump. Link Fixes #123. Say which test command you ran. Stay for review.

Git mechanics: first pull request guide. Week-1 map: how to contribute to open source.

FAQ

Is a NuGet README sample that actually restores a real first PR?

Yes. Package metadata and a restore snippet that dotnet restore can follow is a real merge. Bumping package versions, the SDK, or TargetFramework as a souvenir is not.

Should I add NUnit or MSTest if the project already uses xUnit?

No. One test next to the method, in the runner they already have. If that is xUnit, write xUnit. If that is NUnit or MSTest, use that. Do not add a second framework as a side quest.

Can I XML-doc the whole assembly while I am here?

No. Document the one public API the ticket named. A whole-assembly <summary> pass is a docs dump. Reviewers close it or make you revert.

Should I run dotnet format on the whole solution?

No. Format the hunk you touched. A whole-solution dotnet format or an EditorConfig rewrite of files you did not need is a style PR. Leave .editorconfig alone unless that file is the ticket. If CI formats the tree, let CI.

Where do I find live C# good first issues?

On the C# hub. The slug is /language/csharp, not /language/c#. F# is a different language: the F# hub. Filter, skip stale and claimed threads. Read CONTRIBUTING for restore, test, and format. Other languages: the homepage.

Start here

Open the C# hub. Pick one unclaimed ticket that is a NuGet sample that restores, one xUnit (or their runner) next to the method, or XML docs on one public API — not runtime / BCL / ASP.NET Core internals, not a whole-solution dotnet format. Comment once, format only what you touched, keep the diff on that job, and stay for review. Writing F#, not C#? The F# hub is a different language. Not writing C# tonight? The homepage is the language switch.

Back to all articles Find projects that need your help