Quickstart
This page gets you from a downloaded zip to a running Nova program in a
few minutes, then to a slightly bigger example that shows the two things
that make Nova different: effects in function signatures, and structured
concurrency without async/await.
Nova is a compiled language: nova build turns a .nv file into C, then
into a native binary via your system C compiler. There is no interpreter
(nova run is intentionally unsupported) — nova build and nova test
are the two commands you’ll use.
Install (Windows x64)
-
Download
nova-v0.1.0-windows-x64.zipfrom the GitHub Releases page and unzip it anywhere, e.g.C:\nova. -
In a PowerShell session, from the folder you unzipped into, dot-source the setup script (the leading
.matters — without it the environment variables vanish when the script exits):. .\setup-env.ps1This sets five environment variables (
NOVA_STD_PATH,NOVA_CG_INCLUDE,NOVA_RT_DIR,NOVA_GC_LIB_DIR,NOVA_GC_INCLUDE_DIR) that tellnova.exewhere to find the standard library and the C runtime when it isn’t running from inside the Nova monorepo, and it adds the folder toPATHfor the current session. To make this permanent, add the folder to yourPATHand set the same five variables via Settings → Environment Variables (orsetx). -
Check it worked:
nova --version # nova 0.1.0 -
You also need a C compiler on your machine — Nova compiles to C, not directly to machine code. MSVC (Visual Studio Build Tools) is detected automatically via
vcvars64.bat; Clang or GCC also work via--toolchain.
Install (Linux)
There is no prebuilt Linux archive for v0.1.0 yet — build from source.
See docs/guide/linux-build.md for the full recipe (Debian/Ubuntu
packages, Rust toolchain, git submodule update, build, smoke test);
it’s a five-minute TL;DR at the top of that page.
Hello, Nova
Every Nova project needs its own nova.toml so the compiler knows the
package root. Create a folder with two files:
nova.toml:
[package]
name = "hello"
version = "0.1.0"
hello.nv:
module hello
fn main() {
println("Hello, Nova!")
}
The module name (hello) has to match the package name for a .nv file
sitting directly at the project root — that’s a Nova convention, not a
typo.
Build and run:
nova build hello.nv
.\hello.exe
# Hello, Nova!
nova build compiles hello.nv all the way to hello.exe in one step
(Nova → C → native binary). There’s also nova check (type-check only,
no C compiler needed) and nova test (runs in-file test { ... } blocks).
A slightly bigger example: effects + concurrency
The one-liner above doesn’t show what makes Nova interesting. This does —
it’s the actual examples/mini_aggregator.nv file from the Nova
repository, ~30 lines, no networking, no UI:
module nova_examples.mini_aggregator
import std.time.duration
const BUDGET_MS int = 120 // total budget for the whole run, ms
// One "source": waits its own latency (simulated network call) and
// reports on a channel. A spawn that misses the shared deadline is
// genuinely cancelled — not left running in the background with its
// result thrown away.
fn probe(latency_ms int, deadline Monotonic) Time -> str {
ro { tx, rx } = Channel[bool].new(1)
// A `with Fail[T]` handler runs IN THE FIBER of the failing operation,
// not the installing scope's fiber (see spec/decisions/06-concurrency.md
// D441) — a bare `mut` flag captured there is a data race under M:N.
// `AtomicBool` is the synchronized alternative.
mut timed_out = AtomicBool.new(false)
with Fail[TimeoutError] = |_e| { timed_out.store(true) } {
supervised(deadline: deadline) {
spawn {
Time.sleep(latency_ms)
ro _ = tx.try_send(true)
}
}
}
if timed_out.load() {
"cancelled"
} else {
match rx.try_recv() {
Some(_) => "done"
None => "cancelled"
}
}
}
// Fan-out: all sources start AT ONCE, results collected into []str.
fn fan_out(latencies []int, deadline Monotonic) Time -> []str {
ro outcomes = parallel for i int in 0..latencies.len() {
probe(latencies[i], deadline)
}
outcomes
}
fn main() Time {
ro latencies []int = [20, 40, 60, 80, 300, 800] // ms; last two miss the budget
ro t0 Monotonic = Monotonic.now()
ro deadline Monotonic = t0 + BUDGET_MS.to_millis()
ro outcomes = fan_out(latencies, deadline)
mut done = 0
mut cancelled = 0
for i int in 0..outcomes.len() {
if outcomes[i] == "done" { done = done + 1 } else { cancelled = cancelled + 1 }
}
ro now Monotonic = Monotonic.now()
ro wall = now.elapsed_since(t0)
println("done=${done} cancelled=${cancelled} wall=${wall.millis()}ms")
}
Build and run it from a checkout of the Nova repository (it lives in
examples/, alongside a nova.toml that already declares the workspace):
cd examples
nova build mini_aggregator.nv -o mini_agg
.\mini_agg
# done=3 cancelled=3 wall=155ms
(Note: with an explicit -o name, the output file is exactly name — no
.exe is appended, even though it’s a normal PE binary on Windows. Without
-o, nova build hello.nv names the output hello.exe after the input
file.)
The exact done/cancelled split and wall time are timing-dependent —
the important part is structural: six sources start together, the two
slowest ones (300ms, 800ms) never get to finish because they exceed the
120ms shared budget, and they are actually cancelled (supervised(deadline:))
rather than left running after their result is discarded. Note what’s
not here: no async fn, no .await, no Future<T> in the return
type — Time in the function signature is the only marker that this code
touches the clock, and spawn/parallel for/supervised give you
structured concurrency without a separate “async” dialect of the language.
Where to go next
- spec/overview.ru.md — main ideas, what’s borrowed from where, tooling overview.
- examples/flagship/aggregator — the
full-sized version of the example above: a real HTTP server (via the
httppackage), a web UI with a waterfall visualization, and the sameNet Time Emiteffect signature checked by the compiler (--strict-effects). Comes with its own Dockerfile. - spec/decisions/ — the design decision log (D-numbers), the authoritative source for Nova syntax and semantics — every language feature traces back to a decision here.
- docs/dev/test-conventions.md — how
nova testworks,EXPECT_*markers, CLI flags. - docs/guide/linux-build.md — building from source on Linux/WSL2.