Skip to content

Foldkit

Foldkit is an Elm-architecture frontend framework built on Effect. Its apps are client-only Vite projects, so Prisma.Website.Foldkit is Vite with SPA fallback to index.html. Deep links boot the app and its router takes over.

The client build and generated server are uploaded as tar.gz and served on Bun in Prisma Compute. There is no Foldkit SSR handler, but the deployment still runs a Compute static-file server; no Docker image or registry is needed.

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

Terminal window
bun add -d @alchemy.run/frontend-frameworks @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"] },
});
alchemy.run.ts
import * as Prisma from "alchemy/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. The SPA only sees values Vite inlines at build time. VITE_* keys are public, so never put secrets in them.

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.

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" },
});

bun alchemy dev runs Vite with Foldkit HMR 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; the app must be on the project’s current default branch. Configure the returned DNS records yourself and verify status before cutover. See Custom domains.