Static Site
Neon.Website.StaticSite runs a build command and packages only its output
directory with a Node 24 Fetch file handler. The site runs on a Neon Function,
not S3, a container, or a listening Bun server. It does not adapt SSR output;
use a framework constructor for server-rendered applications.
Prepare the app
Section titled “Prepare the app”Use a static project with build and dev:site scripts, or the
runnable StaticSite example.
In that example, these scripts are vite build and vite --host 127.0.0.1.
Configure deployment credentials, then install in the app directory:
Install Alchemy and its matching Effect dependencies first; use Node 24 for this build toolchain.
pnpm add -D @alchemy.run/frontend-frameworks @vercel/nftDefine the stack
Section titled “Define the stack”import * as Alchemy from "alchemy";import * as Neon from "alchemy/Neon";import * as Effect from "effect/Effect";
export default Alchemy.Stack( "NeonStaticSite", { providers: Neon.providers(), state: Alchemy.localState() }, Effect.gen(function* () { const site = yield* Neon.Website.StaticSite("Web", { command: "pnpm run build", outdir: "dist", dev: { command: "pnpm run dev:site" }, }); return { url: site.url }; }),);Change command and outdir to your generator’s build and output directory;
for example, Hugo uses hugo --minify and public. cwd sets the build directory
for a monorepo, and outdir is relative to it. Do not point outdir at the repository.
Enable client-side routing
Section titled “Enable client-side routing”const site = yield* Neon.Website.StaticSite("Web", { command: "pnpm run build", outdir: "dist", spa: true, dev: { command: "pnpm run dev:site" },});spa: true serves index.html on unmatched GET/HEAD paths. Alternatively, set
errorPage: "404.html" for a built error document with status 404. spa and
errorPage are mutually exclusive; without either, misses return 404.
Develop and deploy
Section titled “Develop and deploy”pnpm exec alchemy devpnpm exec alchemy deploypnpm exec alchemy destroyRun separately, destroying when finished. With dev.command, development skips
the production build and runs your native dev command. Without it, Alchemy builds
and serves the output locally. site.url is local and no implicit Neon resources
are created. Append .pipe(Alchemy.remote()) to the Website Effect to deploy the
real Function during dev instead.
Without scope, live deploy creates an Ohio Project. Supply either project or
branch for an existing backend; choose Ohio when adding storage. See
scope and credentials.
Build tools may inline env into static output. The deployed file handler does
not inject private runtime values into HTML or JavaScript, so never use static
assets to distribute privileged branch tokens or your account key.