# How to Integrate typescript-go into an Existing Go Project: 3 Methods Explained

> Integrate typescript-go into your existing Go project using 3 methods: tsg CLI, embedding the compiler, or the JSON-RPC API. Boost your Go development today.

- Repository: [Microsoft/typescript-go](https://github.com/microsoft/typescript-go)
- Tags: how-to-guide
- Published: 2026-04-25

---

**You can integrate typescript-go into an existing Go project by either running the `tsgo` CLI tool, embedding the compiler as a library via `execute.CommandLine` with a custom `System` implementation, or deploying the JSON-RPC/MessagePack API server for cross-process communication.**

**typescript-go** is Microsoft's official TypeScript compiler rewritten in Go, offering full compatibility with existing [`tsconfig.json`](https://github.com/microsoft/typescript-go/blob/main/tsconfig.json) configurations while providing native Go APIs for programmatic control. Whether you need a drop-in replacement for `tsc` or a compiler embedded within your build pipeline, the repository provides three distinct integration paths based on the `cmd/tsgo`, `internal/execute`, and `internal/api` packages.

## Installation and Module Configuration

Add the typescript-go module to your project using the standard Go toolchain:

```bash
go get github.com/microsoft/typescript-go@latest

```

This updates your `go.mod` to include the dependency:

```go
module your/project

go 1.26

require github.com/microsoft/typescript-go v0.0.0-<commit-hash>

```

The module exposes both high-level CLI wrappers and low-level compiler primitives, allowing you to choose the appropriate abstraction level for your integration.

## Method 1: Running the tsgo CLI Tool

The simplest integration method uses the `cmd/tsgo` binary as a drop-in replacement for the traditional TypeScript compiler. This approach requires minimal code changes and supports all standard `tsc` flags.

Build the CLI from source:

```bash
go build -o tsgo ./cmd/tsgo
./tsgo --project tsconfig.json

```

Under the hood, [`cmd/tsgo/main.go`](https://github.com/microsoft/typescript-go/blob/main/cmd/tsgo/main.go) parses command-line arguments and delegates to `execute.CommandLine` in [`internal/execute/tsc/compile.go`](https://github.com/microsoft/typescript-go/blob/main/internal/execute/tsc/compile.go). This function orchestrates the entire compilation pipeline including configuration parsing, type checking, and file emission.

**When to use this method:** Choose the CLI approach when you need a standalone binary for build scripts or CI/CD pipelines without requiring programmatic access to compilation results.

## Method 2: Embedding the Compiler as a Library

For custom build pipelines or IDE integrations, embed the compiler directly by implementing the `tsc.System` interface and invoking `execute.CommandLine` programmatically.

The interface definition resides in [`internal/execute/tsc/compile.go`](https://github.com/microsoft/typescript-go/blob/main/internal/execute/tsc/compile.go) and requires methods for file system access, environment variables, and output writing. Reference the `osSys` type in [`cmd/tsgo/sys.go`](https://github.com/microsoft/typescript-go/blob/main/cmd/tsgo/sys.go) as a production-ready implementation template.

Create a minimal wrapper:

```go
package tsintegration

import (
	"io"
	"os"
	"time"

	"github.com/microsoft/typescript-go/internal/bundled"
	"github.com/microsoft/typescript-go/internal/execute/tsc"
	"github.com/microsoft/typescript-go/internal/tspath"
	"github.com/microsoft/typescript-go/internal/vfs"
	"github.com/microsoft/typescript-go/internal/vfs/osvfs"
	"golang.org/x/term"
)

type System struct {
	writer             io.Writer
	fs                 vfs.FS
	defaultLibraryPath string
	cwd                string
	start              time.Time
}

func (s *System) Writer() io.Writer                { return s.writer }
func (s *System) FS() vfs.FS                        { return s.fs }
func (s *System) DefaultLibraryPath() string       { return s.defaultLibraryPath }
func (s *System) GetCurrentDirectory() string      { return s.cwd }
func (s *System) WriteOutputIsTTY() bool           { return term.IsTerminal(int(os.Stdout.Fd())) }
func (s *System) GetWidthOfTerminal() int          { return 80 }
func (s *System) GetEnvironmentVariable(n string) string { return os.Getenv(n) }
func (s *System) Now() time.Time                   { return time.Now() }
func (s *System) SinceStart() time.Duration        { return time.Since(s.start) }

func NewSystem() *System {
	cwd, _ := os.Getwd()
	return &System{
		writer:             os.Stdout,
		cwd:                tspath.NormalizePath(cwd),
		fs:                 bundled.WrapFS(osvfs.FS()),
		defaultLibraryPath: bundled.LibPath(),
		start:              time.Now(),
	}
}

// Compile executes the TypeScript compiler with the provided arguments.
func Compile(args []string) tsc.ExitStatus {
	sys := NewSystem()
	result := execute.CommandLine(sys, args, nil)
	return result.Status
}

```

Use the wrapper in your application:

```go
package main

import (
	"fmt"
	"yourproject/tsintegration"
)

func main() {
	// Equivalent to: tsgo --project tsconfig.json --noEmit
	status := tsintegration.Compile([]string{"--project", "tsconfig.json", "--noEmit"})
	
	if status == 0 {
		fmt.Println("TypeScript compilation succeeded")
	} else {
		fmt.Printf("Compilation failed with exit code %d\n", status)
	}
}

```

The `execute.CommandLine` function handles the complete compilation lifecycle: parsing [`tsconfig.json`](https://github.com/microsoft/typescript-go/blob/main/tsconfig.json), creating a `compiler.Program`, running type checking, and managing incremental builds or watch modes.

**When to use this method:** Choose library embedding when you need to capture compilation status codes, intercept diagnostics, or integrate TypeScript compilation into larger Go-based build systems.

## Method 3: Deploying the JSON-RPC/MessagePack API Server

For language-server integrations or scenarios requiring process isolation, typescript-go provides a stdio-based API server via `internal/api`.

Initialize the server:

```go
package main

import (
	"context"
	"os"
	"os/signal"
	"syscall"

	"github.com/microsoft/typescript-go/internal/api"
	"github.com/microsoft/typescript-go/internal/bundled"
)

func main() {
	opts := &api.StdioServerOptions{
		Err:                os.Stderr,
		Cwd:                ".",
		DefaultLibraryPath: bundled.LibPath(),
		Async:              false, // false = JSON-RPC, true = MessagePack
	}
	
	srv := api.NewStdioServer(opts)

	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
	defer stop()

	if err := srv.Run(ctx); err != nil {
		panic(err)
	}
}

```

The server reads requests from `stdin` (or named pipes) and returns compilation results via the configured protocol. The [`cmd/tsgo/api.go`](https://github.com/microsoft/typescript-go/blob/main/cmd/tsgo/api.go) file provides the reference implementation for launching this server from command-line contexts.

**When to use this method:** Choose the API server for VS Code extensions, long-running build daemons, or polyglot environments where Go code must communicate with TypeScript tooling written in other languages.

## Integration Method Comparison

Select the appropriate integration strategy based on your architectural requirements:

- **CLI Tool**: Use when replacing `tsc` in existing build scripts without code changes. Entry point: [`cmd/tsgo/main.go`](https://github.com/microsoft/typescript-go/blob/main/cmd/tsgo/main.go).
- **Library Embedding**: Use for custom build orchestration in Go. Entry point: `execute.CommandLine` with a custom `System` implementation.
- **API Server**: Use for IDE integrations or cross-language services. Entry point: `api.NewStdioServer`.

## Summary

Integrating typescript-go into an existing Go project offers three distinct approaches depending on your isolation and control requirements:

- Install via `go get github.com/microsoft/typescript-go` to add the module to your project
- **Run the CLI** by building `cmd/tsgo` for drop-in `tsc` replacement functionality
- **Embed as a library** by implementing the `tsc.System` interface and calling `execute.CommandLine` from [`internal/execute/tsc/compile.go`](https://github.com/microsoft/typescript-go/blob/main/internal/execute/tsc/compile.go)
- **Deploy the API server** using `api.NewStdioServer` from `internal/api` for JSON-RPC or MessagePack-based inter-process communication
- Reference [`cmd/tsgo/sys.go`](https://github.com/microsoft/typescript-go/blob/main/cmd/tsgo/sys.go) for the canonical `System` implementation when embedding the compiler

## Frequently Asked Questions

### Can typescript-go use existing tsconfig.json files?

Yes. The `execute.CommandLine` function in [`internal/execute/tsc/compile.go`](https://github.com/microsoft/typescript-go/blob/main/internal/execute/tsc/compile.go) fully parses and respects [`tsconfig.json`](https://github.com/microsoft/typescript-go/blob/main/tsconfig.json) configurations, including compiler options, file includes, and project references. Pass `--project tsconfig.json` in your arguments array to specify the configuration file path.

### How does typescript-go handle the TypeScript standard library?

The compiler bundles standard library definitions ([`.d.ts`](https://github.com/microsoft/typescript-go/blob/main/.d.ts) files) internally via the `internal/bundled` package. When implementing the `tsc.System` interface, return `bundled.LibPath()` from the `DefaultLibraryPath()` method to provide access to these embedded type definitions without requiring external `node_modules` installations.

### What is the performance difference between library embedding and the CLI?

Both methods use the same underlying compilation engine in [`internal/execute/tsc/compile.go`](https://github.com/microsoft/typescript-go/blob/main/internal/execute/tsc/compile.go). Library embedding eliminates process startup overhead and allows reusing `vfs.FS` instances across multiple compilations, potentially improving performance for incremental builds or watch mode implementations compared to spawning separate CLI processes.

### Is the API server compatible with the Language Server Protocol (LSP)?

No. The `internal/api` server uses a custom JSON-RPC/MessagePack protocol specific to typescript-go's compiler operations, distinct from LSP. It exposes compilation and project management functions rather than editor-oriented features like hover information or go-to-definition. For LSP functionality, you would need to build a separate adapter layer that calls the typescript-go library programmatically.