June 24, 2026
The V Language: The Best Parts of Go, Rust, and Python — All in One
A Go-like simple, Rust-like safe, and Python-like productive language that transpiles to C

By Shalitha Suranga
14 min read
I started programming with Visual Basic 6.0 in 2009. I learned Java, C, C++, JavaScript, Python, Delphi, C#, and many mature languages. I learned modern, popular languages like Go and Rust too. Every programming language I learned is unique; they come with new concepts and syntax. Some programming languages improve other existing mature ones, but they also introduce new concepts and features. Programming languages aren't perfect — they come with core design issues, limitations, and various frustrations for programmers along with features that programmers truly love. While some programmers like a specific language's syntax and semantics, some can hate it. That's why there are more than 20 popular languages — not just one that dominates the entire software development industry.
Have you ever thought what if we could build a single language by extracting every programmer-loved feature of popular, modern languages? The V programming language project, initially released in 2019, created a new, compiled programming language by taking developer-loved features from Go, Rust, Python, C/C++, Dart, and more.
Let's explore the V language, experiment with it by writing some code, and evaluate how it can compete with today's programming language ecosystem.
What is the V language?
V is a statically typed, compiled, general-purpose, modern programming language that lets programmers create fast and lightweight software systems. It is a fully featured, general-purpose language with systems programming features, so it's suitable for creating web services to operating system kernels — you can literally build anything productively while maintaining high performance and a small binary size.
V is an attempt to create a versatile but performance-first language with minimized developer pain points by implementing good features of existing popular languages:
- Go: V uses Go-like syntax to achieve extreme syntactical and semantic simplicity
- Rust: V implements Rust-like memory safety using default immutability, unsafe blocks, no null type, and optionals
- D: V offers zero-cost C interop, somewhat similar to D, and also extremely fast compilation like D
- Dart: Dart-like hot reloading for improving developer productivity
- Python: V offers Python-like
inkeyword, REPL, many cross-platform features, targeting improved DX (developer experience)
We have Go and Rust, so why V?
You might think why you should learn V since Go and Rust have won the systems programming industry. Don't conclude V as yet another attempt to create just a better C/C++ language.
V is a unique language that combines the developer-loved parts of Go and Rust, eliminating their pain points and limitations:
Go mastered the syntactical simplicity — it offers the most minimalistic coding syntax and semantics, but Go wasn't designed for creating kernels and lightweight software systems — it generates heavy binaries and creates abstraction over low-level programming (e.g., Goroutines aren't POSIX threads). That's why Go stayed in the cloud — where portability and memory-safety-enabled performance matter over low-level programming requirements.
Rust is winning the better C/C++ race with its impressive memory safety features, but many developers don't like its complexity, syntax, and slow compilation.
V is like a further simplified, improved, lighter version of Go with Rust's memory safety techniques and Python's DX
Highlighted V features
Along with V's simple core language design and common coding features, such as generics, interfaces, simpler error-handling, etc., it offers the following features to make it a highly versatile but low-level-programming-friendly modern language:
- C compiler backend: V doesn't use heavyweight LLVM or implement its own multi-architecture machine code generator (yet). The V compiler transpiles V code to C and uses pre-packaged Tiny C or a C compiler installed on your PC to achieve portability, performance, and zero-cost C interop
- Flexible memory management: V lets you turn on the garbage collector and write code without worrying about freeing memory, or turn it off and write low-level, C-like code with manual memory-handling. Four total memory management strategies are available for various development scenarios
- Fully-featured standard library: The V standard library includes pre-developed cryptography algorithms, cross-platform operating system features (file I/O, child processes, etc.), JSON, YAML, TOML parsers, networking APIs, graphics API, terminal UI API, high-performance web framework, file compression features, database APIs, string manipulation, and more
- Built-in ORM: V implements a built-in ORM by effectively using structs and annotations, and lets you work with SQL productively, without external dependency modules
- Built-in test runner: No need to seek external testing frameworks — the language itself includes productive testing syntax, and the V CLI can run tests without third-party modules
- Built-in REPL: This is an unexpected feature from a systems-programming-focused language, but remember V is a versatile language. V offers a built-in Python-like REPL
- Built-in shell scripting features: You can use V as a cross-platform, productive alternative to Bash for shell scripting, similar to D, Lua, and Tcl, but the V compiler gives more scripting support, like using the
.vshfile extension and calling theosmodule's functions directly - Hot reloading and watching: You can enable Dart-like smooth hot reloading in V and also use classic source watching re-compilation for programming productivity
- WASM target: Your V projects can be compiled to WASM via Emscripten and executed on web browsers
- Official UI library: The V development team maintains a cross-platform UI library called V UI, which offers a productive, clean Flutter-like widgets API with hot reloading support
V offers features to make the language highly versatile, while respecting the fundamental minimal design and being a better C, a systems programming language.
V features and capabilities cover both Go's and Rust's user bases
Getting started with V programming
Let's write some code in V to understand its simplicity, programming capabilities, and overall DX. I composed this as a simple V tutorial that helps you master V in a few minutes. Knowing Go or Rust syntax isn't a prerequisite.
Installing V
You can download the pre-built V compiler package for Linux, macOS, and Windows from the official website. Or, you can download the V compiler source code and build it on your PC.
I've downloaded the V compiler for Linux and configured PATH as follows:
export PATH="$PATH:$HOME/programs/v"export PATH="$PATH:$HOME/programs/v"Once the path is configured, you can verify whether the V CLI binary works by entering v. This command will start REPL as follows:
Note: If you don't like to install the V compiler and CLI right now, you can continue with this tutorial by running sample code snippets on the official online V playground.
Writing a basic V program
Similar to Go, the V CLI offers a command to initialize an empty project instantly. Create a new project called tutorial:
v init tutorialv init tutorialThe above command asks a few details about the project and finally creates a new "Hello World" project inside the tutorial directory. See the main.v file content:
module main
fn main() {
println('Hello World!')
}module main
fn main() {
println('Hello World!')
}The code looks like a mixture of Go and Rust syntax. We don't need to import anything to use println(), since it's a built-in function.
Run this sample program using the run command. You can switch the C compiler if you need (by default, V uses the Tiny C compiler that comes with the V compiler package)
v run . # Compile using Tiny C (embedded in the V package)
v -cc gcc run . # Compile using GCCv run . # Compile using Tiny C (embedded in the V package)
v -cc gcc run . # Compile using GCC
The run command transpiles V to C, compiles C to an executable using a C compiler, and runs the final C program. This process is inspectable using the verbose flag (-v) with the run command.
You can get the readable, transpiled C source file by halting the compilation process at the C code generation phase as follows:
v -o main.c -gc none .v -o main.c -gc none .Now, compiling main.c using gcc (or any C compiler installed in your PC) generates the same sample portable C program:
gcc main.c -o main
./maingcc main.c -o main
./main
Primary data types in V
V has 16 primary data types for storing booleans, integers, floating points, and characters. Signed types begin with the i prefix and unsigned types begin with u, similar to Go.
Here is a simple demonstration of integer and floating-point types:
a := i8(-50)
b := i16(-250)
c := int(-5000)
d := i64(-57000)
e := u8(50)
f := u16(250)
g := u32(5000)
h := u64(57000)
i := f32(4.553)
j := f64(12.222201)
println('a = ${a}')
println('b = ${b}')
println('c = ${c}')
println('d = ${d}')
println('e = ${e}')
println('f = ${f}')
println('g = ${g}')
println('h = ${h}')
println('i = ${i}')
println('j = ${j}')a := i8(-50)
b := i16(-250)
c := int(-5000)
d := i64(-57000)
e := u8(50)
f := u16(250)
g := u32(5000)
h := u64(57000)
i := f32(4.553)
j := f64(12.222201)
println('a = ${a}')
println('b = ${b}')
println('c = ${c}')
println('d = ${d}')
println('e = ${e}')
println('f = ${f}')
println('g = ${g}')
println('h = ${h}')
println('i = ${i}')
println('j = ${j}')The above code snippet uses string interpolation to display variable values with strings. Type size can be retrieved using the sizeof keyword:
println('i16 size: ${sizeof(i16)} bytes')println('i16 size: ${sizeof(i16)} bytes')You can store UTF-8-encoded immutable strings using the string type and UTF-32-encoded Unicode characters using the rune type (an alias of u32):
s := 'Hello V '
u := `🚀`
println(s + u.str())s := 'Hello V '
u := `🚀`
println(s + u.str())
Complex data types in V
Built-in arrays and maps are available with a very productive syntax. You can define arrays as you define lists in Python — V feels like a dynamic language when you work with built-in collections:
a := [10, 20, 100, 50]
println(a) // [10, 20, 100, 50]
println(typeof(a).name) // []inta := [10, 20, 100, 50]
println(a) // [10, 20, 100, 50]
println(typeof(a).name) // []intHere is the interesting part about arrays. In V, you can use C++'s stream write operator (<< ) to append an item to an array. The following example creates a mutable empty array using the mut keyword and appends several items later:
mut a := []int{}
a << 10
a << 20
a << 30
println(a) // [10, 20, 30]mut a := []int{}
a << 10
a << 20
a << 30
println(a) // [10, 20, 30]The modern array slice syntax is also available:
a := [10, 20, 30, 40]
println(a[1..3]) // [20, 30]a := [10, 20, 30, 40]
println(a[1..3]) // [20, 30]V map syntax is similar to Go's, but V lets you productively create a map by using another map. This works very similarly to JavaScript's spread operator:
mut m := map[string]int{}
m['x'] = 10
m['y'] = 20
n := {
...m
'z': 30
}
println(n)mut m := map[string]int{}
m['x'] = 10
m['y'] = 20
n := {
...m
'z': 30
}
println(n)
You can use Python-like in operator to check item existence in arrays and maps:
a := [10, 20, 30, 40]
m := {
'x': 10
'y': 20
}
println(10 in a) // true
println('z' in m) // falsea := [10, 20, 30, 40]
m := {
'x': 10
'y': 20
}
println(10 in a) // true
println('z' in m) // falseV structs help you create complex records and use OOP in your projects, similar to Go:
struct Doc {
id int
title string
width int
height int
}
d := Doc {1000, 'Document #1', 1000, 800}
println(d)struct Doc {
id int
title string
width int
height int
}
d := Doc {1000, 'Document #1', 1000, 800}
println(d)
Control structures
While traditional if branching work as in other languages, V additionally implements if expressions. The following code snippet demonstrates a simple if statement and a if expression:
mut a := 10
if a > 5 {
println('a > 5')
}
a = -10
abs := if a < 0 { -a } else { a }
println(abs) // 10mut a := 10
if a > 5 {
println('a > 5')
}
a = -10
abs := if a < 0 { -a } else { a }
println(abs) // 10V's array and map iteration loops are very simple — simpler than Go's. Here is how you can iterate over arrays and maps:
a := [10, 20, 50, 100]
for n in a {
print('${n} ')
}
println('')
m := {'x': 10, 'y': 20, 'z': 30}
for k, v in m {
print('${k}: ${v} ')
}
println('')a := [10, 20, 50, 100]
for n in a {
print('${n} ')
}
println('')
m := {'x': 10, 'y': 20, 'z': 30}
for k, v in m {
print('${k}: ${v} ')
}
println('')
You can label the outerfor loops and break or continue them from the inner for loops, similar to Go.
Functions and lambda expressions
Creating V functions is very simple. You can return multiple values too from functions:
fn add(a int, b int) int {
return a + b
}
fn getxy() (int, int) {
return 10, 20
}
fn main() {
println(add(10, 20)) // 30
println(getxy()) // (10, 20)
}fn add(a int, b int) int {
return a + b
}
fn getxy() (int, int) {
return 10, 20
}
fn main() {
println(add(10, 20)) // 30
println(getxy()) // (10, 20)
}Go doesn't implement a dedicated lambda syntax — you'll have to use classic anonymous functions to use lambda functions in Go, but V introduces Rust-like dedicated lambda syntax. Here is an example with the array map() function:
a := [1, 2, 3, 4, 5]
println(a.map(|n| n * 2))
println(a.map(|n| n.str().repeat(2)))a := [1, 2, 3, 4, 5]
println(a.map(|n| n * 2))
println(a.map(|n| n.str().repeat(2)))
Using the V standard library
V has a fully-featured, cross-platform, modern, and simple standard library. V is a system programming-focused language, but its standard library makes V suitable for building anything, literally, even web apps, since everything you seek is available there. V is the first systems programming language I have ever seen that includes a complete web framework within its standard library.
V turns complex operating system features into simple cross-platform APIs. Here is how you can use the child process API to run a command and get output:
import os
fn main() {
r := os.execute('node --version')
if r.exit_code == 0 {
v := r.output.trim_space().replace('v', '')
println('Node.js version: ${v}')
}
else {
println('ERR: Cannot find Node.js binary')
}
}import os
fn main() {
r := os.execute('node --version')
if r.exit_code == 0 {
v := r.output.trim_space().replace('v', '')
println('Node.js version: ${v}')
}
else {
println('ERR: Cannot find Node.js binary')
}
}Here is another example that uses the standard library's http module to create a simple web server that sends a random number to web clients:
import net.http { Request, Response, Server }
import rand
struct Handler {}
fn (h Handler) handle(req Request) Response {
println('Handling request: ${req.method} ${req.url}')
return Response {
status_code: 200
body: '{n: ${rand.int_in_range(1, 100) or {0} }}'
}
}
fn main() {
mut s := Server{handler: Handler{}}
s.listen_and_serve()
}import net.http { Request, Response, Server }
import rand
struct Handler {}
fn (h Handler) handle(req Request) Response {
println('Handling request: ${req.method} ${req.url}')
return Response {
status_code: 200
body: '{n: ${rand.int_in_range(1, 100) or {0} }}'
}
}
fn main() {
mut s := Server{handler: Handler{}}
s.listen_and_serve()
}
Note: The above code snippet uses
orkeyword to set a default value sincerand.int_in_range()returns an optional integer. We'll discuss optionals in the error handling section.
Browse the official V standard library reference to browse all available modules and functions.
Memory management in V
V comes with a garbage collector, but it is not strictly embedded in every program — the V CLI allows you to toggle the garbage collector as you prefer. V supports a new memory management concept called autofree and also lets you manually manage memory as in C. All these make four memory management ways in V programming.
Let's discuss each memory management approach.
By default, the V CLI embeds the garbage collector, so you don't need to handle memory explicitly:
struct User {
name string
score u32
}
p := &User {'john', 82} // heap allocation done using '&'
println(p)
v -o main.c .struct User {
name string
score u32
}
p := &User {'john', 82} // heap allocation done using '&'
println(p)
v -o main.c .The generated C source file includes garbage collector calls:
Manual memory management is available using the unsafe{} blocks:
p := &User {'john', 82}
println(p)
unsafe {
p.free()
}
v -gc none -o main.c .p := &User {'john', 82}
println(p)
unsafe {
p.free()
}
v -gc none -o main.c .Here comes the most innovative memory management strategy. If you compile the first garbage-collected example snippet and compile with -autofree, the V compiler automatically adds free() calls wherever necessary— imagine the future of memory-safe, performance-first, productive programming without built-in garbage collection. In my opinion, the autofree concept is the most productive, performance-friendly, and lightweight systems programming memory handling method:
v -autofree -o main.c .v -autofree -o main.c .
Note: The autofree memory management feature is still experimental and under development, so the V development team recommends avoiding using it until it becomes production-ready.
The V documentation states that autofree will be the default memory management strategy in the future
The arena memory allocation strategy is available via the -prealloc flag and can be used as follows:
v -prealloc -o main.cv -prealloc -o main.cError handling features
V doesn't use C++-like try-catch exceptions to keep the language minimal. It implements a simple C3-like error handling strategy using optionals. If a function returns an optional type, it can return a value and also throw an error:
fn div(a int, b int) !int {
if b == 0 {
return error('ERR: Division by zero')
}
return a / b
}
fn main() {
a := [1, 2, 0, 5]
for n in a {
ans := div(10, n) or {
println('10 / ${n} = ?')
continue
}
println('10 / ${n} = ${ans}')
}
}fn div(a int, b int) !int {
if b == 0 {
return error('ERR: Division by zero')
}
return a / b
}
fn main() {
a := [1, 2, 0, 5]
for n in a {
ans := div(10, n) or {
println('10 / ${n} = ?')
continue
}
println('10 / ${n} = ${ans}')
}
}
Here we used the continue statement since we need to continue processing the a array. The return statement can be used if you need to exit immediately. You can also use the same syntax to use default values:
ans := div(10, n) or { 0 }
// Using 0 only for demonstration; division by zero is undefinedans := div(10, n) or { 0 }
// Using 0 only for demonstration; division by zero is undefinedV slightly changes the way we naturally handle errors in programming, but if you correctly understand the or{} block, you'll find it so productive.
Calling C code from V
V offers a truly zero-cost C interop. There is no FFI, ABI mapping, or other technique hiding behind since V transpiles to C. You can directly include C header files using #include and call C functions with the C. prefix.
The following code snippet prints a string using the C standard library's puts() function:
#include <stdio.h>
fn C.puts(&char) int
fn main() {
C.puts(c'Hello from C')
}#include <stdio.h>
fn C.puts(&char) int
fn main() {
C.puts(c'Hello from C')
}Running this with the V CLI works as expected:
What if you need to call your existing C sources and incrementally migrate your classic C project to V?
No problem. You can use a similar approach to call C code and compile the project with both V and C sources.
Assume that you have the calc.c source file, and you need to call its add() function implementation from V:
int add(int a, int b) {
return a + b;
}int add(int a, int b) {
return a + b;
}Declare C.add() as usual, and instruct the V compiler to include the calc.c file in the final C program compilation process:
#flag @VMODROOT/calc.c
fn C.add(a int, b int) int
fn main() {
println('10 + 5 = ${C.add(10, 5)}')
}#flag @VMODROOT/calc.c
fn C.add(a int, b int) int
fn main() {
println('10 + 5 = ${C.add(10, 5)}')
}
V uses compiler flags and C. prefix to let programmers integrate C, maintaining the quality of the language — it doesn't let programmers mix C and V, complicating source files.
Converting C code to V
If you plan to migrate a C codebase to V, you can do an incremental migration by converting a part of the codebase to V and using transpiled C files in your current C build system. Or, you can write the project bootstrap code in V, call C source files directly in V using C.<function>, and use V CLI for building the project.
Regardless of the migration approach, you'll have to convert C to V. V doesn't force you to convert C to V manually — it offers a command to automate:
v translate main.cv translate main.c
How about class C dependencies then, e.g., libuv? You can instantly generate a V wrapper for C libraries using the v translate wrapper <clibrary> command.
Note: The
v translatecommand requires Clang installed on your PC since the V compiler doesn't have a built-in C parser
Conclusion
Creating a perfect language that everyone loves is practically impossible. While Programmer A loves a specific syntax or feature in a specific language, Programmer B can hate it. However, each popular language has its own good parts that every programmer generally likes to use. Go has its simplicity, C has the freedom, Rust has memory-safety features, and Python attracts everyone with productivity shortcuts. On the other hand, these languages have unique bad parts too.
The V programming language impressively extracts good parts of Go, Rust, and Python and creates a systems-programming-friendly, versatile language, which you can use to build desktop, CLI, embedded, mobile, and any low-level project.
I tried building a web service and some sample programs using the standard library; the DX is truly impressive as the compiler always prints descriptive error messages, and the CLI offers everything you need, including a package manager. You don't need to worry about binary sizes since you'll get an optimized C program eventually.
If you don't like trendy Rust's complexity and struggle with low-level programming with Go, V is a must-try.
The following article introduces the D programming language, a better alternative to C++:
The D Language: A Better C/C++ Alternative Only a Few Programmers Know A modern, fast, fully-featured, compiled language that you can use beyond systems programming
Thanks for reading.