{"id":47865175,"url":"https://github.com/forst-lang/forst","last_synced_at":"2026-04-21T20:03:07.438Z","repository":{"id":286620608,"uuid":"927929926","full_name":"forst-lang/forst","owner":"forst-lang","description":"[alpha] A programming language for backend development.","archived":false,"fork":false,"pushed_at":"2026-04-12T14:20:58.000Z","size":2944,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-12T16:29:09.457Z","etag":null,"topics":["backend","compiler","golang","programming-language","static-typing","structural-typing","trpc","type-inference"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/forst-lang.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-02-05T19:21:04.000Z","updated_at":"2026-04-12T14:21:04.000Z","dependencies_parsed_at":"2025-05-27T23:23:18.516Z","dependency_job_id":"ae2efe26-f64d-4736-80b3-1e59c92db7fc","html_url":"https://github.com/forst-lang/forst","commit_stats":null,"previous_names":["haveyaseen/forst","forst-lang/forst"],"tags_count":64,"template":false,"template_full_name":null,"purl":"pkg:github/forst-lang/forst","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forst-lang%2Fforst","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forst-lang%2Fforst/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forst-lang%2Fforst/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forst-lang%2Fforst/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/forst-lang","download_url":"https://codeload.github.com/forst-lang/forst/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forst-lang%2Fforst/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31989342,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T20:23:30.271Z","status":"ssl_error","status_checked_at":"2026-04-18T20:23:29.375Z","response_time":103,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backend","compiler","golang","programming-language","static-typing","structural-typing","trpc","type-inference"],"created_at":"2026-04-04T00:06:10.127Z","updated_at":"2026-04-21T20:03:07.431Z","avatar_url":"https://github.com/forst-lang.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Forst \u0026emsp; [![CI]][actions] [![Release]][release] [![Go Report Card]][goreport] [![Coverage Status]][coveralls] [![License]][license]\n\n[CI]: https://img.shields.io/github/actions/workflow/status/forst-lang/forst/lint-test-coverage.yml\n[actions]: https://github.com/forst-lang/forst/actions\n[release]: https://img.shields.io/github/v/release/forst-lang/forst?filter=v*\n[Go Report Card]: https://goreportcard.com/badge/github.com/forst-lang/forst\n[goreport]: https://goreportcard.com/report/github.com/forst-lang/forst\n[Coverage Status]: https://coveralls.io/repos/github/forst-lang/forst/badge.svg?branch=main\n[coveralls]: https://coveralls.io/github/forst-lang/forst?branch=main\n[License]: https://img.shields.io/github/license/forst-lang/forst\n\n**Forst is a programming language that brings TypeScript's type safety and developer experience to Go.**\n\nIts primary goal is to help you move away from TypeScript on the backend:\n\n- Generate instantly usable TypeScript types from backend endpoints – enabling full-stack development without build steps.\n- Strong static typing with aggressive inference and smart narrowing – so you move fast while staying safe.\n- Data schemas acting as guards, automatically validating deeply nested input data through type definitions – to keep untrusted user input out of your application logic.\n\nSee also [ROADMAP.md](./ROADMAP.md) for planned work and **feature parity**.\n\n## Why?\n\nWe love TypeScript's efficiency in structuring data.\n\nWe love Go's efficiency at compile and runtime.\n\nWe want the best of both worlds.\n\nWe want to be to Go what TypeScript is to JavaScript.\n\n## Examples\n\nPlace an order: validate input, attach domain failures, assert invariants with `ensure`, and narrow `Result` values at call sites. The snippets follow one **catalog order** story (`StockKeepingUnit` + `Quantity`, stock check, order id). For more samples, see [`examples/in/`](examples/in/).\n\n### Hello World\n\n*Before (Go)* and *After (Forst)* — Forst is a superset of Go for ordinary programs: the same `package main` source can be built with the standard Go toolchain or compiled with Forst, so a minimal executable looks identical on both sides. Use a **`.ft`** file for the Forst CLI (`forst run`, `forst generate`, …); `go build` expects the usual **`.go`** name if you compile the same text with Go.\n\n```golang\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(\"Hello World!\")\n}\n```\n\n### Input shape\n\n*Before (Go)* — You declare a request struct with plain `string` and `int` fields, then enforce stock-keeping unit length and quantity range with hand-written `if` checks and generic errors such as `errors.New`. The types themselves do not carry those constraints; validation lives entirely in imperative code.\n\n```golang\ntype PlaceOrderInput struct {\n\tStockKeepingUnit string\n\tQuantity         int\n}\n\nfunc placeOrder(in PlaceOrderInput) (string, error) {\n\tif len(in.StockKeepingUnit) \u003c 1 || len(in.StockKeepingUnit) \u003e 64 {\n\t\treturn \"\", errors.New(\"invalid stock keeping unit\")\n\t}\n\tif in.Quantity \u003c 1 || in.Quantity \u003e 99 {\n\t\treturn \"\", errors.New(\"invalid quantity\")\n\t}\n\t// function body continues...\n}\n```\n\n*After (Forst)* — With Forst, you put constraints directly on the fields themselves. No need for manual validation as invalid inputs are rejected automatically.\n\n```golang\ntype PlaceOrderInput = {\n\tstockKeepingUnit: String.Min(1).Max(64),\n\tquantity: Int.Min(1).Max(99),\n}\n\nfunc placeOrder(in: PlaceOrderInput) {\n\t// in is already validated; invariants enforced by typechecker\n}\n```\n\n### Nominal errors\n\n*Before (Go)* — Each failure kind is a distinct struct type implementing `error`, with `Error()` returning a human-readable string. Callers who need structure use `errors.As`, type switches, or sentinel comparisons; there is no single dedicated syntax for “named” domain errors beyond conventions.\n\n```golang\ntype UnknownStockKeepingUnit struct{}\n\nfunc (e UnknownStockKeepingUnit) Error() string { return \"unknown stock keeping unit\" }\n\ntype InsufficientStock struct {\n\tStockKeepingUnit string\n\tRequested        int\n\tAvailable        int\n}\n\nfunc (e InsufficientStock) Error() string {\n\treturn fmt.Sprintf(\"insufficient stock for %s: need %d, have %d\",\n\t\te.StockKeepingUnit, e.Requested, e.Available)\n}\n```\n\n*After (Forst)* — `error Name { … }` introduces a nominal failure with an explicit payload shape. The language treats it as a first-class error variant, so you get a dedicated declaration instead of bolting domain meaning onto generic structs and `Error()` strings alone.\n\n```golang\nerror UnknownStockKeepingUnit {}\n\nerror InsufficientStock {\n\tstockKeepingUnit: String,\n\trequested:        Int,\n\tavailable:        Int,\n}\n```\n\n### Catalog lookup and stock\n\n*Before (Go)* — Map lookup returns a value plus a boolean: you use `value, ok := catalog[key]` to tell “missing key” from “present but zero”, then branch with `if` statements and construct `error` returns yourself.\n\n```golang\navail, ok := catalog[in.StockKeepingUnit]\nif !ok {\n\treturn \"\", UnknownStockKeepingUnit{}\n}\nif in.Quantity \u003e avail {\n\treturn \"\", InsufficientStock{\n\t\tStockKeepingUnit: in.StockKeepingUnit,\n\t\tRequested:        in.Quantity,\n\t\tAvailable:        avail,\n\t}\n}\n```\n\n*After (Forst)* — A **map read** `catalog[key]` has type **`Result(V, Error)`**: a missing key becomes the failure side of that `Result` (generated code uses comma-ok under the hood). You **must** handle failure before using the success value—the usual pattern is **`ensure x is Ok()`**, which narrows `x` to `V`. **Comma-ok assignment (`v, ok := m[k]`) is not supported** as Forst syntax. See [`examples/in/map_catalog.ft`](examples/in/map_catalog.ft) for `ensure avail is Ok()` after a lookup.\n\n```golang\navail := catalog[in.stockKeepingUnit]\nensure avail is Ok()\nensure in.quantity is Max(avail) or InsufficientStock({\n\tstockKeepingUnit: in.stockKeepingUnit,\n\trequested:        in.quantity,\n\tavailable:        avail,\n})\n```\n\n`ensure … or …` is not allowed in `func main` (parser rule); put guards that use `or` in a non-`main` function if needed.\n\n### Caller — success path and narrowing\n\n*Before (Go)* — The API returns `(string, error)`. The caller must test `err != nil` before using the order id, then decide how to log, wrap, or branch on concrete error types—standard Go error discipline, with no automatic narrowing of the success value.\n\n```golang\nid, err := PlaceOrder(PlaceOrderInput{\n\tStockKeepingUnit: \"ITEM-1\",\n\tQuantity:         2,\n})\nif err != nil {\n\t// switch on type, wrap, log, etc.\n\treturn\n}\n_ = id\n```\n\n*After (Forst)* — `placeOrder` yields a `Result`-style value. `ensure x is Ok()` refines `x` to the success payload (here the order id), so the following code can treat it as that value without a separate `if err != nil` block. The call site passes a single anonymous record `{ stockKeepingUnit, quantity }`, usually wrapped by `Mutation.Input`, instead of naming a separate struct type for this invocation.\n\n```golang\nx := placeOrder({\n\tstockKeepingUnit: \"ITEM-1\",\n\tquantity:         2,\n})\nensure x is Ok() or x\n// use success value from x (order id / narrowed payload per compiler)\n```\n\nIf `placeOrder` accepts a bare record, use `placeOrder({ stockKeepingUnit: \"ITEM-1\", quantity: 2 })` instead.\n\n### Types across the wire\n\n*Before (TypeScript)* — *You have to define TypeScript interfaces manually to describe the structured data being passed around. These interfaces use broad types like `string` or `number`, which means the input is only type-checked in a very basic way—e.g., every string is accepted, not just valid SKUs or positive quantities. To provide runtime validation (for example, checking `quantity \u003e 0` or `stockKeepingUnit` matches a pattern), you’d need extra schema validators like Zod or Effect.Schema.*\n\n```typescript\ninterface PlaceOrderInput {\n  stockKeepingUnit: string; // any string: not validated further by TypeScript\n  quantity: number;         // any number: not automatically checked for positivity, etc.\n}\n```\n\n*After (TypeScript)* — *With Forst, you define your types in one place. Running `forst generate` outputs unified **generated/types.d.ts** (see [`forst/cmd/forst/generate.go`](./forst/cmd/forst/generate.go)). You just import these. There is no need for extra types and they are available on the consuming code with zero config.*\n\n```typescript\nimport type { PlaceOrderInput } from \"./generated/types\";\n\nasync function submitOrder(input: PlaceOrderInput) {\n  // input is structurally checked, but fields are still unconstrained primitives unless validated\n  // For runtime checks, use e.g. Zod: placeOrderInputSchema.parse(input)\n  // JSON.stringify(input) — same shapes the server checked in .ft\n}\n```\n\nAdjust the import path to your output layout. See [TypeScript client output](#typescript-client-output) for `forst generate` and the `generated/` tree.\n\n## Features\n\n- Static typing\n- Strong type inference\n- Backwards compatibility with Go\n- Seamless TypeScript type generation inspired by tRPC – publishing types of API endpoints should be easy\n- Structural typing for function parameters and return values\n- Type-based assertions that allow complex type narrowing in function parameters\n- First-class nominal errors and explicit `ensure` / `Result` control flow—no exceptions; depth and parity are tracked in [ROADMAP.md](./ROADMAP.md)\n\n## Design Philosophy\n\nSee also [PHILOSOPHY.md](./PHILOSOPHY.md) for what guides and motivates us.\n\n## Development\n\nInstall Task using the [official instructions](https://taskfile.dev/installation/).\n\nRun tests:\n\n```bash\ntask test                  # Go tests: forst/internal/... and forst/cmd/forst/...\ntask ci:test               # Full CI suite (Go tests + VS Code extension build + @forst/cli \u0026 @forst/sidecar + examples)\ntask test:unit             # Run compiler unit tests (internal only)\ntask test:unit:parser      # Run parser tests\ntask test:unit:typechecker # Run typechecker tests\n```\n\nRun examples:\n\n```bash\ntask test:integration                    # Run compilation examples / integration tests\ntask example -- ../examples/in/basic.ft  # Run specific example\ntask example:function                    # Run function example\n```\n\n## VS Code\n\nThe workspace includes an optional extension in [`packages/vscode-forst`](./packages/vscode-forst): it registers `.ft` and talks to the compiler’s HTTP LSP (`forst lsp`) for diagnostics. Its **release cadence is separate** from compiler `v*` tags (see `vscode-forst-v*` in [`.github/workflows/publish-vscode-extension.yml`](./.github/workflows/publish-vscode-extension.yml)). After `bun install` at the repo root, run `task build:vscode` to compile it (or rely on the F5 **preLaunchTask** in [`.vscode/launch.json`](./.vscode/launch.json)). CI runs the same compile as the first step of `task ci:test`. See [`packages/vscode-forst/README.md`](./packages/vscode-forst/README.md) for F5 and troubleshooting.\n\n## npm\n\n**[`@forst/cli`](./packages/cli/README.md)** installs the Forst compiler in JS/TS projects: `npm i -D @forst/cli`, then `npx forst` / `node_modules/.bin/forst` (it pulls the matching native binary from GitHub Releases). For the dev-server + HTTP client, use **[`@forst/sidecar`](./packages/sidecar/README.md)** instead.\n\n## TypeScript client output\n\nYou can generate **TypeScript types and a small client** from your Forst code so front ends or Node callers get the same shapes your server uses, without copying types by hand.\n\nRun `forst generate` with a `.ft` file or a folder of `.ft` files; it writes a `generated/` tree (declarations plus helpers) and a `client/` stub you can wire to your app. The dev server can also expose types over HTTP while you iterate.\n\n## Inspirations\n\nOur primary inspiration is TypeScript's structural type system and its enormous success in making JavaScript development more ergonomic, robust and gradually typeable. We aim to bring similar benefits to Go development, insofar as they are not already present.\n\nWe also draw inspiration from:\n\n- **Zod** — constraints and shape guards as composable runtime checks on nested data.\n- **tRPC** — one source of truth for API shapes, with **TypeScript types and a small client** generated from Forst (`forst generate`, `examples/client-integration/`).\n- **Go** and **Rust** — **errors as values** and explicit control flow (`ensure` … `or …`), not exceptions.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fforst-lang%2Fforst","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fforst-lang%2Fforst","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fforst-lang%2Fforst/lists"}