1---
2title: Foldkit
3description: Deploy Foldkit to Prisma Compute with Prisma.Website.Foldkit — a Vite SPA served on Bun, deep-link fallback, and native HMR locally.
4sidebar:
5 order: 8
6---
7
8import { Code, Tabs, TabItem } from "@astrojs/starlight/components";
9
10export const devDeps = "@alchemy.run/frontend-frameworks @vercel/nft";
11
12[Foldkit](https://foldkit.dev) is an Elm-architecture frontend framework
13built on Effect. Its apps are client-only Vite projects, so
14`Prisma.Website.Foldkit` is [Vite](/prisma/frontend/vite) with SPA
15fallback to `index.html`. Deep links boot the app and its router takes over.
16
17The client build and generated server are uploaded as `tar.gz` and
18served on **Bun in Prisma Compute**. There is no Foldkit SSR handler,
19but the deployment still runs a Compute static-file server; no Docker
20image or registry is needed.
21
22## Install
23
24Install the build-time integration; the resource loads `/vite` and
25`/vite/node` from your frontend project:
26
27<Tabs syncKey="pkgManager">
28 <TabItem label="bun" icon="bun"><Code code={`bun add -d ${devDeps}`} lang="sh" /></TabItem>
29 <TabItem label="npm" icon="npm"><Code code={`npm install -D ${devDeps}`} lang="sh" /></TabItem>
30 <TabItem label="pnpm" icon="pnpm"><Code code={`pnpm add -D ${devDeps}`} lang="sh" /></TabItem>
31 <TabItem label="yarn" icon="seti:yarn"><Code code={`yarn add -D ${devDeps}`} lang="sh" /></TabItem>
32</Tabs>
33
34## Configure Vite
35
36Keep Foldkit's Vite setup and your existing plugins:
37
38```typescript
39// vite.config.ts
40import { foldkit } from "@foldkit/vite-plugin";
41import tailwindcss from "@tailwindcss/vite";
42import { defineConfig } from "vite";
43
44export default defineConfig({
45 plugins: [foldkit(), tailwindcss()],
46 optimizeDeps: { entries: ["src/entry.ts"] },
47});
48```
49
50:::note[Pinned Effect versions]
51Foldkit pins its Effect peer to an exact version. Alchemy uses your
52frontend project's own Vite and dependencies; keep Foldkit's peer
53versions aligned in that project rather than replacing them with the
54Stack's Effect version.
55:::
56
57## Declare the Website
58
59```typescript
60// alchemy.run.ts
61import * as Prisma from "alchemy/Prisma";
62
63export const Website = Prisma.Website.Foldkit("Website", {
64 rootDir: "applications/web",
65});
66```
67
68Omit `rootDir` for an app at `.`. Omit `project` to create a
69database-less Prisma project on live deploy, or pass an existing project.
70
71## Add it to the Stack
72
73```typescript
74// alchemy.run.ts
75import * as Alchemy from "alchemy";
76import * as Effect from "effect/Effect";
77
78export default Alchemy.Stack(
79 "MyFoldkitSite",
80 { providers: Prisma.providers(), state: Alchemy.localState() },
81 Effect.gen(function* () {
82 const site = yield* Website;
83 return { url: site.url };
84 }),
85);
86```
87
88`site.url` is the Compute endpoint on deploy and Vite's local URL in dev.
89
90## Add environment variables
91
92```diff lang="typescript"
93export const Website = Prisma.Website.Foldkit("Website", {
94 rootDir: "applications/web",
95+ env: {
96+ VITE_API_URL: "https://api.example.com",
97+ },
98});
99```
100
101`env` is applied before build and dev, and passed to Compute. The SPA
102only sees values Vite inlines at build time. `VITE_*` keys are public,
103so never put secrets in them.
104
105## Read the environment
106
107```typescript
108// src/vite-env.d.ts
109/// <reference types="vite/client" />
110
111interface ImportMetaEnv {
112 readonly VITE_API_URL: string;
113}
114```
115
116This declares the client-visible key for TypeScript.
117
118```typescript
119const apiUrl = import.meta.env.VITE_API_URL;
120```
121
122Vite replaces the lookup with the build-time value.
123
124## Deep links
125
126`assets.notFoundHandling` defaults to `"single-page-application"`.
127A path like `/counter/42` returns `index.html` with status 200, letting
128Foldkit's client router resolve it. For real 404 responses instead:
129
130```typescript
131export const Website = Prisma.Website.Foldkit("Website", {
132 assets: { notFoundHandling: "404-page" },
133});
134```
135
136## Local dev
137
138`bun alchemy dev` runs Vite with Foldkit HMR and devtools. The Website
139creates no Prisma resources. `.pipe(Alchemy.remote())` selects the live
140path during dev. Pin the local address when running several apps:
141
142```typescript
143export const Website = Prisma.Website.Foldkit("Website", {
144 dev: { host: "127.0.0.1", port: 5180, strictPort: true },
145});
146```
147
148## Custom domain
149
150```typescript
151const site = yield* Prisma.Website.Foldkit("Web", {
152 domain: "app.example.com",
153});
154```
155
156This creates `Prisma.CustomDomain`; the app must be on the project's
157current default branch. Configure the returned DNS records yourself
158and verify status before cutover. See
159[Custom domains](/prisma/frontend/websites#custom-domains).
160
161## Where next
162
163- [Foldkit API](/providers/prisma/website/foldkit).
164- [Foldkit example](https://github.com/alchemy-run/alchemy/tree/main/examples/prisma-website-foldkit).
165- [Vite](/prisma/frontend/vite), [Websites](/prisma/frontend/websites), and [Compute apps](/prisma/compute/apps).