Warning: Crux is currently in preview status. While it's possible to write programs with it today, there are many rough edges, and not every feature described here is complete. You can help by sharing your thoughts - click the feedback button below! Or join the community on Slack.

Crux is statically-typed, compiles to JavaScript, and emphasizes familiarity, productivity, and soundness.

Crux is designed to be as lightweight in small projects as it is reliable and maintainable in large projects.

fun getFolderContents(folder) {
  let rv = mutable []

  let contents: [String] = fs.readdirSync(folder)
  for entry in contents {
    let absEntry = combine(folder, entry)
    let stat = fs.lstatSync(absEntry)
    if stat.isFile() && (entry->endsWith(".jpeg") || entry->endsWith(".jpg")) {

  return rv

What's Special?

Bidirectional Type Inference

Unlike other statically typed languages, Crux's type inference algorithm means the programmer is never forced to write type annotations on functions or variables.

let output = mutable []
output->append("hello world")
// output is inferred to be a MutableArray<String>

Integration with npm and JavaScript

Crux code integrates directly with existing JavaScript -- import existing JS libraries or publish your package on npm.

declare require<any>: String => any
let fs = require("fs")

type Stat = {
  length: Number,
  mtime: Number,
  ctime: Number,

// jsffi verifies all of the types used
// in the function are natural JS data
export jsffi fun statFiles(
  files: [String]
): Dict<Stat> {
  // ...

Unlike other compile-to-JavaScript languages (e.g. Scala.js, GHCJS, Emscripten), Crux's concepts map directly to ES6, so the generated code is clean, debuggable, and has predictable performance.


Crux is sound - never worry about missing properties or "undefined is not a function" again.

Rich Data Types

Unlike TypeScript, Crux allows non-native data types to use the same syntax and operators as native data types.

fun bigmad(x: Int64, y: Int64, z: Int64) {
  return x * y + z

Collections are also consistent. The length of any collection is len(c) and iteration across any iterable (set, map, slice, range) uses the same for loop syntax.

for (index, value) in array->enumerate() { ... }
for (key, value) in dict->enumerate() { ... }


subscribe via RSS