Navigated to /docs/core/node-runtime

Node runtime and production security

Configure the generated Node server, handler, origin and host checks, document boundary, static cache, and remote image optimizer.

Configure the stable server boundary

Place under ssr in the one root tavo.config.ts. Tavo.js supplies route modules and top-level plugins to generated builds; applications configure the remaining handler behavior. Document fields follow , and image fields follow .

  • RenderDocumentOptions has title and unsafeHeadHtml. It has no raw document.head string alias.

  • Prefer route head exports and escaped TSX metadata. unsafeHeadHtml is unescaped and must never contain user-controlled content.

  • canonicalOrigin must contain only an HTTP(S) origin: no credentials, path, query, or hash.

  • maxRequestBodyBytes defaults to 10 MiB for the Node handler.

  • Cookie or Authorization requests bypass static response caching.

TS
tsimport { defineConfig } from "@tavojs/core/config";

const reviewedBootstrapHtml =
  '<meta name="application-name" content="Acme">';

export default defineConfig({
  ssr: {
    canonicalOrigin: "https://app.example.com",
    trustedHosts: ["app.example.com"],
    maxRequestBodyBytes: 10 * 1024 * 1024,
    stream: true,
    document: {
      lang: "en",
      title: "Acme",
      unsafeHeadHtml: reviewedBootstrapHtml
    },
    images: {
      allowRemote: true,
      remotePatterns: [{
        protocol: "https:",
        hostname: "images.example.com",
        pathname: "/media/**"
      }]
    }
  }
});

Know the production HTTP behavior

applies this contract to the generated Node server. Low-level document and page render functions remain available when a platform needs a custom server integration.

API / contractType / boundaryDefault / resultBehavior
GET / HEADpage requestrender routeResolves the route, plugins, images, static response cache, and optional streaming document.
unsafe method + actionmutationaction responseValidates host/origin and optional content type before running the route action.
unsafe method + plugin endpointmutationplugin responseRuns matching server middleware and the most-specific endpoint with request-scoped disposal.
non-page method without handlerHTTP failure405Returns Allow: GET, HEAD and baseline security headers.
body over limitHTTP failure413Rejects before an action or endpoint receives the body.
uncaught handler failureHTTP failuregeneric 500Contains the exception and avoids returning private error details.
client disconnectcancellationAbortSignalAborts request-owned work and cancels an active streaming reader.
  • HTML, actions, plugin responses, images, and generated static assets receive baseline nosniff, referrer, permissions, and framing headers where applicable.

  • Tavo.js does not invent a universal Content Security Policy. Add a deployment-specific policy and pass one request nonce through intentional inline content.

  • The handler exposes invalidateCache(tags) and clearCache() for rendered and resolved cache invalidation.

TS
tsimport { createServer } from "node:http";
import { createNodeRequestHandler } from "@tavojs/core/server";
import * as modules from "virtual:tavo-pages";

const handleRequest = createNodeRequestHandler({
  modules,
  trustedHosts: ["example.com"],
  stream: true,
});

createServer(handleRequest).listen(3000);

Apply the exact origin and Host policy

Origin validation applies to unsafe methods when validateOrigin is not false. A present Origin must equal the normalized request URL origin. Missing Origin is accepted by the Fetch handler; the Node handler still requires a local or configured trusted inbound host.

API / contractType / boundaryDefault / resultBehavior
Fetch + matching Originunsafe action / endpointacceptedOrigin exactly matches new URL(request.url).origin.
Fetch + mismatched Originunsafe action / endpoint403Rejected before application mutation code runs.
Fetch + missing Originunsafe action / endpointacceptedSupport for non-browser clients; authentication and authorization remain required.
Node + untrusted Hostunsafe action / endpoint403Rejected even when Origin is missing or agrees with the forged Host.
Node + local Hostlocalhost / loopbacktrustedLocalhost, 127.0.0.1, and loopback IPv6 are implicit.
Node + trustedHostsexact host or hostnameacceptedA configured hostname also matches that hostname with an inbound port.
Node + canonicalOriginreverse proxypublic URL originConstructs request URLs from the public origin and adds its host and hostname to the trusted set.
validateOrigin: falseexplicit opt-outno origin checkReserve for independently authenticated integrations such as signature-verified webhooks.

Allowlist remote images narrowly

Configure remote loading through . The optional resolveHostname hook is a platform adapter with the exact signature shown below.

API / contractType / boundaryDefault / resultBehavior
allowRemotebooleanfalseRemote sources remain disabled until explicitly enabled.
remotePatternsstring | { protocol, hostname, port, pathname }[][]Allows only matching remote origins and paths. Prefer HTTPS and the narrowest pathname.
resolveHostname(hostname: string) => Promise<Array<{ address: string }>>Node DNSAdvanced test/platform hook; every returned address must pass public-network validation.
allowInsecureRemotebooleanfalseRelaxes HTTP/private-network protections. Use only inside a controlled network boundary.
timeoutMs / maxBytesnumber5000 / 10 MiBBounds remote fetch time and source bytes.
maxConcurrentTransformsnumber4Limits active image transformations.
maxPendingTransformsnumber64Excess queued transformations receive 503.
  • The optimizer rejects private hostnames and private DNS results, and checks redirected locations again.

  • Local absolute paths must remain inside publicDir.

  • Set the Image component's unoptimized prop when the source should bypass the optimizer.

  • Install the optional sharp peer only on servers that perform transformations.

Operate the generated Node server

API / contractType / boundaryDefault / resultBehavior
NODE_ENVenvironmentproductionSelects mode-specific server env loading before the built entry is imported.
HOSTbind address127.0.0.1Use 0.0.0.0 only when the container or platform must accept external connections.
PORTnumber4174HTTP listen port.
TAVO_MONITOR_TOKENsecretmonitor disabledEnables /_tavo/monitor with an exact Authorization: Bearer header. Unauthorized requests return 404.
assets/*fingerprinted static assets1 year immutableGenerated hashed assets receive long-lived caching.
other client filesstatic filesno-cacheHTML and non-fingerprinted files are revalidated.
  • Deploy .tavo/build/client for fully client/static applications or run .tavo/build/server/start.mjs for request-time behavior.

  • Plain tavo preview delegates to Vite preview. tavo preview --ssr checks for missing or stale output and runs tavo build first when required.

  • Protect the external TLS, proxy header, CSP, secret injection, health-check, and process supervision boundaries on the hosting platform.

BASH
bashnpx tavo build
HOST=0.0.0.0 PORT=4174 node .tavo/build/server/start.mjs

Verify the deployed boundary

  • Exercise one SSR GET, one client navigation, one action, one plugin endpoint, one error response, and one remote image policy decision.

  • Verify the public Origin observed behind the real reverse proxy.

  • Confirm an untrusted Host and mismatched Origin receive 403 before mutation code runs.

  • Confirm the monitor endpoint is hidden without the Bearer token.

BASH
bashnpx tavo check
npx tavo build --report-json
npx tavo preview --ssr
npx tavo monitor --url http://127.0.0.1:4174 --token "$TAVO_MONITOR_TOKEN" --once

Look up exact public types

Follow linked API names to their canonical TypeScript declarations and package boundaries.