1---
2title: Static Site
3description: Run a static-site build command and package its output for a Neon Function.
4sidebar:
5 order: 13
6---
7
8`Neon.Website.StaticSite` runs a build command and packages only its output
9directory with a Node 24 Fetch file handler. The site runs on a Neon Function,
10not S3, a container, or a listening Bun server. It does not adapt SSR output;
11use a framework constructor for server-rendered applications.
12
13## Prepare the app
14
15Use a static project with `build` and `dev:site` scripts, or the
16[runnable StaticSite example](https://github.com/alchemy-run/alchemy/tree/main/examples/neon-website-static).
17In that example, these scripts are `vite build` and `vite --host 127.0.0.1`.
18Configure [deployment credentials](/neon/setup), then install in the app directory:
19
20Install [Alchemy and its matching Effect dependencies](/getting-started) first;
21use Node 24 for this build toolchain.
22
23```sh
24pnpm add -D @alchemy.run/frontend-frameworks @vercel/nft
25```
26
27## Define the stack
28
29```typescript
30// alchemy.run.ts
31import * as Alchemy from "alchemy";
32import * as Neon from "alchemy/Neon";
33import * as Effect from "effect/Effect";
34
35export default Alchemy.Stack(
36 "NeonStaticSite",
37 { providers: Neon.providers(), state: Alchemy.localState() },
38 Effect.gen(function* () {
39 const site = yield* Neon.Website.StaticSite("Web", {
40 command: "pnpm run build",
41 outdir: "dist",
42 dev: { command: "pnpm run dev:site" },
43 });
44 return { url: site.url };
45 }),
46);
47```
48
49Change `command` and `outdir` to your generator's build and output directory;
50for example, Hugo uses `hugo --minify` and `public`. `cwd` sets the build directory
51for a monorepo, and `outdir` is relative to it. Do not point `outdir` at the repository.
52
53## Enable client-side routing
54
55```diff lang="typescript"
56 const site = yield* Neon.Website.StaticSite("Web", {
57 command: "pnpm run build",
58 outdir: "dist",
59+ spa: true,
60 dev: { command: "pnpm run dev:site" },
61 });
62```
63
64`spa: true` serves `index.html` on unmatched GET/HEAD paths. Alternatively, set
65`errorPage: "404.html"` for a built error document with status 404. `spa` and
66`errorPage` are mutually exclusive; without either, misses return 404.
67
68## Develop and deploy
69
70```sh
71pnpm exec alchemy dev
72pnpm exec alchemy deploy
73pnpm exec alchemy destroy
74```
75
76Run separately, destroying when finished. With `dev.command`, development skips
77the production build and runs your native dev command. Without it, Alchemy builds
78and serves the output locally. `site.url` is local and no implicit Neon resources
79are created. Append `.pipe(Alchemy.remote())` to the Website Effect to deploy the
80real Function during dev instead.
81
82Without scope, live deploy creates an Ohio Project. Supply either `project` or
83`branch` for an existing backend; choose Ohio when adding storage. See
84[scope and credentials](/neon/frontend/vite#scope-and-credentials).
85
86Build tools may inline `env` into static output. The deployed file handler does
87not inject private runtime values into HTML or JavaScript, so never use static
88assets to distribute privileged branch tokens or your account key.
89
90:::caution[Deployment limits]
91Complete live Website acceptance remains unverified. Neon probes have served old
92code/env after successful metadata updates. Files are served from the Function
93without an added CDN; registering a domain does not validate TLS. See the
94[shared deployment limits](/neon/frontend/vite#environment-and-deployment-limits).
95:::
96
97## Reference
98
99- [StaticSite API](/providers/neon/website/staticsite)
100- [Runnable StaticSite example](https://github.com/alchemy-run/alchemy/tree/main/examples/neon-website-static)