Skip to main content
While backend engineering covers a wide surface, some central issues affect everyone:
  • Developer experience: everyday work needs fast feedback and low boilerplate.
  • Performance: prod needs to keep up when traffic spikes and complexity grows.
  • Contracts: boundaries need to validate bad data before it reaches domain logic.
Forst is for teams who want all three: one .ft source that ships as native Go while allowing incremental migration within your existing TS or Go codebase.

TypeScript

Keeps client-side boilerplate low and makes working with complex data easy.

Go

Compiles fast, ships static binaries, and scales in production.

The analogy

Similar to TypeScript, Forst allows working within your existing codebase and replacing more and more code over time: TypeScript added types on top of JavaScript while keeping the same runtime. Forst does the same on both sides of your stack:
  • Go: Ship native binaries with go build and typed boundaries layered on top. See Go interop.
  • Node: Stay type-aligned with the frontend and migrate route by route without a big bang rewrite. See Node interop.

Feature comparison

Compare Forst to TypeScript and Go.

Compatibility

How each stack talks to other languages and adopts code incrementally.

Language

How each language models data, errors, and concurrency.

Infrastructure

How you ship, debug, and adopt each stack day to day.
Go import loading, Node interop, Providers, and several invoke paths are experimental. See the roadmap for current status.

What you get

Structural typing on the server

Typed records with field access, signatures, and is narrowing. You define one schema layer for the server.

Validation on the type

Constraints on fields. The compiler checks known values at compile time and emits runtime checks at the boundary.

Generate client types

forst generate emits .d.ts from the same .ft definitions the server uses.

Production Go output

Readable Go output. Ship with go build, existing modules, tests, and CI.

Explicit failures

ensure, nominal error types, and Result. Failures are values you handle in control flow.

Gradual adoption

Mix .ft with .go. Migrate route by route with forst dev or @forst/sidecar.

Design priorities

Structural typing

Shape matters more than inheritance.

Boundary validation

Types and runtime checks run before your logic.

Predictable behavior

Require explicit annotations where inference would lie.

Fast tooling

Inference applies only in clear cases.

Go as runtime

Import Go packages. Deploy with go build.

APIs for consumption

Export types when full stack teams need shared shapes.

What Forst omits

Surprising errors

No try / catch / throw. Failures are values you handle or explicitly ignore. ensure signals intent.

Class hierarchies

Inheritance trees obscure which fields an API actually has.

Macros and metaprogramming

Control flow changes use ordinary keywords you can read top to bottom.

Runtime reflection

Wiring and validation happen at compile time instead of through introspection.

Dependent types

Types cannot depend on runtime values.

Implicit coercions

Conversions stay visible because backend data integrity matters.
Panics may appear in generated Go or third-party libraries. Forst itself favors Result and Go’s error returns.

Read more

Language overview

How the language feels day to day.

Roadmap

What exists, what’s experimental, what’s planned.

Quickstart

Install and run your first handler.

Full philosophy (GitHub)

Long-form design doc in the repository.