Skip to main content
When your Forst application uses a JS import, production builds bundle JavaScript modules and run them alongside the Go binary.
At runtime, the binary connects to a bridge process over a local socket to execute JavaScript calls.

Build for production

Use forst build to compile Go output for deployment. Use forst run to compile and execute in one step. Enable embedded invoke in ftconfig.json before building for production.
Run the binary listed in manifest.json.
Production builds bundle imported .ts files into .forst/js/ as standalone JavaScript files. You do not need tsx at runtime when using compiled mode.

Where bundled modules live

During forst build, esbuild bundles each imported module into .forst/js/ under your project root. For example, legacy/payment.ts becomes .forst/js/legacy/payment.js. The Go binary and manifest.json do not copy .forst/js/ beside the executable. Treat .forst/js/ as a separate deploy artifact. The bridge resolves compiled .js files in this order.
  1. FORST_BRIDGE_MODULES_DIR environment variable
  2. bridge.legacyModules.dir in ftconfig.json
  3. Default path {FORST_ROOT}/.forst/js
When bundled files live on a shared volume or sidecar container, set FORST_BRIDGE_MODULES_DIR.

Choose how JavaScript runs

Set bridge.host in ftconfig.json to node, bun, or deno.

Run in bootstrap mode

Bootstrap mode is the default. Forst starts a dedicated JavaScript child process that runs @forst/runtime/dist/bootstrap.js. Use bootstrap mode unless your JavaScript calls need to share memory with an existing web framework process.
The process communicates over a local socket at .forst/node-bootstrap.sock.

Run in host mode

Use host mode when JavaScript calls must share memory with a running application. Examples include Prisma clients, global singletons, or routes inside Remix or Vite. Host mode runs RPC calls directly inside your application process.

Preload register script

When hostMode is true, Go injects a preload script into your application process.

Signal readiness in custom entries

If your application needs time to initialize before accepting calls, import signalForstAppReady.

Environment variables for socket RPC

Forst sets these variables automatically when spawning or attaching to the bridge.

Keep host running during development

During forst dev, Forst keeps the bridge host process running while rebuilding Go code. This avoids restarting Vite or Remix every time you edit a .ft file. The forst dev parent process starts the host. Each reloaded Go child attaches to FORST_BRIDGE_SOCKET using FORST_BRIDGE_ATTACH_ONLY=1.

Restrict allowed calls with manifests

Forst records every module and export your program can call during compilation. This allowlist is stored in the generated Go binary using the forst-node-manifest-v1 format. At runtime, @forst/runtime checks every RPC request against the embedded manifest. Unregistered modules or exports are rejected immediately. Only these RPC methods are allowed.
  • forst.node/initialize
  • forst.node/call
  • forst.node/callAsync
  • forst.node/genOpen
  • forst.node/genNext
  • forst.node/genNextBatch
  • forst.node/genClose
  • forst.node/shutdown
Requests containing relative path traversal like .. or paths outside the project root are rejected.

How Forst maps TypeScript types

Forst reads TypeScript exports during compilation to verify signatures and generate Go wrapper code. When a union contains unmappable types, Forst widens the type to Object and emits a compiler warning.

Troubleshoot common errors

To see debug logs for spawn and RPC events, set FORST_LOG_LEVEL=debug.

Migrate from implicit import policy

Older projects may have "importPolicy": "implicit" in ftconfig.json. Under implicit policy, any relative import can load .ts files without the js marker. To migrate to explicit policy:
  1. Set "importPolicy": "explicit" in ftconfig.json.
  2. Add js to every TypeScript import.
  3. Rebuild and verify which binaries require JavaScript.

Caveats

  • forst/bridgert dependency: Generated Go code imports forst/bridgert. Your go.mod must resolve the forst module.
  • Whole program requirement: If any package in your import tree uses a JS import, the deployed binary requires a JavaScript runtime.
  • Blocked calls: Unknown exports and message types are rejected by the bridge manifest.
  • Type limits: Unmapped TypeScript unions widen to Object.

Bridge security

Dual allowlists, path jailing, and local socket isolation.

Import and call JavaScript

Import syntax, async promises, and generators.