Skip to content
LogoLogo

Platforms & Targets

Compile one program without hiding its host dependencies

VibeLang is designed to target TypeScript, native code, and Wasm. Portability is checked through the same requirement system used for application services.

Target Families

TargetIntended outputHost examples
TypeScriptordinary TypeScript or JavaScriptNode, Bun, Deno, browser, edge
Nativenear-native code through LLVMserver, CLI, worker
Wasmportable WebAssemblybrowser, WASI, sandbox

The TypeScript target supports the complete TypeScript language. Native and Wasm targets classify features according to whether they can be implemented safely and predictably.

Platform as Capability

Host facilities are not unconditional globals in authored .vibe code:

function refreshCache(): Result<void, HttpError | FileError> {
  const clock = Clock.context()
  const http = HttpClient.context()
  const fs = FileSystem.context()
  const data = http.get(cacheUrl(clock.today())).unwrap()
  fs.writeBytes(cachePath, data.body).unwrap()
}

The compiler records exactly what the function needs from its inherited .context() calls. Requirements propagate through ordinary callers without context parameters, and a deployment layer supplies implementations valid for its target.

process, window, document, ambient filesystem access, and ambient network access are modeled as requirements rather than universally available globals.

Feature Classification

VibeLang classifies TypeScript and JavaScript behavior in three groups:

  1. Portable — implemented on TypeScript and native targets.
  2. TypeScript-required — valid, but adds the built-in TypeScript requirement.
  3. Forbidden — unavailable in authored .vibe code.

For example, any and eval are valid on the TypeScript target but add TypeScript. Type-only imports do not add a runtime requirement.

Native Pins

A native pin is a checked assertion that a function's complete dependency graph can run without the TypeScript requirement:

// Exact modifier spelling is still open.
native function checksum(bytes: Uint8Array): Digest {
  return Hash.blake3(bytes)
}

If a transitive call, provider, or dynamic feature requires TypeScript, compilation fails with the dependency path that introduced it.

Selecting a Target

Use comptime.target when the implementation differs by output environment:

import { comptime } from "vibelang:comptime"
 
const implementations = {
  node: NodeFileSystem,
  bun: BunFileSystem,
  deno: DenoFileSystem,
  native: NativeFileSystem,
  wasm: WasiFileSystem,
}
 
const FileSystemLive = comptime(implementations[comptime.target])

Unselected implementations are not emitted.

Foreign Sources

Zig and Rust source modules import directly, with compiler-generated typed bindings:

import { hashMany } from "./hash.zig" with { type: "zig" }
import { parse } from "./parser.rs" with { type: "rust" }

The compiler owns toolchain invocation and caching. The import's types, source maps, selected target, toolchain versions, feature flags, and foreign dependency graph contribute to its cache identity. Whether a source import becomes native code, Wasm, or a TypeScript-runtime bridge is target- and toolchain-driven; the exact selection policy remains open.

The TypeScript target also supports existing Node-API npm packages, including addons built with napi-rs:

import { parse } from '@acme/parser-native'

These packages keep their published TypeScript declarations and runtime behavior. Node.js and Bun load their .node binaries through Node-API—Bun uses its napi loader for .node—but that host-specific dependency is not silently portable to native or Wasm targets.

Runtime Model

Native output is expected to use a Go-like compiled runtime with garbage collection. Closures, classes, generics, unions, and async functions are not rejected merely because they need runtime support.

Backend-specific lowering is allowed. The source-level failure, requirement, and control-flow semantics remain consistent.