Rask
Rask
v0.23.1-alpha.0.413

The full-stack .NET web framework

The whole stack,
in C#.

Data, queries, auth, background jobs, email, realtime and deploy — one framework and one C# codebase, for a team of one or fifty.

Declare an aggregate, query it from a page, ship it with rask deploy. The UI is C# components, live over a WebSocket or running in WebAssembly — with React, Vue or Angular components inside them as islands.

.NET 10MITServer · WASMSQLite · Postgres · SQL Server
// A table, its columns and a generated read face.
// No DbSet, no configuration class, no registration.
public sealed class Product
    : Aggregate<Guid, Timestamps, Versioned, Model, Deletable>
{
    [MaxLength(200)]
    public string Name { get; private set; } = "";

    [Range(0, 1_000_000)]
    public decimal Price { get; private set; }

    public bool InStock { get; private set; } = true;
}

The whole stack · one codebase

Everything behind the page, already built.

Data, queries, auth, jobs, email, cache, files, realtime, tenants and search ship with the framework and ride your app's own database — no broker to stand up, no Redis to run, and a Redis you already have plugs in as the cache. They are built on the standard .NET pieces — EF Core, hosted services, ILogger, IDistributedCache — so each is a package reference, not a new box to operate.

Data & aggregates

Derive from Aggregate<Guid, Timestamps, Versioned> and the class is the table — its base names what it carries (timestamps, a version, soft delete, a tenant), plus a generated read face to query. EF Core on SQLite, PostgreSQL or SQL Server.

Queries & commands

QueryClient.Query(…) in Render — cached, deduplicated, refetched after a write. Source-generated CQRS underneath, and the same call from the browser or the server.

Auth, on by default

Register, sign in, passkeys and a session row per device with no auth code — sign-in pages scaffolded into your app, the first account made admin. OIDC providers when you need them.

Background jobs

Enqueued, delayed and recurring work stored in your database and run by a hosted worker — at-least-once, with exponential backoff.

Transactional email

Mail queued on the same database and delivered over SMTP off the request thread; the bodies are components.

Transactional outbox

Each handler chooses: in memory at once, or durable — its outbox row committed in the same transaction as the data, then run at-least-once. Crash-safe, no message broker.

Cache

A database-backed IDistributedCache plus Cache.Remember(key, load).For(10.Minutes) — or point it at the Redis you already run.

File storage

Rask.Storage keeps uploads on disk, in S3-compatible storage or in Azure Blob, with a row per file — public or expiring links, and the content type sniffed from the bytes.

Realtime subscriptions

QueryClient.Subscribe<OrderPlaced>() in a page, and every OrderPlaced published afterwards re-renders it — narrowed by a record, opened only through a policy.

Web Push

Send Web Push from your backend on your own VAPID keys (RFC 8292/8291) — zero external dependencies.

Multi-tenancy

PerTenant on a table adds the tenant column, the query filter and tenant-prefixed indexes; Tenant.Across() is the one greppable way around them.

Full-text search

Product.Search("red anvil") — ranked, best match first, with highlights and snippets, on SQLite FTS5 or PostgreSQL.

The operator console

A dashboard at /_rask over every battery's own table — queue depth, dead letters and the errors behind them, cache, a log tail, SQLite status. Fail-closed behind an authorization policy.

One CLI

rask new scaffolds a working app with data, auth and the batteries wired; rask dev runs it with hot reload; rask db migrates and backs up.

One-command deploy

rask deploy takes a bare VPS to a live HTTPS site — Docker, a non-root deploy user, firewall + SSH hardening, and zero-downtime swaps.

Frontend · C# components

The UI is C# too.

Components are plain C# classes — no .razor, no JavaScript, no second language. Roslyn source generators build each one's chain and typed route URLs, trim-safe and reflection-free.

Counter.cs
[Route("/counter")]
public sealed partial class Counter : Component
{
    private int _count;

    protected override Component? Render() =>
        Button.OnClick(() => _count++)[$"Current count: {_count}"];
}
running · /counter

Current count

0
Each click ships a ~41-byte diff — not a re-render of the page.
Components as a chain

A chain surface per component — Card.Title(…) — that demands what the component can't do without, plus type-safe Routes.* URL builders. Rename a route, break the build — never a dead link.

Forms & validation

Form.Model(m) with two-way binding and inline .Validate(…) rules, sync or async. DataAnnotations and FluentValidation work too, checked again on the server.

Scoped CSS & TypeScript

Drop a sibling {Component}.css/.ts. Auto-scoped, no leaks — a mismatch is a build error. Tailwind v4 compiles from dotnet build, with no npm and no config file.

A typed UI kit

Every daisyUI component as a C# component — Ui.Button, Ui.DataGrid, Ui.Tree — accessible and themed, with no npm and no Tailwind config.

6 typed browser APIs

IndexedDB, passkeys, WebRTC with its signaling, view transitions and background sync as awaitable C# — and every other web API straight from MDN through Rask.Web. Serial, USB, HID and Bluetooth pickers are WebAssembly's.

Installable PWA

A typed manifest, a default service worker, offline and background sync — the wasm template is installable out of the box.

C# Hot Reload

Edit Render() or scoped css/js under rask dev and it re-renders live — the closest a compiled framework gets to a no-build loop.

Prerendering

A WASM app renders every route to real HTML at publish, so a crawler is served the page rather than a spinner. On the server, every page is live, and its first response waits for its data.

93 compile-time diagnostics

A missing required step, a public setter on an aggregate, an image with no alt text — each is a RASK error at build time that names the fix, several with an IDE quick-fix.

One component model · every host

Write it once. Ship it where you need it.

The identical C# component runs unchanged across every host — you choose the runtime per project, not per component.

Three front ends · one back end

Bring your own components — or don't.

Rask is a superset, not a rival: React, Preact, Solid, Vue, Svelte, Angular and Lit components, and real Blazor components, run inside C# pages as islands, against the same C# back end — mixed freely in one component tree.

Prerequisite · .NET 10 SDK

Up and running in one command.

ASP.NET live-server app, batteries included
curl -sSL https://rask.sh/rask.sh | sh
rask new MyApp
cd MyApp && rask dev

Nothing preinstalled — it adds the .NET SDK too, under $HOME, no sudo. Windows: irm https://rask.sh/rask.ps1 | iex.

Accounts and cookie sign-in are already on · full path in the getting-started guide.