Topaz is a programming language designed for typesetting. Use it for programs that produce print-ready documents, from books to reports and invoices, and also for command-line tools, data transformation, and application logic. Choose it when you want a small, consistent syntax, names in your own language, and programs that run on your computer or in a browser.
Run your First Program, follow the Learning path, or try the Playground without installing anything. Keep Syntax at a Glance open when you need to look up a form.
Use names from your work
The same program can use Korean, Russian, and English names.
function greet(name: string, language: string) -> string {
return match language {
case "한국어" => "안녕하세요, {name}님!"
case "Русский" => "Привет, {name}!"
case _ => "Hello, {name}!"
}
}
let 사용자 = "김토파즈"
print(greet(사용자, "한국어"))
print(greet("Topaz", "Русский"))안녕하세요, 김토파즈님!
Привет, Topaz!사용자 is a variable name, just like name. Topaz keeps the characters you enter. Names match when their characters match, and the compiler rejects names that could be confused during module lookup.
Handle errors and clean up
This example returns either a port number or an error, then runs cleanup in both cases.
function parsePort(raw: string) -> Result<int, string> {
let n = toInt(raw) ?? -1
if n < 1 {
return Err("not a port: {raw}")
}
return Ok(n)
}
function startup(raw: string) -> Result<string, string> {
defer print("config closed")
let port = parsePort(raw)?
return Ok("listening on {port}")
}
print("{startup("8080")}")
print("{startup("http")}")config closed
Ok(listening on 8080)
config closed
Err(not a port: http)Result represents success as Ok and a recoverable error as Err. ? returns an Err to the caller. defer runs cleanup when the scope ends, including an early return, so both calls print config closed. Use Option with Some or None when a value may be absent. These forms give developers and code generators the same rules to follow.
Keep SQL text and values separate
This example creates a SQL template with text and two inserted values.
let table = "users"
let q = sql"select * from {table} where active = {true}"
print("{q}")<sql template, 3 part(s), 2 interpolation(s)>The output describes three text parts and two inserted values. The template keeps them separate for later use. Topaz also has p for paths, r for regular expressions, and sh for shell commands. Creating a template does not run a query or a command.
Find errors before running
This function accepts three traffic-light values and returns the next one.
type TrafficLight = "red" | "yellow" | "green"
function next(light: TrafficLight) -> TrafficLight {
return match light {
case "red" => "green"
case "green" => "yellow"
case _ => "red"
}
}The compiler checks types, resolves names, and reports missing match cases before execution. These are static checks. It cannot decide whether the program implements the logic you intended. Here, the types allow any of the three colours, so tests must check that the transitions are right. The function definition alone prints nothing.
Choose how to run your program
topaz run checks a file and executes it. topaz build creates a native executable or a package for the browser from the same source. Native builds need additional build tools. Follow First Application for the files, setup, and expected result.
The compiler you install is written in Topaz. It can compile its own source, and repeated compilation produces identical generated code. See Toolchain Status for the compilation stages, supported targets, and installation details.
For direct control of memory ownership, lifetimes, or embedded hardware, consider a systems language such as Rust, C, or Zig. For command-line tools and application logic, continue with the Learning path.
Read the language philosophy for the design reasons. The Topaz source is available at topaz.ooo/dl.