1---
2title: Nuxt
3description: Deploy a Nuxt app to Fly with Fly.Website.Nuxt — nitro's node preset on a Machine, assets baked into the image, and Nuxt's own dev server under alchemy dev.
4sidebar:
5 order: 10
6---
7
8import { Code, Tabs, TabItem } from "@astrojs/starlight/components";
9
10export const devDeps = "@alchemy.run/frontend-frameworks";
11
12`Fly.Website.Nuxt` deploys a [Nuxt](https://nuxt.com) app to Fly. It
13builds the app through your project's own `@nuxt/kit` with nitro's
14`node` preset: the nitro Node server runs on a Machine, and client
15assets plus prerendered pages are baked into the image. Omit `app`
16and a `Fly.App` is created under the site; a `Fly.Service` listens
17on port 3000 and a shared IPv4 assignment makes
18`https://{app}.fly.dev` answer. There is no `nitro.preset` to edit
19and no build command to run.
20
21## Install
22
23The build integration is not bundled with alchemy. Install
24`@alchemy.run/frontend-frameworks`; the resource loads its `/nuxt`
25and `/nuxt/node` exports from your project at deploy time. It is
26only used at build time, so a dev dependency is enough:
27
28<Tabs syncKey="pkgManager">
29 <TabItem label="bun" icon="bun">
30 <Code code={`bun add -d ${devDeps}`} lang="sh" />
31 </TabItem>
32 <TabItem label="npm" icon="npm">
33 <Code code={`npm install -D ${devDeps}`} lang="sh" />
34 </TabItem>
35 <TabItem label="pnpm" icon="pnpm">
36 <Code code={`pnpm add -D ${devDeps}`} lang="sh" />
37 </TabItem>
38 <TabItem label="yarn" icon="seti:yarn">
39 <Code code={`yarn add -D ${devDeps}`} lang="sh" />
40 </TabItem>
41</Tabs>
42
43## Configure Nuxt
44
45Your `nuxt.config.ts` loads natively — modules, layers, and all —
46so configure Nuxt exactly as you would outside Alchemy:
47
48```typescript
49// nuxt.config.ts
50export default defineNuxtConfig({
51 modules: ["@nuxtjs/tailwindcss"],
52 routeRules: {
53 "/about": { prerender: true },
54 },
55});
56```
57
58Deploy-specific overrides are merged over it via the `nuxt` prop
59(the override wins) — see [Prerendering](#prerendering) below for an
60example.
61
62Don't set `nitro.preset` — the Node deploy target owns the preset
63(`"node"`), and a foreign preset is a hard error.
64
65## Declare the Website
66
67Declare the site as a module-level const (rather than inline in the
68Stack):
69
70```typescript
71// alchemy.run.ts
72import * as Fly from "alchemy/Fly";
73
74export const Website = Fly.Website.Nuxt("Website");
75```
76
77Pass `rootDir` if `package.json` is not at `.`. Pass `app` to put
78the Service on an App you already declared; otherwise the site
79creates `Fly.App("App")` under its namespace.
80
81## Add it to the Stack
82
83Yield the site from your Stack and return its URL:
84
85```typescript
86// alchemy.run.ts
87import * as Alchemy from "alchemy";
88import * as Effect from "effect/Effect";
89
90export default Alchemy.Stack(
91 "MyNuxtSite",
92 {
93 providers: Fly.providers(),
94 state: Alchemy.localState(),
95 },
96 Effect.gen(function* () {
97 const site = yield* Website;
98 return { url: site.url };
99 }),
100);
101```
102
103On deploy the site is one App, one Service on port 3000, and a
104`shared_v4` IpAssignment. `site.url` is `https://{app}.fly.dev`
105(or `https://{domain}` when you set `domain`). `site.app`,
106`site.service`, `site.ip`, and `site.certificate` are undefined
107under `alchemy dev`.
108
109## Add environment variables
110
111Process environment is the top-level `env` prop — plain strings, or
112`Redacted` values. They are copied onto `process.env` before build
113and `alchemy dev`, and onto the Machine at deploy:
114
115```diff lang="typescript"
116// alchemy.run.ts
117export const Website = Fly.Website.Nuxt("Website", {
118+ env: {
119+ GREETING: "Hello from Alchemy!",
120+ NUXT_PUBLIC_API_BASE: "https://api.example.com",
121+ },
122});
123```
124
125This is the hosted Node process, not Worker bindings.
126`NUXT_`-prefixed keys override Nuxt `runtimeConfig` the usual way;
127`NUXT_PUBLIC_` values are inlined into the client at build time.
128
129## Read the environment in server code
130
131The nitro server is a plain Node process, so server routes and SSR
132read the environment from `process.env`:
133
134```typescript
135// server/api/hello.ts
136export default defineEventHandler(() => {
137 return { greeting: process.env.GREETING ?? "hello" };
138});
139```
140
141## Prerendering
142
143Routes marked for prerendering in `routeRules` (or via
144`nitro.prerender`) render at build time into `.output/public` and
145are baked into the image, served as static files before the nitro
146handler:
147
148```typescript
149export const Website = Fly.Website.Nuxt("Website", {
150 nuxt: {
151 routeRules: {
152 "/about": { prerender: true },
153 },
154 },
155});
156```
157
158Nitro's `isr` route rule is implemented only by the Vercel and
159Netlify presets. On the Node preset it is silently ignored at build
160time, and the route renders on demand like any other SSR route. Use
161`prerender` for build-time static routes, or `cache` route rules for
162runtime caching.
163
164## Local dev
165
166```sh
167bun alchemy dev
168```
169
170`alchemy dev` runs Nuxt's own dev server (nitro dev, full HMR)
171instead of deploying; `site.url` is the local address and no Fly
172resources are created. Wrap the site in `Alchemy.remote()` to deploy
173the live App and Service even during dev.
174
175## Custom domain
176
177`domain` is a hostname string. The site requests an ACME
178[`Fly.Certificate`](/fly/networking#use-your-own-hostname) on the
179App and `url` becomes `https://{domain}`. Point DNS at the App
180yourself — v1 does not create DNS records:
181
182```typescript
183export const Website = Fly.Website.Nuxt("Website", {
184 domain: "app.example.com",
185});
186```
187
188## Where next
189
190- [`Fly.Website.Nuxt` reference](/providers/fly/website/nuxt) —
191 every prop and attribute.
192- [Services](/fly/compute/services) and [Apps](/fly/compute/apps) —
193 the Service and App the site creates.
194- [IPs & certificates](/fly/networking) — shared IPv4 and ACME.
195- [Setup](/fly/setup) — org, API token, and alchemy login.