Skip to content

Foldkit

Prisma.Website.Foldkit deploys a Foldkit app to Prisma Compute. It supports browser-only SPAs, server-side rendering (SSR), static site generation (SSG), and hybrid rendering. Foldkit’s Vite plugin generates the handler and assets; Alchemy packages them for deployment.

Install the build-time integration; the resource loads /foldkit and /foldkit/neon from your frontend project:

Terminal window
pnpm add -D https://pkg.alchemy.run/@alchemy.run/frontend-frameworks/pr:2930:a10573e @vercel/nft

Keep Foldkit’s Vite setup and your existing plugins:

vite.config.ts
import { foldkit } from "@foldkit/vite-plugin";
import tailwindcss from "@tailwindcss/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [foldkit(), tailwindcss()],
optimizeDeps: { entries: ["src/entry.ts"] },
});

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:

vite.config.ts
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.

src/entry.server.ts
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:

src/entry.server.ts
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.

alchemy.run.ts
import * as Prisma from "@alchemy.run/prisma";
export const Website = Prisma.Website.Foldkit("Website", {
rootDir: "applications/web",
});

Omit rootDir for an app at .. Omit project to create a database-less Prisma project on live deploy, or pass an existing project.

alchemy.run.ts
import * as Alchemy from "alchemy";
import * as Effect from "effect/Effect";
export default Alchemy.Stack(
"MyFoldkitSite",
{ providers: Prisma.providers(), state: Alchemy.localState() },
Effect.gen(function* () {
const site = yield* Website;
return { url: site.url };
}),
);

site.url is the Compute endpoint on deploy and Vite’s local URL in dev.

export const Website = Prisma.Website.Foldkit("Website", {
rootDir: "applications/web",
env: {
VITE_API_URL: "https://api.example.com",
},
});

env is applied before build and dev, and passed to Compute. Server code reads private values from process.env. Vite inlines VITE_* keys into the browser build; keep secrets out of those keys and serialized Foldkit Flags.

src/vite-env.d.ts
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_API_URL: string;
}

This declares the client-visible key for TypeScript.

const apiUrl = import.meta.env.VITE_API_URL;

Vite replaces the lookup with the build-time value.

For browser-only builds, assets.notFoundHandling defaults to "single-page-application". A path like /counter/42 returns index.html with status 200, letting Foldkit’s client router resolve it. For real 404 responses instead:

export const Website = Prisma.Website.Foldkit("Website", {
assets: { notFoundHandling: "404-page" },
});

alchemy dev runs Vite with Foldkit live reload and devtools. The Website creates no Prisma resources. .pipe(Alchemy.remote()) selects the live path during dev. Pin the local address when running several apps:

export const Website = Prisma.Website.Foldkit("Website", {
dev: { host: "127.0.0.1", port: 5180, strictPort: true },
});
const site = yield* Prisma.Website.Foldkit("Web", {
domain: "app.example.com",
});

This creates Prisma.CustomDomain. Configure the returned DNS records yourself and verify status before cutover. See Custom domains.