System requirements
glibc 2.17+ or musl
Apple Silicon or Intel
x86-64; MSVC 2022 toolchain
Clang 17+ or MSVC 2022
Installation
Download the installer script
The installer downloads a pre-built binary, verifies the checksum, and places nova in ~/.local/bin.
curl -fsSL https://nv-lang.org/install.sh | sh
Or download a release tarball and unpack manually.
Add to PATH
If ~/.local/bin is not already on your PATH, add it to your shell profile:
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
For Zsh use ~/.zshrc instead.
Verify
nova --version
Expected output
nova 0.1.0-bootstrap (2026-05-18)
Install via Homebrew
brew tap nv-lang/nova
brew install nova
Or use the installer script:
curl -fsSL https://nv-lang.org/install.sh | sh
Verify
nova --version
Expected output
nova 0.1.0-bootstrap (2026-05-18)
Install via winget
winget install NvLang.Nova
Or download the .msi installer from the GitHub Releases page.
Verify (PowerShell)
nova --version
Expected output
nova 0.1.0-bootstrap (2026-05-18)
Prerequisites
Install Rust (stable, 1.78+) and Clang 17+ (or MSVC 2022 on Windows).
rustup update stable
Clone and build
git clone https://github.com/nv-lang/nova
cd nova/compiler-codegen
cargo build --release
The compiler binary lands at target/release/nova-codegen. Add it to your PATH or symlink it as nova.
Run the test suite (optional)
cargo test --lib
Expect ~300 tests to pass. One known-failing test (fn_static_method) is a pre-existing WIP.
Your first Nova program
Create a file called hello.nv:
module hello
fn main() {
println("Hello, Nova!")
}
Compile and run:
nova run hello.nv
Output
Hello, Nova!
Effects in 30 seconds
Nova requires every side effect to be declared in the function signature. The compiler verifies that no undeclared effects are performed — at compile time, not at runtime.
// Effects appear between parameters and return type.
// Io means this function may perform I/O.
// The compiler rejects calls to Io functions from non-Io contexts.
fn greet(name str) Io -> () {
println("Hello, ${name}!")
}
fn main() {
greet("Nova")
}
Effects appear between parameters and the return type. The compiler verifies statically that every effect is declared — no hidden I/O, no surprise failures.