Your Go code runs anywhere TypeScript runs: Node, Bun, and the browser.
GoScript compiles Go packages into readable TypeScript modules. Goroutines,
channels, select, defer, pointers, and struct copies behave as they do in
Go, and the output is ordinary TypeScript you can import, bundle, and step
through in a debugger.
go install github.com/s4wave/goscript/cmd/goscript@latest
goscript compile --package . --output ./outputGoScript needs the Go toolchain. Install the CLI with Go:
go install github.com/s4wave/goscript/cmd/goscript@latestOr add it to a JavaScript project. The npm package runs the same compiler through your local Go toolchain and adds the TypeScript API:
bun add -d goscriptBun runs generated code directly. For Node and browsers,
bundle it with a bundler that resolves tsconfig.json paths, such as Bun,
Vite, or esbuild.
Write a Go program:
// main.go
package main
import "fmt"
type Greeter struct{ Name string }
func (g Greeter) Greet() string { return "Hello, " + g.Name + "!" }
func main() {
ch := make(chan string)
go func() { ch <- Greeter{Name: "GoScript"}.Greet() }()
fmt.Println(<-ch)
}Compile it from the module directory. GoScript also emits the packages it
imports, here fmt, so the output runs on its own:
goscript compile --package . --output ./outputPoint @goscript/* imports at the output in tsconfig.json:
{
"compilerOptions": {
"paths": { "@goscript/*": ["./output/@goscript/*"] }
}
}Run it:
$ bun run output/@goscript/example.com/hello/main.gs.ts
Hello, GoScript!Each Go package becomes a directory under output/@goscript/, named by its
import path, with one .gs.ts file per Go file and an index.ts that exports
the package. A package main runs directly; any other package is a module you
import:
import { NewUser } from '@goscript/example.com/my/module/index.js'docs/typescript.md has the full tsconfig.json for
typechecking and bundling generated code.
goscript compile --package ./pkg/... --output ./output--package takes any Go package pattern and repeats. GoScript compiles the
requested packages and every package they import. --skip-dependencies emits
only the requested packages and the runtime, for builds that compile
dependencies separately.
docs/cli.md lists every option.
goscript test compiles a package's Go tests to TypeScript and runs them with
Bun, or in Chromium with --browser. The output follows go test:
goscript test --tags goscript ./...import { compile } from 'goscript'
await compile({
pkg: '.',
output: './output',
dir: process.cwd(),
})comp, err := compiler.NewCompiler(&compiler.Config{
Dir: ".",
OutputPath: "./output",
}, nil, nil)
if err != nil {
return err
}
_, err = comp.CompilePackages(ctx, ".")github.com/s4wave/goscript/compiler/wasm builds to WebAssembly and compiles a
single Go source file to TypeScript in the page. It accepts files without
imports; the website playground uses it.
ts, err := wasm.CompileSource(src, "main")- Go language: structs, interfaces, generics, closures, slices, maps, and value copies.
- Pointers:
&x, pointers to pointers, and pointer receivers behave as in Go. - Concurrency: goroutines, channels,
select,sync,defer,panic, andrecover. - Exact integers:
int64anduint64compile tobigintand wrap like Go. - Control flow:
goto, labels, type switches, andrangeover iterator functions. - Standard library:
fmt,strings,sync,time,encoding/json,crypto, and more. - Third-party packages: go-git, klauspost/compress, blake3, protobuf-go-lite, and more.
- Go tests:
goscript testruns your Go tests on the output in Bun or Chromium. - Large programs: GoScript compiles Spacewave's browser core, including go-git.
- In the browser: the compiler runs in the page through WebAssembly.
Go packages -> type check -> semantic model -> lowered IR -> TypeScript
+ runtime + overrides
GoScript loads packages with the Go toolchain and type-checks them. It then
decides which variables need a pointer box, which functions must become
async, and how each type maps to TypeScript, before it writes any text. The
emitter renders the result, and the compiler copies the
@goscript/builtin runtime and any handwritten
overrides for packages such as sync, os, and reflect.
A function that can block on a channel, select, or a lock becomes async,
and so does every function that calls it. Goroutines run as async tasks on the
JavaScript event loop, and no WebAssembly runtime ships with your code.
docs/explainer.md walks through each stage with
generated output for structs, pointers, channels, and defer.
- The CLI and APIs take package patterns, not individual
.gofiles. - Browser compilation accepts single files without imports. Compile code with imports through the CLI or API.
unsafetype-checks, butSizeof,Alignof,Offsetof, and pointer conversions throw at runtime. Pointer arithmetic and cgo are unsupported.int,uint, and integers narrower than 64 bits are JavaScript numbers.uintanduintptrkeep full 64-bit width, butintdoes not wrap on 64-bit overflow.- A standard-library package works when GoScript ships an override for it or it compiles cleanly from Go. Sockets, processes, and plugin loading work only as far as the JavaScript host supports them.
reflectcovers types, values, struct fields, maps,MakeFunc,FuncOf, andDeepEqual, but not all of the package.goscript testsupports a subset oftestingand of thego testflags.- Async calls and
bigintarithmetic cost more than synchronous JavaScript on plain numbers.
Use GoScript when Go is the source of truth and part of your product runs in a TypeScript runtime: shared validation and business rules, TypeScript packages published from Go code, or Go framework code running in the browser without a rewrite.
GoScript is built against Spacewave, a
large Go and TypeScript application framework. Spacewave compiles its browser
core plugin through GoScript, including go-git and the go-mysql-server SQL
engine, and runs its core package tests through goscript test in CI.
GopherJS shares the goal of running Go in JavaScript and ships its own goroutine scheduler. GoScript emits readable TypeScript modules and maps goroutines onto JavaScript async functions.
bun install
bun run test
bun run lint
bun run buildbun run example compiles and runs example/simple.
bun run website:build builds the website and playground.
example/app is a full-stack application built on generated
TypeScript.
The compliance tests under tests/tests are Go programs compiled, typechecked, and run against expected output.
To fix a missing Go behavior, add a focused compiler or compliance test that reproduces it, then implement the behavior in the compiler or runtime stage responsible for it.
Open an issue for Go code GoScript cannot compile, runtime gaps, and missing standard-library overrides.
MIT