npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

gots-engine

v1.0.2

Published

Write Go inside TypeScript. Compile-time speed, runtime magic. Run Go functions directly from TypeScript via WebAssembly or native binaries.

Readme

gots-engine — Go inside TypeScript

Write Go functions directly in TypeScript files. Compile-time speed, runtime magic.

npm version npm downloads TypeScript Go Report Card Go License Tests


What is gots-engine?

gots-engine lets you embed Go code inside TypeScript using tagged template literals. It automatically compiles, caches, and runs your Go code via WebAssembly or a native binary — whichever is faster on your platform.

import { go } from 'gots-engine';

// ① Define Go functions inline
const math = await go`
  func SumN(n int) int {
    total := 0
    for i := 0; i < n; i++ { total += i }
    return total
  }
`;

// ② Call them like normal TypeScript async functions
const result = await math.call('SumN', 1_000_000);
console.log(result); // 499999500000  — runs at Go speed

No microservices. No gRPC. No child processes to manage. One file.


Why?

JavaScript/TypeScript is fast for I/O but slow for CPU-intensive work:

| Operation | JavaScript | gots-engine (WASM) | gots-engine (native) | |-----------|-----------|-------------|----------------| | Sum 1B iterations | ~2,100 ms | ~180 ms | ~95 ms | | gzip 10MB | ~890 ms | ~75 ms | ~40 ms | | Sort 1M elements | ~450 ms | ~85 ms | ~50 ms | | SHA-256 100MB | ~1,200 ms | ~95 ms | ~55 ms |

gots-engine closes this gap without leaving your TypeScript project.


Installation

npm install gots-engine

Requirements:

  • Node.js >= 18
  • Go >= 1.21 (for WASM or native backend)
  • TinyGo (optional — produces smaller WASM binaries)

Check your environment:

npx gots-engine info

Quick Start

Basic computation

import { go } from 'gots-engine';

const calc = await go`
  func Fibonacci(n int) int {
    if n <= 1 { return n }
    a, b := 0, 1
    for i := 2; i <= n; i++ { a, b = b, a+b }
    return b
  }
`;

console.log(await calc.call('Fibonacci', 45)); // 1134903170

Multiple functions in one block

const text = await go`
  import "strings"

  func CountWords(s string) int {
    return len(strings.Fields(s))
  }

  func Reverse(s string) string {
    r := []rune(s)
    for i, j := 0, len(r)-1; i < j; i, j = i+1, j-1 {
      r[i], r[j] = r[j], r[i]
    }
    return string(r)
  }
`;

const wordCount = await text.call('CountWords', 'Hello World from Go');
const reversed  = await text.call('Reverse', 'gots-engine');

Error handling

import { go, GoError } from 'gots-engine';

const safe = await go`
  import "fmt"
  func Divide(a, b float64) (float64, error) {
    if b == 0 { return 0, fmt.Errorf("division by zero") }
    return a / b, nil
  }
`;

try {
  await safe.call('Divide', 10, 0);
} catch (err) {
  if (err instanceof GoError) {
    console.log(err.goMessage); // "division by zero"
  }
}

Structs (marshalled automatically)

const sorter = await go`
  import "sort"

  type User struct {
    Name  string  \`json:"name"\`
    Score float64 \`json:"score"\`
  }

  func SortByScore(users []User) []User {
    sort.Slice(users, func(i, j int) bool {
      return users[i].Score > users[j].Score
    })
    return users
  }
`;

const sorted = await sorter.call('SortByScore', [
  { name: 'Alice', score: 95.5 },
  { name: 'Bob',   score: 87.2 },
  { name: 'Carol', score: 99.1 },
]);
// [{ name: 'Carol', score: 99.1 }, { name: 'Alice', ... }, ...]

Binary data (Uint8Array ↔ []byte)

const compress = await go`
  import (
    "bytes"
    "compress/gzip"
  )

  func GzipCompress(data []byte) ([]byte, error) {
    var buf bytes.Buffer
    w := gzip.NewWriter(&buf)
    if _, err := w.Write(data); err != nil { return nil, err }
    w.Close()
    return buf.Bytes(), nil
  }
`;

const data       = new TextEncoder().encode('Hello!'.repeat(1000));
const compressed = await compress.call('GzipCompress', data);
// compressed is Uint8Array — gzip bytes

Reusable function handles

// Get a named function as a standalone callable
const crunch = await go`
  func Crunch(n int) int {
    sum := 0
    for i := 0; i < n; i++ { sum += i * i }
    return sum
  }
`;

const crunchFn = crunch.fn('Crunch'); // () => Promise<unknown>
const results  = await Promise.all([1000, 2000, 3000].map(crunchFn));

Configuration

import { configure } from 'gots-engine';

configure({
  backend: 'auto',          // 'auto' | 'wasm-js' | 'wasm-wasip1' | 'tinygo-wasm' | 'native'
  preferNative: true,       // Use native binary on Node.js (fastest)
  compileTimeout: 60_000,   // Max compilation time (ms)
  optimize: false,          // Run wasm-opt on WASM output
  logLevel: 'warn',         // 'debug' | 'info' | 'warn' | 'error' | 'silent'
  noCache: false,           // Disable disk cache
  
  // Security — restrict what Go imports are allowed
  deniedImports: ['os/exec', 'plugin'],
  allowedImports: [],       // If set, only these external imports are allowed
});

Backend Selection

| Backend | Where it works | Speed | WASM size | Requires | |---------|---------------|-------|-----------|----------| | native | Node.js only | ⚡⚡⚡ Fastest | N/A | Go | | tinygo-wasm | Browser + Node | ⚡⚡ | ~50-300KB | TinyGo | | wasm-wasip1 | Node 20+ / Deno / Bun | ⚡⚡ | ~2-8MB | Go 1.21+ | | wasm-js | Browser + Node | ⚡ | ~2-8MB | Go 1.11+ |

'auto' (default) picks the best backend for your environment automatically.


Build Plugins

Vite

// vite.config.ts
import { defineConfig } from 'vite';
import { gots-enginePlugin } from 'gots-engine/vite';

export default defineConfig({
  plugins: [
    gots-enginePlugin({
      preferTinyGo: true,    // Smaller WASM for browser
      precompile: true,      // Compile at build time, not runtime
      typegen: true,         // Generate .d.ts from Go structs
      typegenOutput: 'src/generated/gots-engine.d.ts',
    }),
  ],
});

esbuild

import esbuild from 'esbuild';
import { gots-engineEsbuildPlugin } from 'gots-engine/esbuild';

await esbuild.build({
  entryPoints: ['src/index.ts'],
  bundle: true,
  plugins: [gots-engineEsbuildPlugin({ precompile: true })],
});

webpack

// webpack.config.js
const { gots-engineWebpackPlugin } = require('gots-engine/webpack');

module.exports = {
  plugins: [new gots-engineWebpackPlugin({ precompile: true, typegen: true })],
};

Next.js

// next.config.ts
import { withgots-engine } from 'gots-engine/next';

export default withgots-engine({
  // your Next.js config
}, {
  serverBackend: 'native',      // Fast on Node.js server
  clientBackend: 'tinygo-wasm', // Small for browser
  precompile: true,
});

CLI

# Show Go toolchain, TinyGo, cache stats, and recommended backend
npx gots-engine info

# Pre-compile all Go blocks in TypeScript files (for CI/production)
npx gots-engine build
npx gots-engine build "src/**/*.ts" --backend tinygo-wasm --optimize
npx gots-engine build --typegen --typegen-output src/generated/gots-engine.d.ts

# Validate Go blocks without compiling (for linting/CI)
npx gots-engine check src/index.ts
npx gots-engine check  # scans all src/**/*.ts files

# Clear the compiled WASM/binary cache
npx gots-engine clean
npx gots-engine clean --force

Type Safety

gots-engine automatically generates TypeScript types from your Go structs and function signatures:

npx gots-engine build --typegen

This produces a src/generated/gots-engine.d.ts file:

// Auto-generated by gots-engine

export interface User {
  name: string;
  score: number;
  age: number;
}

export type FnSortByScore = (users: User[]) => Promise<User[]>;

Caching

gots-engine uses a two-level cache to make repeated runs instant:

  • Level 1 (Memory): Zero-overhead lookups within a process session
  • Level 2 (Disk): ~/.gots-engine/cache/ — persists across restarts

Each cache entry = <hash>.wasm + <hash>.meta.json

The hash is computed from: Go source code + Go version + gots-engine cache version. Any change to your Go code automatically triggers recompilation.


Security

By default, gots-engine blocks these import paths:

  • os/exec — prevents shell command execution
  • plugin — prevents loading arbitrary Go plugins

Add custom restrictions via gots-engineConfig:

configure({
  deniedImports: ['net/http'], // Block outbound HTTP from Go
  allowedImports: ['fmt', 'strings', 'encoding/json'], // Allowlist mode
});

Architecture

TypeScript                Go Runtime
────────────────          ────────────────────────────
await go`               ──→  GoParser.parse()
  func Foo(...) ...          GoCache.get(hash)
`                            GoCompiler.compile()
                             ↓
                        [js/wasm]  ← syscall/js bridge
                        [wasip1]   ← JSON-RPC via stdin/stdout
                        [native]   ← JSON-RPC via stdin/stdout
                             ↓
handle.call('Foo', ...)  ──→  GoBridge.marshalArgs()
                              runtime.call()
                              GoBridge.unmarshalResult()
                         ←── TypeScript value

Project Structure

gots-engine/
├── src/
│   ├── index.ts                 # Public API: go(), GoError, configure()
│   ├── core/
│   │   ├── types.ts             # All TypeScript type definitions
│   │   ├── errors.ts            # GoError, GoCompileError, etc.
│   │   ├── parser.ts            # Go AST parser (regex + mini-parser)
│   │   ├── compiler.ts          # go/tinygo build orchestrator
│   │   ├── template-generator.ts # Wraps user code in compilable Go
│   │   ├── cache.ts             # Two-level cache (memory + disk)
│   │   ├── bridge.ts            # Type marshalling (TS ↔ Go)
│   │   ├── runtime.ts           # go() tagged template implementation
│   │   ├── config.ts            # Global gots-engineConfig
│   │   └── logger.ts            # Internal logger
│   ├── backends/
│   │   ├── backend-selector.ts  # Picks best backend automatically
│   │   ├── wasm/wasm-backend.ts # js/wasm + WASI WASM runtime
│   │   └── native/native-backend.ts # Native binary JSON-RPC runtime
│   ├── toolchain/
│   │   ├── go-detector.ts       # Detects Go installation + version
│   │   └── tinygo-detector.ts   # Detects TinyGo installation
│   ├── type-system/
│   │   ├── type-mapper.ts       # Go ↔ TypeScript type mapping
│   │   └── validator.ts         # Runtime type validation
│   ├── build-plugin/
│   │   ├── vite-plugin.ts       # Vite integration
│   │   ├── esbuild-plugin.ts    # esbuild integration
│   │   ├── webpack-plugin.ts    # webpack 5 integration
│   │   ├── rollup-plugin.ts     # Rollup integration
│   │   └── next-plugin.ts       # Next.js withgots-engine() wrapper
│   └── cli/
│       ├── index.ts             # CLI entry point
│       └── commands/            # info, build, check, clean
├── go/
│   ├── runtime/                 # Go-side RPC + marshalling helpers
│   └── templates/               # Go code templates
├── wasm-runtime/
│   └── wasm_exec.cjs            # Bundled Go WASM exec shim
└── test/
    └── unit/                    # 67 passing unit tests

Known Limitations

  1. Goroutines in WASM — Limited support. Use native backend for goroutine-heavy code.
  2. TinyGo compatibility — Not all stdlib packages work with TinyGo. gots-engine auto-detects incompatible imports.
  3. First-run compilation — Initial await go\...`` takes 5–30s. Subsequent runs use the cache.
  4. Browser WASM size — Standard Go WASM is 2–8MB. Use preferTinyGo: true for 50–300KB output.
  5. Edge runtime — Native backend not available; use wasm-wasip1 for Cloudflare Workers.

Roadmap

| Version | Feature | |---------|---------| | 1.0 | ✅ Core runtime, all backends, CLI, build plugins | | 1.1 | chan T → AsyncIterable<T> — streaming from Go to TypeScript | | 1.2 | VSCode extension with Go LSP inside TypeScript files | | 2.0 | Reverse direction — call TypeScript from Go via callbacks |


License

MIT © BRAHIM TIMEZGHINE TIMSoftDZ gots-engine contributors