Library / SDK
reactjs/React.NET avatar
reactjs/React.NET

ReactJS.NET: compiling JSX without a Node process

.NET library for JSX compilation and server-side rendering of React components

2,319 stars898 forksC#MIT

At a glance

What is it?
ReactJS.NET is a C# library that compiles JSX and renders React components on the server, aimed at ASP.NET teams who do not want a JavaScript toolchain in the request path. The on-the-fly Babel path is its main idea and its main cost.
Who is it for?
Adopt ReactJS.NET when an ASP.NET application has to produce the first render on the server and the team refuses to add Node to the build pipeline. Leave it alone for a single page application that already ships a compiled bundle, because there the on-the-fly compiler competes with bundling you have.
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?
Activity is slowing. The repository last received commits 7 months 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 October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Babel compiled inside the process, not spawned from it

The central claim in the README is that JSX becomes JavaScript while the application runs, without a separate JavaScript toolchain on the machine. The listed portability claim is the evidence: ReactJS.NET "Runs on Windows, OS X and Linux" via .NET Core and ChakraCore, and ChakraCore is Microsoft's JavaScript engine. Compilation therefore happens inside the managed process, not by shelling out to npm-installed Babel.

That design removes a whole class of deployment problem. There is no Node version to pin on a build server, no npm tree to restore before an ASP.NET publish, and no Babel binary whose path differs between a developer's laptop and a container. A deployment becomes an ordinary .NET publish.

The cost is that the compiler runs on every cold path that needs a transform, inside the same process that is serving requests. Nothing in the README sets a bound on that work or describes a cache lifetime for compiled output, so a hot endpoint that transforms on demand will pay for it on every hit rather than once.

Four bundling routes behind one JSX story

The on-the-fly compiler is one mode of two. The README also lists JSX compilation through established minification and combination libraries, and names four of them:

- ASP.NET Bundling and Minification - Cassette - Webpack - MSBuild

Each is documented on its own page under the bundling section of the site. Webpack and MSBuild are build-time routes that emit JavaScript files ahead of the request; ASP.NET Bundling and Minification and Cassette are asset-pipeline routes that stay inside the ASP.NET application. Picking one means picking where the compile step lives, not merely which minifier runs.

The choice is not cosmetic. Under the on-the-fly mode the transform happens per request on a cold path, and nothing in the README describes a cache lifetime for compiled output. Under Webpack or MSBuild the same JSX is compiled once at build time and the request only serves a finished file.

A template you must install before you can generate it

Starting a project takes three commands, and the order matters more than usual. The first line installs a template package from NuGet, so nothing to generate exists until it finishes.

code
dotnet new -i React.Template
dotnet new reactnet-vanilla
dotnet run

The second line picks the `reactnet-vanilla` flavour, which serves a single JSX file, and the third runs it. A close reading catches a constraint hidden in that sequence: teams planning on `require` or `import` module syntax are pointed at a different template, `reactnet-webpack`, and the two templates do not solve the same problem. Choosing the vanilla one and later adding modules means starting over.

Note also that no version is pinned for the install, so what `dotnet new -i React.Template` retrieves is whatever the feed currently serves.

Html.React is the seam, and IRenderFunctions is the only hook

Server-side rendering is exposed through an HTML helper named `Html.React`, and the README gives exactly one extension point for custom JavaScript: implement `IRenderFunctions` and pass your instance to `Html.React`. The interface file lives at `src/React.Core/IRenderFunctions.cs` and the helper extension at `src/React.AspNet/HtmlHelperExtensions.cs`, so the renderer sits in the core package and the ASP.NET glue sits in the web package.

Around that seam sit three named integrations. CSS-in-JS libraries are supported, which matters because styled-components and its relatives emit their styles during the first render and the result must reach the HTML rather than wait for hydration. React Router is supported so the server can emit the same route the client will hydrate. React Helmet is supported so head tags computed in JavaScript land in the document head.

The gap is scope. `IRenderFunctions` is one interface and no other registration point is named anywhere in the source tree, so anything that needs to alter the emitted script tags or the hydration attributes has to fit that single contract or drop to custom JavaScript. No hook for altering the surrounding HTML attributes is described either.

A first build that cannot happen inside the IDE

Contributing to ReactJS.NET has a sequencing constraint that clones of many .NET libraries do not have. Your first build always has to run through `dev-build.bat`, because that script generates files the build requires, and `SharedAssemblyVersionInfo.cs` is named as one of them. Only after that run can you open `React.sln` in Visual Studio and compile from the IDE.

A second constraint sits alongside it: the build needs Git installed. Removing the `GitVersion` task from `build.proj` drops that requirement. That is a real trade-off rather than a convenience. GitVersion derives the assembly version from Git history, so dropping the task leaves version stamping to whatever the rest of the build produces, and the README does not describe what that produces.

The tree at the repository root shows the shape of this build: `dev-build.bat` and `dev-build-push.bat` as Windows batch entry points, alongside `runs-msbuild.bat`, `build.proj`, `azure-pipelines.yml` and `renovate.json`. Continuous integration runs on Azure Pipelines, and the four batch files split day to day work from shipping builds in the same way their names indicate.

Versioning by Git history, dependencies by Renovate

Two automation systems sit side by side in a repository with no package.json at the top level. `build.proj` invokes `GitVersion`, which reads tags to decide assembly versions. `renovate.json` configures Renovate to open dependency update changes. One numbers the build from history, the other patches the declared dependencies, and neither one is Node based.

`azure-pipelines.yml` sits between them as the place where the batch files are invoked. `netlify.toml` covers the documentation site, and `site/` is that site. `.gitmodules` at the root means the checkout is not self-contained: something in the build arrives as a submodule.

None of this is documented in prose in the README, which stops after the contribution paragraph. The arrangement has one practical consequence worth stating: a fork that wants a different versioning scheme is editing `build.proj`, and a fork that wants a different dependency cadence is editing `renovate.json`. Neither choice requires understanding the JSX pipeline.

One package family, two generations of ASP.NET

Support covers both ASP.NET 4.0/4.5 and ASP.NET Core. Carrying two generations of the web framework in one library explains the directory layout: `src/` holds more than one web target, with `React.Core` shared between them, and the `React.Core` package is the one carrying the NuGet version and download badges at the top of the README.

The runtime story follows the same split. The .NET Core and ChakraCore line covers the modern target. The classic ASP.NET target predates ChakraCore on most machines, so the documentation pages are split accordingly, with separate pages for the ASP.NET Core getting started path and the ASP.NET Core tutorial, and a separate page for ChakraCore.

What the README does not say is which features are equal across the two. CSS-in-JS, React Router and React Helmet support are listed without a per-target qualification, and the bundling options are listed as a flat set of four. Anyone maintaining an older ASP.NET Framework application has to confirm on the documentation pages which of those apply there.

Six years between the newest tag and the newest commit

The maintenance record has an odd shape, and the gap is the first thing to check. The most recent push to the repository was on 2026-03-02, while the most recent published version is 5.2, dated 2020-06-19, after 5.1.2 in November 2019 and 5.0.0 in July 2019. Code is landing in the repository without a matching published package version.

The consequences are concrete. The `React.Template` install in the quick start pulls whatever the package feed currently serves, which need not match `main`, and nothing in the README pins a version for the template. Contributors following the `dev-build.bat` route are building from the tip of `main`, not from the 5.2 sources.

Two facts limit how far that reading goes. The repository is not archived, and the push on 2026-03-02 is within six months of the present, so the source tree is receiving work. Whether a consumer should expect a published package that contains it is a separate question the repository does not answer on its own.

Editorial conclusion

Adopt ReactJS.NET when an ASP.NET application has to produce the first render on the server and the team refuses to add Node to the build pipeline. Leave it alone for a single page application that already ships a compiled bundle, because there the on-the-fly compiler competes with bundling you have. Verify three things first: which of the four bundling routes your target framework supports, whether the package the template install pulls from NuGet actually contains the commit dated 2026-03-02, and whether your CSS-in-JS and React Router libraries still fit the IRenderFunctions contract.

Frequently asked questions

Does ReactJS.NET need Node.js installed to compile JSX?

The README states that JSX compiles on the fly via Babel and that the library runs on Windows, OS X and Linux via .NET Core and ChakraCore, so no Node install is listed as a prerequisite for the runtime path. It does not document any npm step for that path.

Which bundling options does ReactJS.NET support for JSX compilation?

Four are named: ASP.NET Bundling and Minification, Cassette, Webpack and MSBuild. Each has its own page under the bundling section of the documentation site.

How do I add custom JavaScript to server-side rendering in ReactJS.NET?

Implement `IRenderFunctions` from `src/React.Core/IRenderFunctions.cs` and pass the instance to `Html.React`, which is the extension in `src/React.AspNet/HtmlHelperExtensions.cs`. That is the single customisation hook the README names.

Why does my first build of ReactJS.NET fail in Visual Studio?

Your first build has to run through `dev-build.bat`, because that script generates files the build needs, such as `SharedAssemblyVersionInfo.cs`. After it completes you can open `React.sln` and compile from Visual Studio directly.

Can I build ReactJS.NET without Git installed?

Yes, at the cost of version stamping. Remove the `GitVersion` task from `build.proj` and the Git requirement goes away, since that task is what reads Git history for the assembly version.

Which ASP.NET versions can host ReactJS.NET?

Both ASP.NET 4.0/4.5 and ASP.NET Core are listed as supported, with separate getting started and tutorial pages for the ASP.NET Core path. The README does not break down which rendering features apply to the framework target.

Official sources

  1. License: MIT
  2. Project website
  3. reactjs/React.NET on GitHub
  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/reactjs-react-net.svg)](https://hysenlabs.com/projects/reactjs-react-net)

Was this useful?