Backend Development 13 min read

Can Golang‑Compiled TypeScript Outrun Node, Bun, and Deno? Benchmark Results Revealed

This article examines Microsoft’s new Golang‑based TypeScript compiler by benchmarking recursive Fibonacci, merge sort, and matrix multiplication across Golang, Node.js, Bun, and Deno, revealing that while Golang remains faster, Bun narrows the gap, and the promised ten‑fold speedup is not universally achieved.

Code Mala Tang
Code Mala Tang
Code Mala Tang
Can Golang‑Compiled TypeScript Outrun Node, Bun, and Deno? Benchmark Results Revealed

TypeScript has long aimed to improve developer experience, but as projects grow, compilation time, editor responsiveness, and build speed become challenges. Microsoft announced that the TypeScript compiler and tools are being natively ported to Golang, promising a ten‑fold compilation speed increase and better memory efficiency.

Benchmark Setup

To compare performance, a simple benchmark suite was created that evaluates three CPU‑intensive tasks:

Fibonacci (recursive) – quick test of CPU performance.

Merge sort – sorting benchmark to measure algorithm efficiency.

Matrix multiplication – parallelizable task that benefits from concurrent execution.

The benchmarks were run in the following environments:

Golang (direct compile and execute)

Node.js (using --experimental-strip-types to support native TypeScript)

Bun (claimed to be the fastest JavaScript runtime)

Deno (Rust‑based, optimized for TypeScript)

Golang Example Code

<code>package main

import (
    "fmt"
    "math/rand"
    "sync"
    "time"
)

func fibonacci(n int) int {
    if n <= 1 {
        return n
    }
    return fibonacci(n-1) + fibonacci(n-2)
}

func mergeSort(arr []int) []int {
    if len(arr) <= 1 {
        return arr
    }
    mid := len(arr) / 2
    left := mergeSort(arr[:mid])
    right := mergeSort(arr[mid:])
    return merge(left, right)
}

func merge(left, right []int) []int {
    result := []int{}
    i, j := 0, 0
    for i < len(left) && j < len(right) {
        if left[i] < right[j] {
            result = append(result, left[i])
            i++
        } else {
            result = append(result, right[j])
            j++
        }
    }
    result = append(result, left[i:]...)
    result = append(result, right[j:]...)
    return result
}

func multiplyMatrices(A, B [][]float64, result [][]float64, wg *sync.WaitGroup, start, end int) {
    defer wg.Done()
    for i := start; i < end; i++ {
        for j := 0; j < len(B[0]); j++ {
            for k := 0; k < len(A[0]); k++ {
                result[i][j] += A[i][k] * B[k][j]
            }
        }
    }
}

func parallelMultiplyMatrices(A, B [][]float64) [][]float64 {
    size := len(A)
    result := make([][]float64, size)
    for i := range result {
        result[i] = make([]float64, size)
    }
    var wg sync.WaitGroup
    workers := 4
    chunkSize := size / workers
    for i := 0; i < workers; i++ {
        start := i * chunkSize
        end := (i + 1) * chunkSize
        if i == workers-1 {
            end = size
        }
        wg.Add(1)
        go multiplyMatrices(A, B, result, &wg, start, end)
    }
    wg.Wait()
    return result
}

func benchmark() {
    fmt.Println("Starting benchmarks...")

    fibNum := 45
    startFib := time.Now()
    fmt.Println("Fibonacci(", fibNum, "):", fibonacci(fibNum))
    fmt.Println("Fibonacci Execution Time:", time.Since(startFib))

    arraySize := 5000000
    arr := make([]int, arraySize)
    for i := range arr {
        arr[i] = rand.Intn(1000000)
    }
    startSort := time.Now()
    mergeSort(arr)
    fmt.Println("Merge Sort Execution Time:", time.Since(startSort))

    matrixSize := 1000
    A := make([][]float64, matrixSize)
    B := make([][]float64, matrixSize)
    for i := range A {
        A[i] = make([]float64, matrixSize)
        B[i] = make([]float64, matrixSize)
        for j := range A[i] {
            A[i][j] = rand.Float64() * 10
            B[i][j] = rand.Float64() * 10
        }
    }
    startMatrix := time.Now()
    parallelMultiplyMatrices(A, B)
    fmt.Println("Matrix Multiplication Execution Time:", time.Since(startMatrix))
}

func main() {
    benchmark()
}
</code>

TypeScript Example Code

<code>import { Worker } from "node:worker_threads";

function fibonacci(n: number): number {
    if (n <= 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
}

function mergeSort(arr: number[]): number[] {
    if (arr.length <= 1) return arr;
    const mid = Math.floor(arr.length / 2);
    const left = mergeSort(arr.slice(0, mid));
    const right = mergeSort(arr.slice(mid));
    return merge(left, right);
}

function merge(left: number[], right: number[]): number[] {
    const result: number[] = [];
    let i = 0, j = 0;
    while (i < left.length && j < right.length) {
        result.push(left[i] < right[j] ? left[i++] : right[j++]);
    }
    return [...result, ...left.slice(i), ...right.slice(j)];
}

async function parallelMultiplyMatrices(A: number[][], B: number[][]): Promise<number[][]> {
    const size = A.length;
    const result = Array.from({ length: size }, () => Array(size).fill(0));
    const numWorkers = 4;
    const chunkSize = Math.ceil(size / numWorkers);
    const workers: Worker[] = [];
    for (let i = 0; i < numWorkers; i++) {
        const worker = new Worker("./matrixWorker.js");
        workers.push(worker);
    }
    await Promise.all(
        workers.map((worker, i) => new Promise<void>((resolve) => {
            const start = i * chunkSize;
            const end = Math.min((i + 1) * chunkSize, size);
            worker.postMessage({ A, B, start, end });
            worker.on("message", (data) => {
                const { result: partialResult, start, end } = data;
                for (let i = start; i < end; i++) {
                    result[i] = partialResult[i];
                }
                worker.terminate();
                resolve();
            });
        }))
    );
    return result;
}

function measureExecutionTime(label: string, fn: () => void) {
    console.time(label);
    fn();
    console.timeEnd(label);
}

async function benchmark() {
    console.log("Starting benchmarks...");
    measureExecutionTime("Fibonacci Execution Time", () => {
        console.log(`Fibonacci(45):`, fibonacci(45));
    });
    measureExecutionTime("Merge Sort Execution Time", () => {
        const arraySize = 5000000;
        const arr = Array.from({ length: arraySize }, () => Math.floor(Math.random() * 1_000_000));
        mergeSort(arr);
    });
    const matrixSize = 1000;
    const A = Array.from({ length: matrixSize }, () => Array.from({ length: matrixSize }, () => Math.random() * 10));
    const B = Array.from({ length: matrixSize }, () => Array.from({ length: matrixSize }, () => Math.random() * 10));
    console.time("Matrix Multiplication Execution Time");
    await parallelMultiplyMatrices(A, B);
    console.timeEnd("Matrix Multiplication Execution Time");
}

benchmark();
</code>

matrixWorker.js Example Code

<code>import { parentPort } from "node:worker_threads";

parentPort.on("message", (data) => {
    const { A, B, start, end } = data;
    const size = A.length;
    const result = Array.from({ length: size }, () => Array(size).fill(0));
    for (let i = start; i < end; i++) {
        for (let j = 0; j < size; j++) {
            for (let k = 0; k < size; k++) {
                result[i][j] += A[i][k] * B[k][j];
            }
        }
    }
    parentPort.postMessage({ result, start, end });
});
</code>

Benchmark Results

Golang Execution Results

Fibonacci execution time: 6.016 seconds

Merge sort execution time: 1.761 seconds

Matrix multiplication execution time: 6.371 seconds

TypeScript Execution Results (Node.js)

Fibonacci execution time: 12.665 seconds

Merge sort execution time: 5.031 seconds

Matrix multiplication execution time: 7.648 seconds

TypeScript Execution Results (Bun)

Fibonacci execution time: 10.33 seconds

Merge sort execution time: 3.91 seconds

Matrix multiplication execution time: 5.51 seconds

TypeScript Execution Results (Deno)

Fibonacci execution time: 12.678 seconds

Merge sort execution time: 5.102 seconds

Matrix multiplication execution time: 9.443 seconds

Observations

Golang is significantly faster overall, but it does not achieve a universal ten‑fold speedup over TypeScript.

Bun delivers the best TypeScript performance, outperforming both Node.js and Deno in all tests.

Matrix multiplication shows the largest variance due to differing parallel execution models.

Conclusion

Although Golang remains faster, it does not consistently deliver the advertised ten‑fold improvement. The benchmarks demonstrate that TypeScript performance heavily depends on the runtime environment. With Bun’s support, the gap shrinks dramatically, making TypeScript a viable option even for CPU‑intensive tasks.

The key insight is that Golang is not a direct competitor to TypeScript but rather a complementary tool. The new TypeScript‑to‑Golang compiler aims to accelerate development, reduce build times, and improve memory efficiency, ultimately contributing to a more efficient JavaScript ecosystem.

Future work will continue to refine these benchmarks and track performance trends across runtimes. JavaScript developers can rest assured that TypeScript is getting faster, and the ecosystem is evolving to meet performance demands.

PerformanceTypeScriptgolangNode.jsBenchmarkBunDeno
Code Mala Tang
Written by

Code Mala Tang

Read source code together, write articles together, and enjoy spicy hot pot together.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.