Foldkit
Archil.Website.Foldkit deploys a Foldkit app to an Archil
sandbox, as a browser-only SPA, with server-side rendering, or prerendered. The site is the
program of its own sandbox, on port 3000, at a public
https://3000-…archil.app URL. A stopped sandbox starts again on the next
request.
Install
Section titled “Install”The build integration is not bundled with alchemy. Install
@alchemy.run/frontend-frameworks; the resource loads its /foldkit
and /foldkit/node exports from your project at deploy time. It is only
used at build time, so a dev dependency is enough:
pnpm add -D https://pkg.alchemy.run/@alchemy.run/frontend-frameworks/pr:2930:0cabab6bun add -d https://pkg.alchemy.run/@alchemy.run/frontend-frameworks/pr:2930:0cabab6npm install -D https://pkg.alchemy.run/@alchemy.run/frontend-frameworks/pr:2930:0cabab6yarn add -D https://pkg.alchemy.run/@alchemy.run/frontend-frameworks/pr:2930:0cabab6Configure Vite
Section titled “Configure Vite”Your Vite config stays what Foldkit’s setup gives you. Vite plugins
like Tailwind go in plugins as usual:
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 runs Vite programmatically on the project root. The Foldkit plugin and the rest of your setup are preserved as-is.
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.
Declare the Website
Section titled “Declare the Website”Declare the site as a module-level const:
import * as Archil from "@alchemy.run/archil";
export const Website = Archil.Website.Foldkit("Website");sandbox sizes the site’s sandbox and sets its image, timeouts, disks and network policy:
export const Website = Archil.Website.Foldkit("Website", { sandbox: { vcpuCount: 2, memSizeMiB: 4096, idleTtlSeconds: 600 },});Add it to the Stack
Section titled “Add it to the Stack”Yield the site from your Stack and return its URL:
import * as Archil from "@alchemy.run/archil";import * as Alchemy from "alchemy";import * as Effect from "effect/Effect";
export const Website = Archil.Website.Foldkit("Website");
export default Alchemy.Stack( "MyFoldkitSite", { providers: Archil.providers(), state: Alchemy.localState(), }, Effect.gen(function* () { const site = yield* Website; return { url: site.url }; }),);Run alchemy deploy. url is the site’s https://3000-…archil.app URL.
site.sandbox is the sandbox behind it, and undefined under
alchemy dev.
See examples/archil-website-foldkit for the checked-in example.
Add environment variables
Section titled “Add environment variables”Set process environment variables through the top-level env map. Server
code reads private values from process.env; Vite inlines VITE_* values
into the browser build. Values must be strings or Redacted strings.
export const Website = Archil.Website.Foldkit("Website", { env: { API_BASE: "https://api.example.com", VITE_API_URL: "https://api.example.com", },});The values are copied onto process.env before Vite dev and build, and
onto the program. Server code reads process.env.API_BASE. Client code reads
import.meta.env.VITE_API_URL. Keep secrets out of VITE_* keys and serialized
Foldkit Flags.
Read the environment in client code
Section titled “Read the environment in client code”Type a custom public key with Vite’s standard environment declaration:
/// <reference types="vite/client" />
interface ImportMetaEnv { readonly VITE_API_URL: string;}const apiUrl = import.meta.env.VITE_API_URL;Deep links
Section titled “Deep links”A browser-only Foldkit app that uses URL routing (Runtime.makeApplication with
routing, onUrlRequest, and onUrlChange) resolves routes on the
client, so a deep link like /counter/42 arrives as a request for a
file that doesn’t exist.
For browser-only builds, Foldkit defaults assets.notFoundHandling to
"single-page-application", which returns index.html (200) for
unmatched paths so the Foldkit runtime can resolve the route. Use
"404-page" to serve a real 404 instead:
export const Website = Archil.Website.Foldkit("Website", { assets: { notFoundHandling: "404-page" },});Local dev
Section titled “Local dev”alchemy dev runs Vite’s own dev server (Foldkit’s live reload
and devtools) instead of deploying; site.url is the local address and
no sandbox is created. Wrap the site in Alchemy.remote()
to deploy the live sandbox even during dev.
Pin the dev server’s address when several apps run in one Stack:
export const Website = Archil.Website.Foldkit("Website", { dev: { host: "127.0.0.1", port: 5180, strictPort: true },});Where next
Section titled “Where next”Archil.Website.Foldkitreference- Websites — every framework Archil hosts
- Programs and Sandboxes — what the site runs on