An independent frontend language. Niral is the first integration.
Explicit reactive state, gradual types and ordinary JavaScript output. NiralScript has its own parser, semantic checker and standalone compiler, with zero runtime dependencies.
Language extension
.nrs
First framework
Niral
Current stage
Experimental language
Playground.nrs
Ready
01 LANGUAGE & FRAMEWORK
Its own language. Not another component extension.
.nrs belongs to NiralScript. .niral remains Niral's component format, bringing together templates, styles and server code. They have different responsibilities.
The language core has its own directory, parser, scanner, type checker and diagnostics, with no imports from the Niral framework. Its standalone compiler emits JavaScript ES modules. A separate Niral adapter connects the language to Niral's fine-grained runtime.
Niral comes first. Other framework targets, including React for Next.js, are planned. They are not available integrations today.
02 REACTIVE BY DESIGN
State, then what follows.
state declares a reactive value. derive declares a value computed from it. Updating the count updates its doubled value through Niral's fine-grained runtime. Optional annotations check the values before JavaScript is emitted.
counter.niralTyped reactive state
<script lang="niralscript">
state count: number = 0
derive doubled: number = count * 2
</script>
<button on:click={() => count += 1}>Increase</button>
<p>{count} doubled is {doubled}</p>
Scripts can live inside a .niral component or a separate .nrs file, with named imports from other .nrs modules. NiralScript remains experimental; these results do not establish a stable language release.
Lexical scopes, unresolved-name diagnostics, initialization checks, readonly inputs and derived-effect safeguards. Named modules retain isolated scopes and original error locations.
02 / Inputs & server data
Typed inputs connect route and loader data to components. SSR and hydration preserve instance state; server code remains on the server.
03 / Collections & callbacks
Arrow functions, named and anonymous function expressions, nested binding defaults and rest, destructuring assignment, default/rest parameters, call spread and typed callbacks work with the shared semantic pipeline. For-of, for-in, conventional for and while loops support break and continue.
04 / Async & errors
Async functions and arrows, await, throw and try/catch/finally preserve return, rejection and cleanup behavior. Standalone modules support top-level await, which suspends the generated instance setup. Async RPC flows are tested in dev and production builds.
05 / Standalone compilation
A checking API and check/compile CLI emit independent ES modules, bundle named module graphs and produce source maps with original sources and imported error locations.
06 / Gradual types
Literal types, reusable aliases, interfaces, casts, type-only imports, function signatures and generic functions extend primitive, union, record and Promise contracts. Type parameter constraints apply inside function bodies, arrow functions take their own type parameters, and aliases may be recursive. Branch narrowing and opt-in strict unknown/null checks retain the gradual default.
07 / Classes & constructors
Native classes support typed constructors, generic inheritance, private members, accessors, static blocks, class expressions, decorators and instanceof. Methods integrate with reactive state, module imports and original-source diagnostics; class fields remain ordinary JavaScript properties.
Existing JavaScript, TypeScript and JSX/TSX support in Niral stays intact. NiralScript is an additional language direction, not a replacement for those workflows.
04 TYPED COLLECTIONS
Catch the wrong value. Before it reaches the array.
Statically named push, unshift, splice and fill calls now check every inserted value against a known array element type. Position arguments and required argument counts are checked too.
Simple aliases, typed record fields, annotated parameters and returns, and literal bracket method names retain these checks. Unannotated arrays remain dynamic. Unknown host values remain permissive.
Verified locally on 4 November 2026: all 81 language tests and 258 framework tests pass, including real TypeScript checking and the release gate. Classes execute in standalone and both component emitters, with inline/external dev/production HTTP, SSR, RPC privacy and original-source exception checks. Nine actual VS Code host check groups pass. Browser tests were not rerun for these changes; the hosted benchmark below predates them.
05 BEYOND COMPONENTS
A .nrs file. An ordinary JavaScript module.
The standalone compiler does not need a Niral application. Its generated ES module exposes createInstance, with isolated inputs and state, value accessors and input updates. A small included reactive runtime caches derived values; hosts can supply their own compatible runtime.
counter.nrsStandalone source
input initial: number
state count: number = initial
derive doubled: number = count * 2
export function increment(): number {
count += 1
return doubled
}
Type annotations are erased. Version 3 source maps retain original module sources. The CLI checks import boundaries and refuses to overwrite existing output files.
Explicit runtime contracts
contract<Type>(value) generates runtime checks from the same type declaration. Valid data is copied and returned with that type. Invalid data throws NRS081 with a field path, without coercion.
orders.nrsChecked data boundary
type Order = { quantity: number, note?: string }
export function readOrder(candidate: unknown): Order {
return contract<Order>(candidate)
}
const accepted = readOrder({ quantity: 2 })
Finite numbers, strings, booleans, literals, null, undefined, arrays, records, unions and concrete aliases are supported. Extra record fields and accessor-backed record fields or array elements are rejected. Extra non-index array properties are dropped. Unknown, class, function and promise schemas are compile errors. Ordinary annotations still do not validate external data.
Validation runs only at the explicit expression. Put a server-side guard before business logic; a client check cannot secure an RPC. Niral returns HTTP 400 with field errors for server contract failures. Contracts do not add integer ranges, business rules or automatic input-update validation.
06 JS / TS / NRS
Comparable execution. Measured, not assumed.
GitHub Actions ran identical function bodies in JavaScript, TypeScript and NiralScript across four workloads. All correctness checks passed. These are direct language tests, without components or reactive operations.
Microseconds per complete function call. Median of three process medians.
Runner / workload
JS
TS
NRS
Node 22 / 10,000 numbers
9.436
9.442
9.430
Node 22 / 1,000 records
1.310
1.303
1.313
Node 22 / 1,000 strings
37.066
37.346
37.632
Node 22 / 100 awaits
7.186
6.708
6.646
Node 24 / 10,000 numbers
7.476
7.469
7.420
Node 24 / 1,000 records
1.165
1.235
1.154
Node 24 / 1,000 strings
35.306
35.336
35.523
Node 24 / 100 awaits
5.716
5.779
5.768
Ubuntu 24.04 x64, TypeScript 5.7.3, 30 warmups and 12 rotated rounds per process. Compilation, module loading and instance setup are excluded from execution timings. NiralScript and TypeScript both emit JavaScript running on the same V8 engine.
The Node 22 runner used AMD EPYC 7763; Node 24 used AMD EPYC 9V74. Compare languages within each runner, not Node versions. These four workloads establish neither a universal speed winner nor complete TypeScript type-system or tooling parity.
Tested commit: 59d721b. All six hosted jobs passed: Node 22/24 language comparisons and Linux/Windows release checks. Hosted results predate the typed-array follow-up.
07 CURRENT BOUNDARIES
The limits are explicit.
Gradual annotations are not runtime validation; only explicit contract expressions generate guards. Contracts require trusted standard intrinsics and an unshadowed globalThis. Schemas are limited to 64 levels and 1024 type nodes, with 10000 validator visits per call. These limits do not sandbox proxies or impose a hard memory quota. Strict static checking is opt-in through the standalone CLI's --strict flag or the editor's niral.niralscriptStrictTypes setting. Recursive types cannot become runtime contracts, and cycles with no value boundary are still rejected. Decorators are limited to class declarations, methods, accessors and static fields, and a decorator that replaces its target is not type-checked. Classes do not yet include arbitrary computed names, new.target or TypeScript modifiers. Dynamic or detached methods and escaping aliases remain outside the complete static-checking guarantees.
The Niral VS Code extension now has dedicated .nrs highlighting, compiler diagnostics, declared-type hover, keyword and top-level completions, and local or imported definitions. These additions are in the source version; an updated extension has not been published. Incomplete code receives keyword completions; symbol navigation requires valid source.
Compile watch mode and additional framework adapters remain future work. The language is experimental, and the measured runtime results are not a claim of complete JavaScript or TypeScript compatibility.