Go to TypeScript compiler
Write it in Go.Run it anywhere.
GoScript compiles Go packages into readable TypeScript. Bring the standard library, your favorite packages, and goroutines to any web browser, Node, or Bun, without shipping a WebAssembly runtime.
package main import "fmt" func main() { ch := make(chan string) go func() { ch <- "Hello from a goroutine" }() fmt.Println(<-ch) }
export async function main(): globalThis.Promise<void> { let ch = $.makeChannel<string>(0, "", "both") queueMicrotask(async () => { await $.chanSend(ch, "Hello from a goroutine") }) await fmt.Println(await $.chanRecv(ch)) }
12x smaller than Go WebAssembly for hello world
async and await at every blocking call
No runtime beyond a small TypeScript library
Why Go
Everything Go gives you, in the browser
Write the code once in Go and keep the tools that make Go pleasant. GoScript compiles the program you already have, so its packages, tests, and concurrency come with it.
Standard library
fmt, strings, sync,
time, encoding/json, and
crypto compile with your code.
Go packages
Import modules as usual. go-git, klauspost/compress, and blake3 run on the output.
Concurrency
Goroutines, channels, select, and
sync keep their Go semantics on the event loop.
Go tests
goscript test runs your Go tests on the output, in
Bun or in Chromium.
Bundle size
A fraction of the bytes
GoScript output is ordinary TypeScript modules, so your bundler minifies and tree-shakes it like any other code. The same Go program built for WebAssembly ships the whole Go runtime.
Hello world with fmt12x smaller
encoding/json, sort, and
strings13x smaller
Spacewave browser core, with go-git4x smaller
Sizes are Brotli-compressed. The GoScript output is bundled with Bun
and minified with oxc. The WebAssembly builds use Go 1.27.1 with
-trimpath -ldflags='-s -w' and exclude the 17 KB
wasm_exec.js loader.
Runs on the engine
Plain async and await
A Go function that can block compiles to an
async function, so TypeScript calls it with
await. A js.FuncOf callback that blocks
returns a Promise to its JavaScript caller, and goroutines run as
async tasks beside the rest of the page.
Go values are ordinary JavaScript objects, so the engine's JIT optimizes the hot paths and its garbage collector frees what the program drops. A WebAssembly program runs its own collector inside linear memory, which grows but never shrinks.
import { NewUser } from '@goscript/example.com/my/module/index.js' // A Go function that blocks is an async function here. const user = await NewUser('gopher') console.log(user.Name)
Install
Compile your first package
GoScript needs the Go toolchain. Bun runs the output directly. For
Node and browsers, bundle it with a bundler that reads
tsconfig.json paths, such as Bun, Vite, or esbuild.
The npm package runs the same compiler and adds a TypeScript API:
bun add -d goscript.
-
Install the compiler
shell$ go install github.com/s4wave/goscript/cmd/goscript@latest -
Compile the package in the current directory
shell$ goscript compile --package . --output ./output -
Run it, with
@goscript/*mapped to the outputshell$ bun run output/@goscript/example.com/hello/main.gs.ts
Limitations
What to know first
GoScript compiles most Go code as written. These are the known gaps.
Integers
int is a JavaScript number. It loses precision
past 253 and does not wrap at 64 bits. Use
int64 or uint64 where a value needs
exact 64-bit arithmetic: both compile to bigint
and wrap as in Go.
unsafe and cgo
cgo and pointer arithmetic are unsupported. Code using
unsafe type-checks, but Sizeof,
Alignof, Offsetof, and pointer
conversions throw at runtime.
Standard library and host APIs
A standard library package works when GoScript ships an
override for it or it compiles cleanly from Go source.
Sockets, processes, and plugins work only as far as the
JavaScript host allows. reflect covers types,
values, struct fields, maps, MakeFunc, and
DeepEqual, but not the whole package.
Tooling
The CLI and APIs take package patterns, not individual
.go files. The in-browser compiler behind the
playground compiles a single file without imports.
goscript test supports a subset of
testing and of the go test flags.
Speed
Async calls and bigint arithmetic cost more than
synchronous JavaScript on plain numbers. GoScript makes a
function async only when it can block.