# Varyk

Varyk is a small language for APIs, workers, and microservices. No garbage collector, no lifetime annotations, no borrow ceremony, and Rust and crates.io underneath. You write Go-like application code and ship one native binary, checked by the Rust compiler.

## What a service needs. What Rust *guarantees.*

Rust underneath gives you all of this today. The batteries that make a service, what a Go or TypeScript team expects to find built in, are listed below them: JSON, configuration, logging, and tests arrived in milestone 5a, `async` in milestone 5b1, packages that use packages in milestone 5b2, facades for packages in milestone 5b3, routes checked against their handlers in milestone 5b4, and times, ids, and bytes in milestone 5c; databases and HTTP come as packages, [`varyk-sql`](https://github.com/Varyk-Lang/varyk-sql) since milestone 5b3 and [`varyk-http`](https://github.com/Varyk-Lang/varyk-http) since milestone 5b4, and MongoDB as [`varyk-mongo`](https://github.com/Varyk-Lang/varyk-mongo), after milestone 5.


- **One file to deploy.** A whole program is one executable, under half a megabyte for the [`todo` example](/learn/examples/#todo) built on an Apple Silicon Mac, with no language runtime to install.
- **Starts instantly, stays small.** The `todo` example starts in a few milliseconds and uses about a megabyte and a half of memory on an Apple Silicon Mac. There is no garbage collector, so no pauses and no memory ceiling to tune.
- **Bugs caught before the program runs.** No null: a value that can be missing is an `Option`, and you must handle it. Errors are values, not exceptions: a function that can fail says so in its return type, and there is nothing to catch. Two threads cannot touch the same data unsafely. All of it is rustc checking your program, not Varyk approximating it.
- **As fast as Rust, because it is Rust.** Native code, no interpreter, no just-in-time compiler, nothing cloned behind your back.
- **No ownership ceremony.** No lifetime annotations, no choosing between `x`, `&x`, and `&mut x` at a call site, and one string type. The compiler makes those decisions, and rustc checks every one of them.
- **Readable Rust, yours to keep.** The generated Rust is a normal Cargo project, `--emit-rust` shows all of it, and there is no lock-in.
- **The whole Rust ecosystem.** A Varyk package is a Cargo package: since milestone 3 you add a crate with `cargo add`, or `varyk add` since milestone 5a, and call it from a `.rs` file in the package, and the next section shows how.
- **Drop into Rust when you need it.** A `.rs` file beside your `.vr`, in the same package and the same build. Write the borrow-heavy part in Rust and the rest in Varyk. Use Varyk until you actually need Rust.

### The batteries

JSON, configuration, logging, and tests are in the compiler since milestone 5a, `async` since milestone 5b1, and `Time`, `Uuid`, and `Bytes` since milestone 5c; the [examples](/learn/examples/#json) show them. Databases and HTTP come as packages you add, `varyk-sql`, `varyk-mongo`, and `varyk-http`, so a program that prints a line never compiles a web server or a database driver. Milestone 5b3 gave the compiler what `varyk-sql` needs, and milestone 5b4 what `varyk-http` needs; `varyk-mongo` came after milestone 5. Each package lives in its own repository and is released on its own. The figure at the top of the page is a service with `varyk-http` and `varyk-sql`.

- **JSON from your structs.** Turn your structs into JSON and back with `json::parse` and `json::stringify`, and rename, default, or skip a field with an attribute. *Milestone 5a.*
- **Configuration, logging, tests.** A struct filled from the environment and a `.env` file with `env::parse`, log lines on stderr as text or JSON, and `varyk test`. *Milestone 5a.*
- **Async built in.** `async fn` and `.await` on a built-in runtime; call a function without `.await` to start it as a task, and wait on many with `Task::all`. *Milestone 5b1.*
- **Times, ids, and bytes.** `Time`, a point in time in UTC written as `2026-10-07T12:00:00Z`, `Uuid`, with `Uuid::new()` a time-ordered id, and `Bytes`, base64 in JSON, as built-in types that go through JSON and into `varyk-sql`'s native columns, so a `created_at` is a time and not a string. *Milestone 5c.*
- **Databases through one API.** Query SQLite, Postgres, or MySQL and get your structs back, in the [`varyk-sql`](https://github.com/Varyk-Lang/varyk-sql) package on sqlx; the query text is written in the program, so a query built from input is a compile error. *Milestone 5b3.*
- **HTTP server and client.** An explicit route table that `varyk check` checks against each handler, handlers whose return value is the response, errors whose internal message never reaches a client, and calls to other services, in the [`varyk-http`](https://github.com/Varyk-Lang/varyk-http) package on axum and reqwest. *Milestone 5b4.*
- **MongoDB.** Documents from your structs, with times, ids, and bytes as native BSON types, and filters, updates, and pipelines in MongoDB's own syntax with the values beside the text, in the [`varyk-mongo`](https://github.com/Varyk-Lang/varyk-mongo) package on the official `mongodb` crate; `varyk add mongo` adds it. *After milestone 5.*

Varyk exists so that ordinary backend services can be written simply and shipped as safe Rust. It is for the application: kernels, database engines, and borrow-heavy libraries stay in Rust, in a `.rs` file beside your Varyk, in the same build. [Read why Varyk exists](/why/).

## Varyk packages are Cargo *packages.*

A Varyk package is a `Cargo.toml` and a `src/main.vr`. `varyk init` writes one, `varyk run` builds it, and `varyk publish` ships it to crates.io as an ordinary Rust crate that needs no Varyk to use. Since milestone 5b2, a Varyk package uses another Varyk package by its key in `Cargo.toml`, with no facade, and `varyk` builds every one of them from its `.vr` sources, never from Rust its publisher shipped. There is nothing to bootstrap: every crate on crates.io was Varyk's ecosystem from the first day, and every Varyk package joins it.

1. **`main.vr`** Your service, in Varyk. It never names a Rust crate, and it never writes a reference.
2. **`text.rs`** A Rust file beside it: a facade that wraps what the program needs in plain functions, structs, and enums, which Varyk imports like a module of its own. Since milestone 5b3, a facade can also read its result into whatever type the caller names and take any number of values, and since milestone 5b4 take any value JSON can write, so a package such as [`varyk-sql`](https://github.com/Varyk-Lang/varyk-sql) keeps its Rust in a facade, and a program that uses it writes no Rust.
3. **crates.io** Any crate, added with `varyk add` or `cargo add`. Need Stripe, AWS, or Kafka? Use the Rust crate.

Need something Varyk doesn't provide? Use the Rust crate. Need Rust itself, for the one hot loop or the borrow-heavy library? Write it in the `.rs` file, in the same build, and call it from Varyk. The [matcher](/learn/examples/#matcher) example wraps `regex-lite` this way, and the [tools page](/tools/#packages) describes `init` and `publish`.

## How it *works.*

Most of Rust's surface is the *spelling* of decisions the compiler can make on its own. Varyk keeps Rust's ownership model inside the compiler and takes the spelling out of the language. This program runs today; everything marked is what the compiler wrote for you.

| Rule | In Rust you write | In Varyk you write |
|---|---|---|
| **Functions borrow by default.** The signature carries the contract. | `fn rename(user: &mut User)` | `fn rename(mut user: User)` |
| **Call sites never write `&`.** No choosing between `x`, `&x`, and `&mut x`. | `rename(&mut user);` | `rename(user);` |
| **One string type.** The compiler decides the representation. | `name: "Alice".to_string()` | `name: "Alice"` |

From your source to the binary:

1. **`.vr`** Varyk source, with `.rs` files beside it in the same build.
2. **`varyk build`** Parses, type-checks, and runs borrow analysis. Diagnostics carry codes and fix-its.
3. **`target/varyk/`** A Cargo project of readable Rust. It is yours, so there is no lock-in.
4. **`cargo`** rustc and the full borrow checker. Varyk never uses `unsafe` to get around it.
5. **A native binary** No garbage collector, no reference counting, no runtime beyond Rust's.

## Wherever you’re coming from.

### Building services in Go, TypeScript, or Python

- Application code as simple as Go: the compiler does the memory bookkeeping that Rust asks you to write by hand.
- Native speed and memory safety with no garbage collector: no pauses, no memory ceiling to tune, and one small binary to deploy with no language runtime to install.
- The bugs Go and TypeScript compile, a missing value, an unhandled error, two threads on one piece of data, rustc rejects.
- `async`/`await` that looks like JavaScript, with a built-in runtime, since milestone 5b1.
- One toolchain and one package registry, inherited from Cargo and crates.io, since milestone 3.

### Coming from Rust

- Rust syntax and idioms: immutability by default, `let mut`, `struct`, `impl`, `match`, `Option`, `Result`, and `?`.
- The same safety model: the generated Rust is checked by rustc, and Varyk never bypasses it.
- Less ceremony for application code.
- `.rs` files next to `.vr` files in the same package, built by the same `cargo`.
- Varyk packages are Cargo packages and publish to crates.io as ordinary crates, since milestone 3.

### Written with a coding agent

- Agents already write good code; the slow part is reviewing it. Varyk is designed to keep reviews short.
- A small language with one way to do each thing, so agent output looks like the code around it.
- Concrete code, with few abstractions to see through.
- rustc checks memory safety and data races, so a review can focus on what the service does.
- A reference that fits in a prompt, and JSON diagnostics with codes and fix-its, so the agent fixes its own mistakes first.
- One official stack for HTTP, JSON, and databases, the same in every Varyk service (JSON since milestone 5a; databases and HTTP as the packages [`varyk-sql`](https://github.com/Varyk-Lang/varyk-sql), since milestone 5b3, and [`varyk-http`](https://github.com/Varyk-Lang/varyk-http), since milestone 5b4, and MongoDB as [`varyk-mongo`](https://github.com/Varyk-Lang/varyk-mongo), after milestone 5).

## Ordered milestones, no *dates.*

1. **Milestone 1, complete.** Compiler skeleton and the borrow-by-default proof: six example programs, diagnostics with codes and fix-its, and `varyk check`, `build`, and `run`.
2. **Milestone 2, complete.** Enums, `match`, `for`, methods, `Option`, `Result`, `Vec`, `?`, and `format!`.
3. **Milestone 3, complete.** Packages and interop: `Cargo.toml`, Cargo dependencies through `.rs` facades, nested modules, `use`, private fields, Rust structs and enums imported from `.rs` files, `varyk init`, and publishing to crates.io. Released as 0.1.0.
4. **Milestone 4, complete.** Closures, iterators, and patterns: chains such as `filter` and `map`, `if let` and `while let`, nested, literal, and range patterns, `HashMap`, `as`, `.clone()` and `==` on structs and enums, and getters that return part of their value with no copy. Released as 0.2.0.
5. **Milestone 5a, complete.** Data, configuration, logging, and tests: a built-in `Error`, `json::parse` and `json::stringify`, `env::parse` with `.env`, `log` calls, the attributes `#[rename]`, `#[default]`, `#[skip]`, and `#[test]`, and `varyk test` and `varyk add`. Released as 0.3.0.
6. **Milestone 5b1, complete.** Async: `async fn` and `.await` on a built-in runtime, calls started as tasks, `Task::all` and `Task::all_settled`, and `Shared` for a value many tasks read. Released as 0.4.0.
7. **Milestone 5b2, complete.** Packages: Varyk code uses a Varyk package by its key in `Cargo.toml`, to any depth, and `varyk` builds every package from its `.vr` sources, never running Rust a publisher shipped or a build script. Released as 0.5.0.
8. **Milestone 5b3, complete.** Facades for packages: a `.rs` facade function that reads its result into whatever type the caller names, takes any number of values after its other arguments, or takes only text written in the program, plus `pub use` and `varyk add sql`. Released as 0.6.0, with the database package `varyk-sql`, in [its own repository](https://github.com/Varyk-Lang/varyk-sql), released as 0.1.0.
9. **Milestone 5b4, complete.** HTTP: routes and hooks on an app of the `varyk-http` package, each route checked against its handler by `varyk check`, an optional status on `Error`, `app.request` for tests, and `varyk add http sql`. Released as 0.7.0, with the HTTP package `varyk-http`, in [its own repository](https://github.com/Varyk-Lang/varyk-http), released as 0.1.0: a users API on a database is `varyk init`, `varyk add http sql`, one file, and `varyk run` away.
10. **Milestone 5c, complete.** Time, ids, and bytes: `Time`, `Uuid`, and `Bytes` as built-in types, through JSON, database values, and facades, and `Time` and `Uuid` through configuration and route parameters, so the users API does not send a date as a string. Released as 0.8.0, with `varyk-sql` 0.3.0, which stores the three as native columns, and `varyk-http` 0.2.0, which reads times and ids from routes and sends and receives bytes; with them, milestone 5 is met.
11. **Milestone 6, in progress.** Tooling and beyond: `varyk fmt`, a language server, more of Rust imported from `.rs` files, and a decision on a native backend. The first of it came as 0.9.0: `varyk lsp`, which shows errors and quick fixes in an editor when a file is opened or saved, and a `varyk-std` line that names the oldest varyk a package needs, so a varyk release no longer stops a published package from building. Not scheduled.

After milestone 5 came the next packages, each in its own repository: the MongoDB package [`varyk-mongo`](https://github.com/Varyk-Lang/varyk-mongo), released as 0.1.0, and [`varyk-sql`](https://github.com/Varyk-Lang/varyk-sql) 0.4.0, with `$1` placeholders on every database. Varyk 0.8.1 added what `varyk-mongo` needs, and 0.8.2 added `varyk add mongo`. `varyk-redis` is next.

The [roadmap](/design/roadmap/) has every item. None of it has a date, and none of it is a promise of a release.

## Install. Write. Run.

Varyk requires a stable Rust toolchain, 1.88 or newer, installed through [rustup](https://rustup.rs). Install the compiler, write a package, and run it:

```text
$ cargo install varyk --locked
$ varyk init hello
$ cd hello
$ varyk run
Hello, world!
```

`init` wrote `Cargo.toml`, `.gitignore`, `.dockerignore`, and `src/main.vr`, the program. For colour and errors in your editor, install the **Varyk** extension in VS Code, or in Zed once Zed lists it ([set up your editor](/install/#set-up-your-editor)). Continue with [getting started](/learn/getting-started/), which ends with [a first service](/learn/getting-started/#a-first-service) on HTTP and a database, and the [language reference](/learn/reference/). Source and issues are at [github.com/Varyk-Lang/varyk](https://github.com/Varyk-Lang/varyk).
