One developer builds, runs and ships a complete product — the UI, the data, the auth, the background
work and the deployment — from one C# codebase on one server, with SQLite as the production
database. Components are plain C# classes that return a tree of HTML from Render(): state is a
field, and an event handler is a delegate.
[Route("/counter")]
public sealed partial class Counter : Component
{
private int _count;
protected override Component? Render() =>
Button.OnClick(() => _count++)[$"Current count: {_count}"];
}curl -sSL https://rask.sh/rask.sh | shOn Windows, in PowerShell: irm https://rask.sh/rask.ps1 | iex.
Prerequisites: none. The installer adds whatever is missing — the .NET SDK, the wasm-tools
workload, Node — all under $HOME, no sudo. Already have the SDK and want only the tool?
dotnet tool install -g Rask.Cli. See installation.
Adding Rask to a project you already have is one package:
dotnet add package RaskRask is a superset, not a rival: your React, Vue, Svelte, Angular or Lit components, a real Blazor component, a TypeScript SPA or a Nuxt or Next.js app all run on it — and it builds on ASP.NET Core and EF Core rather than replacing them. Pick one per project — all four sit on the same C# back end. Islands also compose inside a Rask component tree, so those two mix freely.
C# components, server-rendered, with every state change streaming to the browser as a minimal diff
over a WebSocket. Add --wasm and the pages run in the browser instead: a WebAssembly app in the
project's Client/ folder, served by the same server that answers its API — no second project to
maintain, and message records in Shared/ compile into both halves.
rask new Shop→ Render modes · Building components
A .tsx, .vue, .svelte or Lit file as an ordinary Rask component. Derive from
ReactComponent, PreactComponent, SolidComponent, VueComponent, SvelteComponent,
AngularComponent or LitComponent, drop the front-end file beside
it, and place it anywhere the chain goes — a leaf inside a card, or a whole route. Props are declared
in C#, callbacks re-enter C# over the channel every handler already uses, and the live diff leaves the
subtree alone because its own renderer owns it. This is the one pillar Rask does not bring on its
own: add Rask.External, and Node, because your React does.
A component from npm needs no front-end file at all: name the package export in Module, and its chain
steps are generated from the package's own TypeScript into a committed ColorPicker.props.json. An
island takes children of its own runtime, so a React island can hold another.
public sealed partial class Chart : ReactComponent
{
public required IReadOnlyList<Point> Series { get; set; }
}
public sealed partial class ColorPicker : ReactComponent
{
protected override string Module => "react-colorful#HexColorPicker"; // .Color(…), .OnChange(…)
}→ Islands
A TypeScript single-page app on an ASP.NET host — React, Preact, Vue, Angular, Solid, Svelte or Lit.
The client's TypeScript is generated from your C# message records on every build, so
await rask.dispatch(getOrder({ id })) is typed and renaming a C# property breaks the build rather
than the wire.
rask new Shop --template reactNuxt, Next.js, SvelteKit, TanStack Start, SolidStart or Analog owning the whole front end — its own
routing, its own rendering, its own Node server — with Rask as the backend behind it. The two ship as
one container on one port: Rask fronts every request, supervises Node as a child process and
forwards to it over loopback, so ASP.NET auth, rate limiting, logging and health stay in front of the
framework and the session has one owner. The client was imported from the framework's own creator —
nuxi, create-next-app, sv, @tanstack/cli — and is committed, so rask new writes it with no
network and no Node, plus a node-server build and a dev proxy.
scripts/refresh-templates.sh is how a newer upstream gets in. Add Rask.Meta.Hosting, and Node at
runtime, because the framework needs it.
rask new Shop --template nuxtrask dev # run it — the first migration is already applied
rask db add AddProducts && rask db update # after you change the model
rask deploy --host root@box --domain shop.example.com # bare box → Docker + auto-HTTPS, zero-downtimeRun rask with no arguments for a wizard.
Auth, jobs, mail, cache, events and file storage are on by default, and every one of them keeps its records in the app's own SQLite database (an upload's bytes go to disk or a bucket) — no broker, no Redis, no second service to run. A fresh app can register somebody, sign them in, confirm their address and reset their password with no auth code written.
- Auth — accounts out of the box: register, sign in, sign out, route guards, and the first account to register is the administrator.
- Background jobs — enqueued, delayed and recurring work on your database, at-least-once with exponential backoff.
- Email — transactional mail queued in the same database and delivered over SMTP off the request thread; bodies are Rask components.
- Outbox — domain events committed in the same transaction as your data and relayed at-least-once, with no message broker.
- Cache — the standard
IDistributedCacheplus a typedICachewithGetOrAddAsync. - Data · CQRS — audit stamps, soft delete, optimistic concurrency and domain events on EF Core, and a source-generated, reflection-free mediator.
- Production SQLite — WAL and busy-timeout pragmas, continuous Litestream backup, scheduled snapshots.
- Logging — the
ILoggerpipeline kept in a SQLite file of its own, with retention by age and row count. - Operator console —
/_rask: queue depth, dead letters and the errors behind them, cache contents and a log tail, behind an authorization policy. - PWA · Web Push — installable, offline apps, and push sent from your backend on your own VAPID keys.
- File storage — uploads on disk, in S3-compatible storage or in Azure Blob, with a row per file on your database and public or expiring links.
- Deploy —
rask deploytakes a bare VPS to a live HTTPS site with zero-downtime swaps.
They build on the standard .NET pieces — EF Core, hosted services, ILogger, IDistributedCache,
ASP.NET Core authentication — so adding one is a package reference, not a new stack to learn or a new
box to operate.
| The One Person Framework | The doctrine, the batteries, and why one server beats a rented stack |
| Getting started · Tutorial | The UI end to end; then a whole product, one pillar per chapter |
| Building components · Routing · Forms | How markup is written, the URLs it answers, and the form pipeline |
The rask CLI · Deployment |
new / dev / db / deploy; Docker over SSH, auto-HTTPS, bare-VPS setup |
| DevTools | A panel in the page while you develop: the wire traffic and the component tree with props. Gone from every Release build |
| Data · CQRS · Auth · Jobs · File storage · SQLite | The database-backed pillars |
| HTTP APIs | API controllers and minimal APIs, hosted properly and called through a client generated from them |
| Migrating from Blazor · Diagnostics | Day-to-day differences side by side; every RASK build error and its fix |
The full index is docs/, and the other packages are listed in
NUGET.md. To see it running, rask.sh is a Rask app — landing page,
guides and every live demo — built from src/Rask.Site.
Rask is the Norwegian/Danish/Swedish word for fast.
Rask is pre-1.0; APIs may change between minor versions. Every package ships for .NET 10 and .NET 11 (net10.0 / net11.0 for
ASP.NET hosts, net10.0-browser / net11.0-browser for WASM); .NET 10 is the LTS release and the
default rask new scaffolds, and --framework net11.0 opts a new app into .NET 11. Production use at your own discretion — issues and PRs welcome.
MIT.