TypeScript and React for ASP.NET Core, with a Vite-style dev loop and no Node.js toolchain
Build the frontend and the backend in one project, one process, one dotnet watch. Components update in place with their state intact; C# changes re-fetch without a reload; dotnet publish ships hashed, code-split bundles.
One project. One process. No node_modules rituals.
Nite does in .NET what Vite does in Node: it compiles your client code on request, serves dependencies through an import map, and pushes hot updates over a WebSocket. esbuild does the compiling; Nite does everything around it.
React Fast Refresh
Edit a component and it updates in place in 100 to 200 ms, keeping its state. Helpers refresh the components that use them; the entry module reloads the page.
Hot reload →Full-stack hot reload
nite watch runs dotnet watch. C# edits apply in the running app and raise a nite:server-update event, so the page re-fetches without losing state.
Single-page apps
Client/index.html plus React, served by app.MapNiteSpa() next to your API. Same origin: no CORS, no dev proxy.
Islands in Razor
Server-rendered pages with interactive React exactly where you need it: <island name="Chart" client="visible" />.
npm packages, from C#
A small npm client resolves semver, writes a lockfile and fills a normal node_modules. Private registries work from your .npmrc.
Sass, Less, Tailwind, PostCSS
The same stylesheet pipeline as Vite, CSS modules included. Tailwind finds classes in your Razor views too. Mantine works out of the box.
Stylesheets →Looks like ASP.NET Core, because it is
Three calls in Program.cs, and a Client folder next to it.
Program.cs
using Nite;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddNite();
var app = builder.Build();
app.UseNite(); // dev server under /_nite
app.MapGet("/api/todos", () => Todos.All());
app.MapStaticAssets();
app.MapNiteSpa(); // index.html for client routes
app.Run();
Client/App.tsx
import { useEffect, useState } from "react";
export function App() {
const [todos, setTodos] = useState([]);
useEffect(() => {
const load = async () =>
setTodos(await (await fetch("/api/todos")).json());
load();
// C# hot reload: re-fetch, keep state
addEventListener("nite:server-update", load);
}, []);
return <TodoList items={todos} />;
}
Already have a Vite app?
Bring it across in one command. Nite reads your lockfile (npm, Yarn, pnpm or Bun) and keeps the exact versions you run today.
Import
nite init my-app --from ../vite-app copies the client, keeps your dependencies and stylesheet tooling, and tells you what it could not bring along.
Ship
dotnet publish runs the production build: minified, code-split, content-hashed bundles in wwwroot/_nite, served precompressed by MapStaticAssets.
Understand it
No magic: a long-lived esbuild service, an import map, a module graph and a WebSocket. Read how the pieces fit before you bet a project on it.
How Nite works →Status
Nite is young (version 0.8), and one dotnet tool install away. It is honest about what it does not do: read Limits and non-goals before you start.