API reference

Node.js and Bun server APIs

API reference for running Effront applications on Node.js and Bun.

@effront/server provides native Effect HTTP hosting and static files for Node.js and Bun. For installation and startup files, see Node.js and Bun.

effrontServer

effrontServer(options?: EffrontServerOptions): Plugin from @effront/server/vite connects the native handler to Vite development and preview, and builds a separate production startup entry. It must follow effront():

import { effront } from "@effront/vite";
import { effrontServer } from "@effront/server/vite";
import { defineConfig } from "vite-plus";

export default defineConfig({
  plugins: [effront({ rsc: "./src/entry.rsc.ts" }), effrontServer()],
});
OptionDefaultEntry contract
rsc?: string./src/entry.rsc.tsNamed handler export containing a native HTTP Effect, such as toHttpEffect(application)
server?: string./src/entry.server.tsProduction startup that launches serve

Empty entry strings throw TypeError. When changing rsc, pass the same path to effront({ rsc }) and effrontServer({ rsc }) so the RSC entry receives Effect Schema JIT registration. The RSC entry accepts HMR with if (import.meta.hot) import.meta.hot.accept();.

Development and preview use Vite's listener through Node-compatible middleware, not the production startup entry. serve options therefore do not configure Vite's port or hostname. @effect/platform-node is required even when production uses Bun. Bun-specific runtime behavior requires the built production entry, normally bun dist/rsc/server.js, not Vite preview.

serve

serve(handler, options) returns a scoped server Layer. handler is an Effect yielding HttpServerResponse, not a Fetch function. Launch the Layer with Layer.launch and the matching platform Runtime:

Runtimeserve importRuntime
Node.js@effront/server/nodeNodeRuntime.runMain from @effect/platform-node
Bun@effront/server/bunBunRuntime.runMain from @effect/platform-bun
ServeOptions fieldContract
assetsRequired AssetOptions, described below
portOptional number, default 3000
hostnameOptional string, default 127.0.0.1

Provide remaining application service Layers before launch. See the Node.js startup example. The default address accepts local connections only. An address such as 0.0.0.0 exposes the listener to other machines. Bun's server also enforces a 10 MiB request-body limit.

withAssets

withAssets(handler, options) from @effront/server/assets constructs a handler with static-file serving. serve already applies it using its assets option.

AssetOptions fieldContract
client.rootRequired dedicated filesystem directory for browser output
client.prefixRequired absolute URL prefix other than /, such as /assets/
client.cacheControlOptional client Cache-Control value
public.rootRequired directory when the optional public mount is configured, served without an added URL prefix
public.cacheControlOptional public Cache-Control value

Both cache policies default to public, max-age=0, must-revalidate. Use public, max-age=31536000, immutable only for hashed filenames. With prefix /assets/, /assets/app.js looks up app.js in client.root. Mounts must match the actual output directories and URLs when Vite output or base changes.

RequestResult
GET or HEAD inside the client prefixFile response, or 404 for a missing file
GET or HEAD matching a public fileFile response
Public miss or other methodApplication handler
Flight, Server Function, or /_effront request outside the client prefixApplication handler, bypassing public lookup

There are no directory indexes or SPA fallbacks. Other filesystem failures remain typed HTTP errors. Roots are checked at request time, not validated at startup.

For an existing Effect HTTP server, obtain the handler with yield* withAssets(handler, options) during server construction. Do not pass the outer construction Effect as the request handler.

StageSuccessErrorsRequired services
ConstructionRequest handler EffectPlatformErrorFileSystem.FileSystem, Path.Path
RequestHttpServerResponseOriginal handler errors plus HttpServerErrorOriginal requirements plus HttpServerRequest

The host owns request scopes and must consume or cancel response bodies. MIME types, weak ETags, conditionals, and ranges follow Effect 4.0.0-rc.116:

ConditionBehavior
HEAD or conditional 304No file stream acquired
Satisfiable single byte range206
Multiple, unsupported, or malformed rangesRange ignored
Decimal range start beyond the file416, even when the value exceeds JavaScript's safe-integer limit
Decimal range end beyond the fileClamped to file length and returned as 206
Valid but unsatisfiable single range416 with Content-Range, without asset cache or validator headers
If-RangeIgnored
Range on HEADIgnored; returns full-file metadata without a body

Caller-provided HttpPlatform or ETag services do not change asset responses.