> ## Documentation Index
> Fetch the complete documentation index at: https://forst-lang.org/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Mix with Go packages

> Transpile to Go, import packages, and mix .ft with .go in one module.

Forst transpiles to **Go**. You keep the same module graph, deployment, and ecosystem. See [Language overview](/docs/language/overview) for syntax. This page covers import paths, Go call lowering, and mixed modules.

## Transpile to idiomatic Go

Every `.ft` file compiles to Go source in your module. The output is an ordinary, readable Go source file. Struct fields, error returns, and control flow follow familiar Go patterns.

Shape fields lower to unexported Go identifiers by default. For JSON marshaling (sidecar invoke, HTTP handlers), enable **`-export-struct-fields`** or **`compiler.exportStructFields`** in `ftconfig.json` to emit exported fields with `json` tags.

Compile a `.ft` file to Go:

```bash theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}}
npx forst build handlers/orders.ft
```

Run the result with the standard toolchain:

```bash theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}}
go build ./...
go test ./...
```

## Aligned with Go

Much of Forst mirrors Go syntax: `package`, `import`, `func`, `if`/`for`/`range`, `defer`, `go` goroutines. A minimal program can be identical in Forst and Go. See [Language overview](/docs/language/overview).

Forst adds structural typing, constraints, `ensure`, and nominal errors on top of that base.

## Import Go packages

Call into the standard library and third-party modules with qualified names:

<Tabs>
  <Tab title="Forst">
    ```ft theme={"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}}
    package main

    import "fmt"

    func main() {
    	fmt.Println("Hello from Go")
    }
    ```
  </Tab>

  <Tab title="Generated Go">
    ```go theme={"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}}
    // forst build
    package main

    import "fmt"

    func main() {
    	fmt.Println("Hello from Go")
    }
    ```
  </Tab>
</Tabs>

The compiler loads Go packages via **`go/packages`** and type-checks Forst↔Go calls when imports resolve. Supported mappings today include primitives, slices, pointers, `error`, and `interface{}` (including variadic calls).

Go functions that return **`(T, error)`** map to **`Result(T, Error)`** in Forst at call sites. That applies to the **result type** of the call and to trailing expressions in [implicit returns](/docs/language/errors-and-result#return-inference-and-implicit-returns). This differs from using **`println`** / **`print`** for void side effects inside a function that should not return a value.

## Slice subslices

Forst slice values (`[]T`) support three-index subslice syntax, lowered to Go slice expressions:

* `xs[low:high]` — bounded range
* `xs[low:]` — from index through end
* `xs[:high]` — from start through index

Given a slice, subslicing looks like this:

```ft theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}}
xs := [10, 20, 30]
mid := xs[1:3]
tail := xs[2:]
```

See **`examples/in/slices.ft`** (`task example:slices`). Subslices are a **language** feature on Forst slice values. They are distinct from **variadic spread** at Go call sites (next section).

## Variadic spread into Go calls

When a Go function takes a variadic parameter, spread a Forst slice subslice at the call site with **`expr[low:]...`**. The compiler lowers this to a Go variadic argument list.

<Tabs>
  <Tab title="Forst">
    ```ft theme={"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}}
    package main

    import "os/exec"

    func main() {
    	argv := []String{"true", "extra"}
    	cmd := exec.Command(argv[0], argv[1:]...)
    	cmd.Run()
    	cmd.ProcessState.ExitCode()
    }
    ```
  </Tab>

  <Tab title="Generated Go">
    ```go theme={"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}} theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}}
    // forst build
    package main

    import "os/exec"

    func main() {
    	argv := []string{"true", "extra"}
    	cmd := exec.Command(argv[0], argv[1:]...)
    	cmd.Run()
    	cmd.ProcessState.ExitCode()
    }
    ```
  </Tab>
</Tabs>

See **`examples/in/go_interop/cli.ft`** and **`helpers.go`** (`task example:go-interop`).

## Fields and methods on Go values

After a Go call or a local binding typed from Go, use **field access** and **methods** with dotted paths:

* `cmd.Run()` — method on a `*exec.Cmd` binding
* `cmd.ProcessState.ExitCode()` — field then method

Qualified import calls such as `exec.Command(...)` are checked when the stdlib package loads from your module workspace (`go.mod` walk-up sets `GoWorkspaceDir`).

## Forst packages in the same module

An `import "module/path"` can refer to **another Forst package** in the same Go module—not only hand-written Go. The compiler resolves these as **Forst siblings** from `.ft` sources and the module import map (`modulecheck`). Cross-package calls type-check against the sibling package’s Forst signatures.

This matters for [Providers](/docs/language/providers) cross-package wiring: `api` can call `auth.LogEvent` without a committed Go stub. `forst test` emits ephemeral lib shims under `.forst/gen/test/`; the LSP uses the same module-level pass so editor diagnostics match compile-time arity.

Try the cross-package provider examples:

```bash theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}}
task example:providers-cross_pkg
task test:providers-cross_pkg
```

Cookbook: `examples/in/rfc/providers/cross_pkg/` (`auth` + `api`).

Do not confuse sibling Forst imports with **Go package** imports: `import "fmt"` loads Go via `go/packages`; `import "yourmod/auth"` loads a Forst package when `auth/` contains `.ft` files declaring `package auth`.

## Mixed packages

Place `.ft` files alongside `.go` in the same module:

```text theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}}
my-service/
├── go.mod
├── handlers/
│   ├── orders.ft
│   └── legacy.go
└── internal/
    └── db.go
```

Use **`-root`** to merge all same-package sources under a tree, matching discovery for `forst run`, `forst build`, and the dev server:

```bash theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}}
npx forst run -root ./handlers handlers/orders.ft
```

The typechecker walks up from your `.ft` file to find **`go.mod`** (`GoWorkspaceDir`). Exported funcs from co-located **`.go`** files resolve **without** an import line (same package). Example: `examples/in/go_interop/helpers.go` called from `custom.ft` / `cli.ft`.

## Project layout profiles

Forst supports three common Go module layouts. Pick one and stay consistent within a project.

| Profile          | `go.mod` location | `.ft` location                   | Typical workflow                                                                                                                          |
| ---------------- | ----------------- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| **Go-native**    | project root      | mixed with `.go`                 | `forst build` + `go run .` / `go test ./...`                                                                                              |
| **Node-primary** | `.forst-gomod/`   | project root (`main/`, `forst/`) | `forst generate` + `forst run`; `replace` paths in `.forst-gomod/go.mod` are relative to the **project boundary**, not to `.forst-gomod/` |
| **Compiler dev** | either            | either                           | `FORST_GOMOD_ROOT=<path-to-forst-module>` when the `forst` binary is not adjacent to `module forst`                                       |

**`forst run`** writes a temp sandbox under `.forst/run/` with its own `go.mod` and links the `forst` runtime module. **Go-native** projects (root `go.mod`, not only `.forst-gomod/`) use **Mode B**: an auto-managed `.forst/go.work` workspace instead of a fragile `replace` in the sandbox. **Node-primary** projects keep **Mode A** (`replace forst => …` in the sandbox `go.mod`). For mixed `.ft` + hand-written `.go`, prefer **`forst build`** and the normal Go toolchain — `forst run` emits transpiled `.go` only.

Examples: **`examples/in/go_interop/`** (Go-native), **`examples/in/rfc/node-interop/remix-serve/`** (Node-primary with `.forst-gomod/go.mod`).

## Runtime validation

Type constraints in Forst emit **runtime checks** in generated Go. Untrusted input is validated at the boundary before your handler body executes. See [Shapes and constraints](/docs/language/shapes-and-constraints).

## Providers

Forst **Providers** (`use` / `with`) declare shared runtime services at function boundaries and wire implementations at entry points. See [Providers (DI)](/docs/language/providers).

Run the provider examples:

```bash theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}}
task example:providers
task example:providers-cross_pkg
```

## When to keep hand written Go

* **`unsafe`** or low-level syscalls not yet mapped
* Large existing packages you are migrating incrementally
* Performance-critical paths already audited in Go

Forst supports **gradual adoption**. You can migrate route by route without a big bang rewrite.

## Caveats

**Go import loading** is **experimental**. Unmapped Go types report diagnostics. This is not a full Go loader yet.

### `unsafe` not end to end

Put **`unsafe`** usage in hand written **`.go`** and call from Forst. Qualified **`unsafe.*`** calls and **`unsafe.Pointer`** mapping are not wired through the Forst import path yet.

### `make` and `new` type args

**`make`** and **`new`** with a type argument are rejected until Forst type syntax works in that position (e.g. **`Array(Int)`**, not Go **`[]T`**).

### Slice subslices experimental

Three index subslice syntax on Forst **`[]T`** values is experimental. It is distinct from variadic **spread** at Go call sites.

### JSON field export

Shape fields lower to unexported Go identifiers by default. For JSON marshaling, see [Shapes and constraints § Caveats](/docs/language/shapes-and-constraints#caveats).

## Related

<CardGroup cols={2}>
  <Card title="CLI reference" icon="terminal" href="/docs/workflow/cli">
    `run`, `build`, `-root`, and compile flags.
  </Card>

  <Card title="Editor workflow" icon="puzzle-piece" href="/docs/workflow/editor">
    LSP hover for Go imports, godoc, and cross-package Forst siblings.
  </Card>

  <Card title="Node overview" icon="server" href="/docs/interop/node">
    Share types, call Forst from Node, or call JavaScript from Forst.
  </Card>

  <Card title="Call JavaScript from Forst" icon="https://mintcdn.com/forst/r5GJChnfkgCSJa-b/icons/typescript.svg?fit=max&auto=format&n=r5GJChnfkgCSJa-b&q=85&s=8a8c0cd7b4bf60c264d51f66d0f52e91" href="/docs/interop/node/call-javascript" width="512" height="512" data-path="icons/typescript.svg">
    Call legacy `.ts`/`.js` from Forst at runtime.
  </Card>
</CardGroup>
