Nuxt
Fly.Website.Nuxt deploys a Nuxt app to Fly. It
builds the app through your project’s own @nuxt/kit with nitro’s
node preset: the nitro Node server runs on a Machine, and client
assets plus prerendered pages are baked into the image. Omit app
and a Fly.App is created under the site; a Fly.Service listens
on port 3000 and a shared IPv4 assignment makes
https://{app}.fly.dev answer. There is no nitro.preset to edit
and no build command to run.
Install
Section titled “Install”The build integration is not bundled with alchemy. Install
@alchemy.run/frontend-frameworks; the resource loads its /nuxt
and /nuxt/node exports from your project at deploy time. It is
only used at build time, so a dev dependency is enough:
bun add -d @alchemy.run/frontend-frameworksnpm install -D @alchemy.run/frontend-frameworkspnpm add -D @alchemy.run/frontend-frameworksyarn add -D @alchemy.run/frontend-frameworksConfigure Nuxt
Section titled “Configure Nuxt”Your nuxt.config.ts loads natively — modules, layers, and all —
so configure Nuxt exactly as you would outside Alchemy:
export default defineNuxtConfig({ modules: ["@nuxtjs/tailwindcss"], routeRules: { "/about": { prerender: true }, },});Deploy-specific overrides are merged over it via the nuxt prop
(the override wins) — see Prerendering below for an
example.
Don’t set nitro.preset — the Node deploy target owns the preset
("node"), and a foreign preset is a hard error.
Declare the Website
Section titled “Declare the Website”Declare the site as a module-level const (rather than inline in the Stack):
import * as Fly from "alchemy/Fly";
export const Website = Fly.Website.Nuxt("Website");Pass rootDir if package.json is not at .. Pass app to put
the Service on an App you already declared; otherwise the site
creates Fly.App("App") under its namespace.
Add it to the Stack
Section titled “Add it to the Stack”Yield the site from your Stack and return its URL:
import * as Alchemy from "alchemy";import * as Effect from "effect/Effect";
export default Alchemy.Stack( "MyNuxtSite", { providers: Fly.providers(), state: Alchemy.localState(), }, Effect.gen(function* () { const site = yield* Website; return { url: site.url }; }),);On deploy the site is one App, one Service on port 3000, and a
shared_v4 IpAssignment. site.url is https://{app}.fly.dev
(or https://{domain} when you set domain). site.app,
site.service, site.ip, and site.certificate are undefined
under alchemy dev.
Add environment variables
Section titled “Add environment variables”Process environment is the top-level env prop — plain strings, or
Redacted values. They are copied onto process.env before build
and alchemy dev, and onto the Machine at deploy:
export const Website = Fly.Website.Nuxt("Website", { env: { GREETING: "Hello from Alchemy!", NUXT_PUBLIC_API_BASE: "https://api.example.com", },});This is the hosted Node process, not Worker bindings.
NUXT_-prefixed keys override Nuxt runtimeConfig the usual way;
NUXT_PUBLIC_ values are inlined into the client at build time.
Read the environment in server code
Section titled “Read the environment in server code”The nitro server is a plain Node process, so server routes and SSR
read the environment from process.env:
export default defineEventHandler(() => { return { greeting: process.env.GREETING ?? "hello" };});Prerendering
Section titled “Prerendering”Routes marked for prerendering in routeRules (or via
nitro.prerender) render at build time into .output/public and
are baked into the image, served as static files before the nitro
handler:
export const Website = Fly.Website.Nuxt("Website", { nuxt: { routeRules: { "/about": { prerender: true }, }, },});Nitro’s isr route rule is implemented only by the Vercel and
Netlify presets. On the Node preset it is silently ignored at build
time, and the route renders on demand like any other SSR route. Use
prerender for build-time static routes, or cache route rules for
runtime caching.
Local dev
Section titled “Local dev”bun alchemy devalchemy dev runs Nuxt’s own dev server (nitro dev, full HMR)
instead of deploying; site.url is the local address and no Fly
resources are created. Wrap the site in Alchemy.remote() to deploy
the live App and Service even during dev.
Custom domain
Section titled “Custom domain”domain is a hostname string. The site requests an ACME
Fly.Certificate on the
App and url becomes https://{domain}. Point DNS at the App
yourself — v1 does not create DNS records:
export const Website = Fly.Website.Nuxt("Website", { domain: "app.example.com",});Where next
Section titled “Where next”Fly.Website.Nuxtreference — every prop and attribute.- Services and Apps — the Service and App the site creates.
- IPs & certificates — shared IPv4 and ACME.
- Setup — org, API token, and alchemy login.