A high-performance, concurrent bytecode virtual machine and language written in Go.
Tiny combines the development speed of dynamic coding with a robust, multi-threaded runtime engine.
Tiny is a concurrent programming language and runtime system. It compiles source files into compact, stack-based bytecode instructions (.tbc) which run on a highly optimized, register-less virtual machine written in Go.
The runtime engine features direct OS-level parallel threading, native WebAssembly compilation for inline Go extensions, zero-copy matrix linear algebra, a built-in Language Server (LSP), and standalone binary distribution packaging.
Read the full documentation at tiny-lang-docs.github.io, or check out the examples to see Tiny in action.
Precompiled binaries are available on the release page:
- Windows:
tiny_windows_amd64.exe - Linux:
tiny_linux_amd64 - macOS (Apple Silicon):
tiny_darwin_arm64
To install:
- Download the binary for your operating system.
- Rename the file to
tiny(ortiny.exeon Windows). - Move the binary into a directory in your system path (for example,
~/.tiny/binon Unix or%USERPROFILE%\.tinyon Windows). - Add that directory to your system
PATHenvironment variable.
For compilation from source instructions, see the online documentation.
Tiny is dynamically typed by default. You can write untyped code for rapid prototyping, or apply optional static type hints to variables, parameters, and function returns.
import std "io";
// Untyped variable
let data = "untyped string";
// Explicitly typed variable
const port: number = 8080;
// Typed function parameters and return type
fn calculatePayout(base: number, multiplier: number): number {
return base * multiplier;
}
io.println(calculatePayout(100, 1.5));Tiny uses structural typing (shape-based validation). Objects are validated against interfaces at runtime based entirely on their properties and methods, rather than explicit inheritance declarations.
import std "io";
interface Task {
title: string
done: bool
}
fn printTask(t: Task) {
let status = t.done ? "Completed" : "Pending";
io.println(`${t.title} - Status: ${status}`);
}
// Valid structural matches
printTask({ title: "Write Compiler Tests", done: true });
printTask({ title: "Optimize VM Dispatcher", done: false, priority: 1 });Tiny does not use deep class inheritance hierarchies. Instead, it supports composition via the embed keyword. When a class embeds another class instance, any methods and fields from the embedded instance are delegated automatically if they are not defined on the parent class.
import std "io";
import std "json";
class Logger {
field messages = []
fn log(message: string) {
this.messages.push(message);
io.println(`Log: ${message}`);
}
fn dump() {
return this.messages;
}
}
class SessionManager {
field active = true
embed logger
fn init() {
this.active = true;
this.logger = Logger();
// Call to embedded class method
this.log("Session manager initialized");
}
fn close() {
this.active = false;
this.log("Session closed");
}
}
let session = SessionManager();
session.close();
// Directly calls the embedded Logger.dump method
io.println(json.pretty(session.dump()));The match block provides a clean syntax for branch dispatching, supporting literal values, variable variables, enums, and a default fallback case (_).
import std "io";
enum Status {
Idle,
Running,
Failed
}
let current = Status.Running;
match current {
"Idle" {
io.println("System is idling");
}
"Running" {
io.println("System is actively running");
}
_ {
io.println("System encountered an error or unknown state");
}
}The defer statement schedules a function call to execute immediately before the current surrounding function scope exits. This ensures that resource cleanups, file closures, and synchronization locks are released regardless of early returns or errors.
import std "fs";
import std "io";
fn processFile(path: string) {
io.println("Opening file stream...");
let file = fs.open(path);
defer fn() {
io.println("Running defer block: closing file stream.");
// Cleanup logic runs here
}
io.println("Processing file data...");
}
processFile("README.md");The for loop supports unpacking both elements and their indices directly when iterating over collections.
import std "io";
const names = ["Alice", "Bob", "Charlie"];
for name, index in names {
io.println(`Index ${index}: ${name}`);
}Tiny executes parallel operations by using OS-level multi-threading backed by the Go scheduler. The spawn keyword starts a new execution routine running on an independent, isolated VM state space containing its own call frame stack.
Unlike event-loop models or runtimes with a Global Interpreter Lock (GIL), Tiny runs tasks concurrently across all available CPU cores.
import std "io";
import std "time";
let worker = spawn () fn() {
time.sleep(1000);
return "Worker thread complete";
};
io.println("Main thread proceeding...");
let result = await worker;
io.println(result);Shared memory operations can be coordinated using mutexes and native lock blocks. The compiler guarantees that the mutex is automatically released when execution leaves the lock block scope, preventing common deadlock mistakes.
import std "io";
import std "sync";
let counter = 0;
const m = sync.mutex();
fn increment() {
lock m {
counter = counter + 1;
}
}For performance-critical code segments, Tiny allows you to write Go logic directly in the source file using the native fn keyword. During compilation, the compiler extracts these blocks and compiles them to WebAssembly bytecode via TinyGo, loading them at runtime for near-native execution speed.
import std "io";
import std "time";
native fn calculateSha256(input: string): string {
go {
import "crypto/sha256"
import "encoding/hex"
h := sha256.Sum256([]byte(input))
return hex.EncodeToString(h[:])
}
}
native fn computeFibonacci(n: number): number {
go {
if n < 2 {
return n
}
return computeFibonacci(n - 1) + computeFibonacci(n - 2)
}
}
const text = "Tiny runtime speed";
io.println(`SHA256: ${calculateSha256(text)}`);
const start = time.nowMs();
const fibResult = computeFibonacci(30);
const duration = time.nowMs() - start;
io.println(`Fibonacci(30) = ${fibResult} (calculated in ${duration}ms)`);Note: Utilizing
native fnGo extensions requires Go and TinyGo installations on the host system.
Tiny includes a CGO-free standard library designed for networking, UI creation, scripting, and calculations.
The http module contains a fully concurrent web server and client. The server uses a multiplexed routing engine that can process more than 45,000 requests per second.
import std "http";
import std "io";
let server = http.server(8080);
server.get("/", fn(req) {
return http.json({
status: "online",
system: "Tiny VM"
});
});
server.get("/users/:id", fn(req) {
const userId: string = req.params["id"];
return http.json({
id: userId,
query: req.query
});
});
io.println("Web server listening on port 8080");
server.start();The ui module provides a Webview container to construct lightweight desktop applications using HTML, CSS, and JavaScript, while binding underlying system logic to Tiny functions.
import std "ui";
import std "io";
// Embed index.html and its directory assets
embeddir "./ui" const assets
let clicks = 0;
const win = ui.new(true); // Argument enables developer tools
win.setTitle("Tiny Desktop UI");
win.setSize(500, 400);
// Bind a function accessible from JavaScript
win.callback("registerClick", fn(args) {
clicks = clicks + 1;
io.println(`Clicks registered: ${clicks}`);
return clicks;
});
// Load embedded HTML content
win.setHtml(assets["index.html"]);
win.run();Inside ui/index.html, invoke the bound function using standard JavaScript promises:
<script>
async function handleClick() {
const count = await window.registerClick("");
document.getElementById("counter").innerText = count;
}
</script>The desktop module wraps native OS level interfaces for automating keyboard inputs, mouse actions, screen parsing, and clipboard interactions.
import std "desktop";
import std "time";
// Move mouse smoothly to coordinates (800, 600) over 1 second
desktop.moveMouseSmooth(800, 600);
desktop.click();
// Simulate keyboard input
desktop.type("Tiny Automation");
desktop.hotKey("ctrl", "a");
// Screenshot and Clipboard operations
let clipboardText = desktop.getClipboard();
desktop.setClipboard("New Clipboard Content");The math module leverages Go's Gonum package for high-speed matrix computations. It utilizes unsafe zero-copy casting of raw Buffer binary payloads to perform memory-efficient linear algebra calculations.
import std "io";
import std "math";
// Define two 2x2 matrices using flat data arrays inside a Buffer
const matrixA = {
rows: 2,
cols: 2,
data: math.toFloat([1.0, 2.0, 3.0, 4.0]) // Floats packed into a buffer
};
const matrixB = {
rows: 2,
cols: 2,
data: math.toFloat([5.0, 6.0, 7.0, 8.0])
};
// Perform high-speed matrix multiplication
let result = math.matMul(matrixA, matrixB);
io.println(`Product rows: ${result.rows}, cols: ${result.cols}`);Run external commands, check execution status, pipes outputs, and manipulate files directly.
import std "fs";
import std "io";
import std "process";
// Direct file access
if fs.exists("config.json") {
let content = fs.readFile("config.json");
io.println(content);
}
// Spawn and wait for a shell command, capturing standard output
let res = process.run("git", ["status"], { stdout: true });
if res.success {
io.println("Git Status Output:");
io.println(res.stdout);
}Manage scripts, dependencies, targets, and compilation rules using a project-level tiny.json file.
{
"name": "my-tiny-project",
"version": "1.0.0",
"entry": "src/main.tiny",
"outDir": "dist",
"target": "windows-amd64",
"scripts": {
"start": "tiny run",
"build": "tiny build",
"pack": "tiny pack"
},
"dependencies": {
"TinyDotEnv": {
"source": "github:confh/TinyDotEnv",
"version": "main"
}
},
"plugins": [],
"compilerOptions": {
"stackTraces": true,
"strict": true
}
}The tiny binary acts as a compiler, package manager, and execution runtime:
tiny run <file>: Compiles and runs a.tinyor.tbcfile. Direct execution of.tinyfiles utilizes.tinycachetracking to skip compilation if source files have not been modified.tiny build <file> -o <out>: Compiles a source file into a distribution bytecode file (.tbc).tiny pack <file> -o <binary>: Compiles and bundles the source bytecode alongside the VM runtime interpreter into a single, standalone native executable (~9MB).tiny dist <file> -o <dir>: Packages the application alongside compiled external library plugins (.dll/.so).tiny init: Generates a defaulttiny.jsonconfig in the current directory.tiny add <owner/repo>: Downloads and registers a third-party library from GitHub into the global dependency cache.tiny install: Installs all libraries specified in thetiny.jsonmanifest.tiny remove <owner/repo>: Deletes a library from the project dependencies.tiny task <name>: Runs a task script defined in thescriptssection oftiny.json.tiny lsp: Starts the language server.
Tiny features a native Language Server Protocol implementation. Run tiny lsp to interface with editor plugins. The LSP provides:
- Semantic diagnostics and syntax error reporting.
- Auto-completion for variables, objects, standard library, and custom modules.
- Jump-to-definition and reference tracking.
- Automated code formatting.
- Type narrowing (refining variable types following flow control structures like
ifchecks).
You can embed static strings and binary files directly into compiled bytecode using embedstr and embedbin. Assets are compiled into the .tbc stream and automatically obfuscated with an XOR key. This prevents sensitive configurations, keys, or binary assets from being extracted using simple static analysis tools (like the Unix strings utility).
import std "io";
embedstr "./api_key.txt" const apiKey
embedbin "./logo.png" const logoBytes
io.println(`API Key securely loaded: ${apiKey}`);Tiny Language © 2026 | MIT Licensed

