forst generate, the compiler typechecks your Forst code and projects the resulting type definitions and function signatures into an in-memory snapshot. The compiler then executes your configured plugin binaries and passes this snapshot to them over standard input.
Plugins emit generated code—such as JSON Schema files, RPC contract definitions, or framework route handlers—into dedicated output folders. Your application imports these generated outputs, ensuring external contracts and routers stay synchronized with your backend code without manual duplication. Because generated files are written exclusively to designated output directories, running forst generate updates your generated code without overwriting hand-written source files.
Work in progress and known limitations
Semantic plugins and the official emitters are under active development. The table below lists current constraints—not a promise of future design.
If you rely on generated artifacts in CI or production, pin the compiler, regenerate in CI or commit outputs, and treat plugin warnings as signals to fix before shipping.
Quickstart
Add a plugin to thegenerate.plugins array in ftconfig.json:
forst generate from your terminal:
generated/jsonschema/schema.json alongside your generated TypeScript client. You can now import schema.json directly into your API gateway, validation pipeline, or external documentation tools.
Build official plugin binaries from the Forst repo with task build (compiler + plugins land in bin/). GitHub Releases and @forst/cli ship the same plugin binaries next to the compiler; bare cmd names resolve automatically.
Example project
The repo ships a runnable boundary atexamples/in/plugins/ that exercises every official plugin from real .ft sources (RPC catalog, file routes, and React Router handlers). See that directory’s README for commands.
Resolving plugin executables (cmd)
Each generate.plugins[].cmd value resolves as follows:
When you invoke
forst through @forst/cli, the CLI downloads official plugin binaries into the same version cache directory as the compiler only when forst generate runs against an ftconfig.json that lists bare official plugin names in generate.plugins, then prepends that directory to PATH before spawning.
Plugin out directories are owned exclusively by the plugin. On each run, forst generate removes stale files under out that the plugin did not emit. Diagnostics with severity: "error" fail the generate command; warnings are logged only.
Invalid opt JSON in ftconfig.json fails the plugin at runtime with a parse error.
What you can build with plugins
Plugins bridge Forst’s type system with any external system or toolchain. Because plugins receive fully resolved types, constraint chains, and function signatures, you can automate any downstream output that derives from backend service definitions:- Validation and data schemas. Convert type constraint chains into JSON Schema, Zod, Effect Schema, or custom validation rules for external clients, API gateways, and message queues.
- API contracts and specifications. Derive end-to-end typed contract trees, OpenAPI specs, AsyncAPI definitions, GraphQL schemas, or client SDKs for RPC frameworks, REST endpoints, and message brokers.
- Framework and HTTP routing. Generate route tables, parameter mappers, middleware hooks, and request dispatchers for web servers and full-stack frameworks.
- Full-stack data integration. Produce server-side data loaders, resource route handlers, or form actions so UI frameworks can fetch Forst data without modifying your frontend source code.
- Persistence and database definitions. Translate shape types and constraints into database schema migrations, SQL constraint assertions, ORM model mappings, or seed fixtures.
- Infrastructure and cloud topology. Generate IaC definitions (Terraform, Pulumi, AWS CDK, Kubernetes CRDs) or API gateway policies directly from backend service declarations and provider dependencies.
- CI/CD and pipeline validation. Produce GitHub Actions workflows, contract compatibility matrices, or breaking-change checkers between git revisions.
- Automated testing and mock suites. Build deterministic test fixtures, fake service implementations, property-based test generators, or contract-testing suites automatically from service shapes.
Official plugin packages
Official plugins are shipped alongside the compiler as standalone binaries. Each emitter is early-stage; output file names,opt fields, and generated APIs may change while plugin versioning matures.
forst-gen-jsonschema
Generates standard JSON Schema files from Forst shapes and constraint chains.
- Use case: Share strict type validation with external services, API gateways, or OpenAPI documentation.
- Key behavior: Maps built-in constraints (
Min,Max,HasPrefix,Contains) to schema properties. On maps,Min/MaxbecomeminProperties/maxProperties. Emits a warning for runtime type-guard functions likeEmail()rather than guessing a format string.
forst-gen-orpc
Generates Zod schemas and procedure contracts for oRPC or tRPC applications.
- Use case: Connect frontend web apps to Forst backend services using end-to-end typed RPC.
- Key behavior: Reads contract types marked with
.Router(). Generateszod.ts,contract.ts, andinvoke.ts. Supports stream returns as subscriptions and maps optional query or mutation hints.
forst-gen-file-routes
Generates a sealed HTTP route registry from file paths under a target directory.
- Use case: Build RESTful HTTP APIs where file layout determines URL structure.
- Key behavior: Converts paths like
app/api/orders/$id.ftinto route pattern/api/orders/:id. Generates handler wrappers, path parameter bindings, and a centraldispatch()function. Skips.Router()types declared outsideopt.routesRoot(for example RPC catalogs incatalog/). Skips HTTP members whose bound function is not runnable (same as the React Router plugin) and emits an error diagnostic.
forst-gen-react-router
Generates React Router and Remix resource routes and server loaders.
- Use case: Integrate Forst data fetching into React Router v7 or Remix full-stack applications.
- Key behavior: Generates
forstApiRoutesarrays, resource handler modules (loaderandaction), and helper functions for page modules. Never writes into yourapp/UI source folder.
forst-gen-echo
Development-only manifest of type and function ids in the semantic snapshot. Use it to verify generate.plugins[] wiring — not for production artifacts.
How to write a custom plugin
You can write a custom plugin in Go or any language that can read standard input and write standard output.Why write a custom plugin?
Write a custom plugin when you need to transform Forst type metadata into custom project files. Examples include:- Generating database migration scripts or SQL
CHECKconstraints from type assertions. - Emitting GraphQL schema definitions (
.graphql) from exported shape types. - Producing custom SDKs for internal SDK clients or language runtimes.
- Generating infrastructure config (Terraform, AWS CDK, Kubernetes manifests) based on service definitions.
Under the hood: The semantic snapshot model
Plugins do not receive raw source tokens or abstract syntax trees (AST). Instead,forst generate typechecks your Forst code and projects a structured JSON payload called the semantic snapshot (the same typecheck also feeds the TypeScript client).
The snapshot contains resolved, fully-qualified facts about your codebase:
- Packages: Module layout, directories, files, and exported type/function IDs.
- Types: Resolved primitives, shapes, field names, optionality, tags, and ordered constraint chains.
- Functions: Exported declarations, parameters, synthesized input shapes, return types, and nominal error sets.
Step 1: Implement the JSON protocol
Plugins read a single JSON request fromstdin and write a single JSON response to stdout.
Here is a minimal Go plugin using the official forst/internal/genplugin helper package:
Step 2: Register your plugin executable
Build your executable and reference it in yourftconfig.json:
forst generate, the compiler executes ./bin/my-custom-plugin, passes the snapshot, and writes generated/summary/SUMMARY.md.
Inspecting snapshots for debugging
You can inspect the exact JSON snapshot emitted by the compiler without executing any plugins by using the--dump-semantic flag:
GenerateRequest payload to standard output, making it easy to test and debug custom plugin transformations.