1---
2title: Vite
3description: Package a Vite client build as a Neon Function, with native Vite development.
4sidebar:
5 order: 1
6---
7
8`Neon.Website.Vite` builds a Vite app and packages its static assets with a
9Node 24 Fetch handler in a Neon Function ZIP. It does not provision a container,
10start a listening Bun server, or upload the site to S3. For SSR, use the
11[framework-specific constructors](/neon/frontend/astro) instead.
12
13## Prepare the app
14
15Start with an existing Vite app or the
16[runnable Vite example](https://github.com/alchemy-run/alchemy/tree/main/examples/neon-website-vite).
17Keep your plugins in `vite.config.*`. From the app directory:
18
19Install [Alchemy and its matching Effect dependencies](/getting-started) first;
20use Node 24 for this build toolchain.
21
22```sh
23pnpm add -D @alchemy.run/frontend-frameworks @vercel/nft
24```
25
26The integration drives the build; `@vercel/nft` traces runtime dependencies for
27packaging. Configure your deployment account key using [Neon setup](/neon/setup).
28In CI, set `CI=true` and `NEON_API_KEY` in the deployment environment, not the
29website's `env`.
30
31## Define the stack
32
33```typescript
34// alchemy.run.ts
35import * as Alchemy from "alchemy";
36import * as Neon from "alchemy/Neon";
37import * as Effect from "effect/Effect";
38
39export default Alchemy.Stack(
40 "NeonVite",
41 { providers: Neon.providers(), state: Alchemy.localState() },
42 Effect.gen(function* () {
43 const site = yield* Neon.Website.Vite("Web", {
44 rootDir: ".",
45 });
46 return { url: site.url };
47 }),
48);
49```
50
51An omitted scope creates an owned Ohio (`aws-us-east-2`) Project on live deploy,
52then a Function on its default branch. `site.function` exposes the Function;
53`site.url` is its URL. Keep the local state files for subsequent deploys and cleanup.
54
55## Choose routing
56
57Vite defaults to SPA routing: unmatched GET/HEAD paths fall back to `index.html`.
58For a multi-page build that emits `404.html`, change only the asset fallback:
59
60```diff lang="typescript"
61 const site = yield* Neon.Website.Vite("Web", {
62 rootDir: ".",
63+ assets: { notFoundHandling: "404-page" },
64 });
65```
66
67The `vite` prop accepts serializable `outDir` and `base` overrides. Keep plugin
68instances in `vite.config.*`, not in resource props.
69
70## Develop locally
71
72```sh
73pnpm exec alchemy dev
74```
75
76This runs Vite's native dev server and HMR. The site returns a local URL with
77`function` and `domain` undefined; it creates no implicit Neon Project. Any
78explicit backend resources you declare separately still have their own lifecycle.
79
80## Opt out of local development
81
82Apply `Alchemy.remote()` to the site to deploy it even during `alchemy dev`:
83
84```diff lang="typescript"
85 const site = yield* Neon.Website.Vite("Web", {
86 rootDir: ".",
87- });
88+ }).pipe(Alchemy.remote());
89```
90
91This requires cloud credentials and incurs the normal live resource lifecycle.
92
93## Deploy and remove
94
95```sh
96pnpm exec alchemy deploy
97pnpm exec alchemy destroy
98```
99
100Run `destroy` when finished, from the same directory and with the same stage and
101state. It removes the site's owned resources, including an implicit Project.
102
103## Scope and credentials
104
105All 13 Neon Website constructors accept either `project` or `branch`, never both.
106A project selects its current default branch; a branch pins an explicit identity.
107For an existing branch, add just the scope to the site props:
108
109```diff lang="typescript"
110 const site = yield* Neon.Website.Vite("Web", {
111 rootDir: ".",
112+ branch: { projectId: "your-project-id", branchId: "your-branch-id" },
113 });
114```
115
116Replace both IDs with your own. Referenced projects and branches are not owned by
117the Website. When declaring a Project for a combined website/storage backend,
118choose `region: "aws-us-east-2"` (Ohio) and verify service availability for your
119account.
120
121The deployment account key is not an application credential.
122[`Neon.Credential`](/providers/neon/credential) grants branch-and-descendant
123permissions, not per-bucket permissions. Request only needed scopes; storage
124reads currently require explicit `storage:read`, even with `storage:write`.
125Never put account keys or privileged service tokens in a browser bundle.
126
127## Environment and deployment limits
128
129The website's `env` is supplied to build, native dev, and Function configuration.
130Vite embeds `VITE_*` values into browser assets; there is no Vite server application
131to read private runtime values. `Redacted` does not prevent a build tool from
132embedding secrets. SSR constructors use the same shared environment contract,
133with their own framework's public-variable rules.
134
135:::caution[Verification boundaries]
136Native development and local Fetch tests do not establish live acceptance for
137all frameworks. Live probes have observed new active deployment IDs while the
138Function URL still served old code and environment. Verify actual HTTP behavior
139after a deploy; metadata success or `memo: false` is not a verified workaround.
140:::
141
142Static files are served inside the Function, currently with
143`Cache-Control: no-cache`; this composition adds no CDN or durable framework cache.
144The `domain` prop registers a custom hostname and exposes `site.domain.cnameTarget` for a
145DNS-only CNAME. Registration and the returned URL do not establish DNS propagation
146or valid TLS; verify HTTPS separately. Follow [Custom domains](/neon/guides/custom-domains)
147for DNS, CAA, HTTPS checks, and safe retirement, or see the
148[`CustomDomain` reference](/providers/neon/customdomain).
149
150## Reference
151
152- [Vite API](/providers/neon/website/vite)
153- [Function API](/providers/neon/function)
154- [Runnable Vite example](https://github.com/alchemy-run/alchemy/tree/main/examples/neon-website-vite)