Skip to content
The book

Getting started#

Install#

A released toolchain brings its own linker, so you need nothing else: no Visual Studio Build Tools, Xcode or C compiler. Optionally, LLVM/clang 16 or newer makes --release builds faster programs.

Install the latest release. On Linux and macOS:

Terminal
curl -fsSL https://github.com/velt-lang/velt/releases/latest/download/get-velt.sh | sh

On Windows, in PowerShell:

PowerShell
irm https://github.com/velt-lang/velt/releases/latest/download/get-velt.ps1 | iex

The installer puts the toolchain in ~/.velt/toolchains/<version> and the velt launcher in ~/.velt/bin, which it adds to your PATH (on Windows %LOCALAPPDATA%\velt\toolchains\<version> and %LOCALAPPDATA%\velt\bin, added to your user Path). Several versions can be installed side by side; each package runs the one its manifest names (below). To uninstall, delete ~/.velt (%LOCALAPPDATA%\velt) and remove its bin directory from your PATH. Open a new terminal and check the installation:

Terminal
velt doctor

velt doctor checks the toolchain and builds and runs a hello world. Installer options and other platforms: Platforms and installation.

From source#

Building Velt yourself needs Rust (stable), from rustup.rs, and a system linker, which a build from source uses: the Build Tools for Visual Studio ("Desktop development with C++") on Windows, build-essential (or gcc) on Linux, the Xcode command line tools on macOS.

Terminal
git clone https://github.com/velt-lang/velt
cd velt
cargo build --release -p veltc -p velt_rt
./target/release/velt doctor

Put target/release on your PATH, or build a self-contained toolchain directory with scripts/package.sh (Linux, macOS) or scripts/package.ps1 (Windows) and install it with the matching install script, beside released versions (Platforms and installation).

Your first program#

Create hello.vlt:

ts
const name = "world";
console.log(`Hello, ${name}!`);
Terminal
velt run hello.vlt              # debug build (Cranelift, compiles fast), then run
velt run --release hello.vlt    # optimized build (LLVM -O3 when clang is installed)
velt build hello.vlt            # just build: ./target/velt/hello
Text
$ velt run hello.vlt
Hello, world!

A program runs its file's top-level statements in order, as Node runs a script; top-level await works too. There is no main to write (Scripts). The result is a native executable with no runtime to install: target/velt/hello (.exe on Windows) runs on its own.

A project#

Terminal
velt new hello
cd hello
velt run
Text
     Created binary package `hello` (app template)

Next: cd hello && velt run && velt test
Text
$ velt run
Hello, world!

velt new creates a package:

Text
hello/
  package.vlt               the manifest: name, version, the velt version, dependencies
  src/main.vlt              the entry point: `velt run` builds and runs it
  src/greet.vlt             a module, imported by main and by the tests
  tests/greet.test.vlt      tests: every exported `test_*` function
  README.md
  .gitignore                ignores target/, where builds go
  .gitattributes            makes GitHub highlight .vlt files (as TypeScript)
  .vscode/launch.json       F5 builds and debugs the program in VS Code
  .vscode/extensions.json   recommends the Velt and CodeLLDB extensions
ts
import type { Package } from "velt/package";

export const pkg: Package = { name: "hello", version: "0.1.0", velt: "0.5" };

The manifest is written in Velt but holds only data: velt reads it without running it (package.vlt). velt: "0.5" records the velt version the package was made with: the velt command runs that version, so installing a newer velt doesn't change how the package builds (velt toolchain). In an editor, the language server completes its fields, explains them on hover and reports the same errors velt would.

src/greet.vlt is a module with one exported function:

ts
// The greeting, in its own module so tests/greet.test.vlt can check it.

/// A friendly greeting for `name` (a blank name greets the world).
export function greet(name: string): string {
  const who = name.trim();
  return `Hello, ${who === "" ? "world" : who}!`;
}

src/main.vlt imports it, and the program arguments from the standard library (velt/process):

ts
// Entry point: `velt run` builds and runs this.
import { args } from "velt/process";
import { greet } from "./greet";

function main() {
  const argv = args();
  console.log(greet(argv.length > 0 ? argv[0] : "world"));
}

A file that declares function main() and has no other top-level statements runs main; one with top-level statements runs those, as in Node. Both work; the template uses main.

tests/greet.test.vlt checks the greeting:

ts
// `velt test` runs every exported `test_*` function in `*.test.vlt` files.
import { greet } from "../src/greet";

export function test_greets_by_name() {
  assertEq(greet("Ada"), "Hello, Ada!");
}

export function test_blank_name_greets_the_world() {
  assertEq(greet("  "), "Hello, world!");
}
Text
$ velt run -- Ada
Hello, Ada!
$ velt test tests
running tests/greet.test.vlt
ok test_greets_by_name
ok test_blank_name_greets_the_world

test result: ok. 2 passed; 0 failed

The everyday commands, inside the package:

CommandWhat it does
velt runbuild and run src/main.vlt
velt run -- Adapass arguments to the program (after --)
velt devrun, then hot-swap or restart on every save (Hot reload)
velt testrun the tests (Testing)
velt checktype-check without building
velt fmtformat the sources
velt build --releasean optimized binary in target/velt/hello

Other templates start you off with a bigger skeleton: velt new todo --template api (a JSON HTTP API on the http-server package, which its package.vlt lists as a dependency), --template cli (a command-line tool), --template websocket (a chat server and client), --template lib (a library to publish). velt init does the same in the current directory.

Editor setup#

Install the Velt extension for VS Code (code --install-extension andtii.velt) for highlighting, diagnostics as you type, go-to-definition, completion and quick fixes, or point any LSP client at velt lsp (Editors). With a debugger extension such as CodeLLDB installed too, F5 builds the package and stops on breakpoints (on Linux and macOS; on Windows see Debugging): velt new writes the .vscode/launch.json for it, and velt init --editor vscode adds the .vscode files to an existing package.

Next steps#

Edit this page on GitHub