Foldkit
Neon.Website.Foldkit supports browser-only SPAs, server-side rendering (SSR),
static site generation (SSG), and hybrid rendering. It packages Foldkit’s assets and
optional generated handler as a Node 24 Fetch module in a Neon Function ZIP.
Prepare the app
Section titled “Prepare the app”Use an existing Foldkit app or the runnable Foldkit example. Configure deployment credentials and install Alchemy and its matching Effect dependencies. Use Node 24 for this build toolchain, then install the build integration in the app directory:
pnpm add -D https://pkg.alchemy.run/@alchemy.run/frontend-frameworks/pr:2930:a10573e @vercel/nftKeep the foldkit() plugin from @foldkit/vite-plugin in vite.config.* and
retain your application’s normal entry configuration. No application adapter or
server wrapper is required.
Server rendering and prerendering
Section titled “Server rendering and prerendering”Configure rendering in the application’s foldkit(...) plugin. This example
uses Foldkit 0.167.0, @foldkit/vite-plugin 0.27.0 and compatible Effect
dependencies:
import { foldkit } from "@foldkit/vite-plugin";import { defineConfig } from "vite";
export default defineConfig({ plugins: [ foldkit({ ssr: { serverEntry: "/src/entry.server.ts", clientEntry: "/src/entry.ts", build: true, }, }), ],});The server entry exports renderPage and renderDocument. Import stylesheets
from the client entry and use Runtime.hydrate to start the browser application.
Remove the source index.html for this build: Foldkit generates the complete
HTML document, including the client script, stylesheets and module preload links.
import { Server } from "foldkit/experimental";
export const renderDocument = Server.renderDocument;Keep your application’s renderPage export alongside the document renderer.
Foldkit currently exposes its server rendering API through foldkit/experimental;
see its server rendering guide for
the application and hydration contract.
For static site generation (SSG), change build to { prerender: true } and
export the URLs to generate from the server entry:
export const prerenderPaths = ["/", "/about"];SSG renders those URLs during the build. SSR renders a page when its request
arrives. A hybrid application prerenders some URLs and renders others on request.
The same renderPage and renderDocument exports serve both delivery policies.
The same Website declaration deploys the client assets and generated handler.
GET and HEAD requests serve matching assets and prerendered pages first;
remaining requests go to the handler. Other methods bypass static assets.
The application owns its response status and headers through renderPage.
For an SSG-only application, return 404 for URLs outside its generated route set;
allowing those URLs to render on request makes the deployment hybrid.
Browser-only builds use SPA fallback. Server builds send unmatched requests to
the handler. Explicit assets.notFoundHandling settings override these defaults.
Vite’s resolved base also mounts the client assets. With base: "/app/",
/app/assets/main.js serves assets/main.js from the client output. SPA fallback
is limited to that prefix; server handlers receive the original URL.
Define the stack
Section titled “Define the stack”import * as Alchemy from "alchemy";import * as Neon from "@alchemy.run/neon";import * as Effect from "effect/Effect";
export default Alchemy.Stack( "NeonFoldkit", { providers: Neon.providers(), state: Alchemy.localState() }, Effect.gen(function* () { const site = yield* Neon.Website.Foldkit("Web", { rootDir: ".", }); return { url: site.url }; }),);Browser-only builds serve index.html for unmatched GET/HEAD paths so the
client router can resolve deep links.
For a multi-page build with a 404.html, set assets.notFoundHandling to
"404-page". vite.outDir overrides the build output directory.
env values with Vite’s VITE_* prefix are embedded into the browser build.
Server-rendered apps read private runtime values from process.env. Keep secrets
out of VITE_* keys and serialized Foldkit Flags because both reach the browser.
Develop and deploy
Section titled “Develop and deploy”pnpm exec alchemy devpnpm exec alchemy deploypnpm exec alchemy destroyRun separately, destroying when finished. Dev uses Vite’s native server with Foldkit live reload,
returns a local URL, and creates no implicit Neon resources. Append
.pipe(Alchemy.remote()) to the Website Effect to use live deployment during dev.
Live deploy creates an Ohio Project if no scope is supplied. Pass either
project or branch for an existing backend; choose Ohio for combined storage
use. Read scope and credentials:
account keys and privileged branch tokens must not reach this browser bundle.