Hetzner.Website reference
Source:
src/Hetzner/Website/Astro.ts
Deploy an Astro application to a Hetzner Cloud
Server: the Node adapter bundle as a systemd unit on port 3000, static
assets baked into the unit. Pages render on demand by default
(output: "server"); astro: { output: "static" } prerenders every
page and deploys assets-only.
The build runs through @alchemy.run/frontend-frameworks/astro with the
@alchemy.run/frontend-frameworks/astro/node deploy target. Your
astro.config.* must not declare an adapter.
Astro: Creating Astro Sites
Section titled “Astro: Creating Astro Sites”Basic Astro App
const site = yield* Hetzner.Website.Astro("Web", { rootDir: "./app",});Custom Domain
const site = yield* Hetzner.Website.Astro("Web", { rootDir: "./app", domain: "app.example.com", zone,});Astro: Static Sites
Section titled “Astro: Static Sites”const site = yield* Hetzner.Website.Astro("Docs", { rootDir: "./docs", astro: { output: "static" }, assets: { notFoundHandling: "404-page" },});Foldkit
Section titled “Foldkit”Source:
src/Hetzner/Website/Foldkit.ts
Deploy a Foldkit app to a Hetzner Cloud Server.
Foldkit apps are client-only Vite projects, so this composite is the
Vite site with SPA fallback to index.html (deep links boot the app
and the Foldkit router takes over).
Foldkit: Creating Foldkit Sites
Section titled “Foldkit: Creating Foldkit Sites”Foldkit App
const site = yield* Hetzner.Website.Foldkit("Website");Project in a Subdirectory
const site = yield* Hetzner.Website.Foldkit("Website", { rootDir: "applications/web",});Foldkit: Single-Page Application Routing
Section titled “Foldkit: Single-Page Application Routing”const site = yield* Hetzner.Website.Foldkit("Website", { assets: { notFoundHandling: "404-page" },});Nextjs
Section titled “Nextjs”Source:
src/Hetzner/Website/Nextjs.ts
Deploy a Next.js application to a Hetzner Cloud Server: next build
then a long-running next({ dev: false }) systemd unit on port 3000.
Does not use OpenNext (those wrappers are Lambda/workerd).
The .next output (and public/ when present) is packed into the
unit archive. next, react, and react-dom are installed on the
unit with npm install rather than bundled.
During alchemy dev the site is next dev and no cloud resources
are declared; Alchemy.remote() opts back into the live Service.
Nextjs: Creating Next.js Sites
Section titled “Nextjs: Creating Next.js Sites”Basic Next.js App
const site = yield* Hetzner.Website.Nextjs("Web", { rootDir: "./app",});Custom Domain
const site = yield* Hetzner.Website.Nextjs("Web", { rootDir: "./app", domain: "app.example.com", zone,});Source:
src/Hetzner/Website/Nuxt.ts
Deploy a Nuxt application to a Hetzner Cloud Server: the nitro Node server as a systemd unit on port 3000, static assets baked into the unit.
The build runs through @alchemy.run/frontend-frameworks/nuxt with the
@alchemy.run/frontend-frameworks/nuxt/node deploy target (nitro.preset
"node").
Nuxt: Creating Nuxt Sites
Section titled “Nuxt: Creating Nuxt Sites”Basic Nuxt App
const site = yield* Hetzner.Website.Nuxt("Web", { rootDir: "./app",});Custom Domain
const site = yield* Hetzner.Website.Nuxt("Web", { rootDir: "./app", domain: "app.example.com", zone,});Octane
Section titled “Octane”Source:
src/Hetzner/Website/Octane.ts
Deploy an OctaneJS application to a Hetzner Cloud Server: Octane’s SSR server as a systemd unit on port 3000, static assets baked into the unit.
Hetzner.Website.Octane selects hosting and automatically wraps Octane’s
default native Node output. Keep compiler and route settings in
octane.config.ts without an adapter. The legacy Node marker adapter
remains optional for existing projects.
Octane: Creating Octane Sites
Section titled “Octane: Creating Octane Sites”Basic Octane App
const site = yield* Hetzner.Website.Octane("Web", { rootDir: "./app",});Custom Domain
const site = yield* Hetzner.Website.Octane("Web", { rootDir: "./app", domain: "app.example.com", zone,});ReactRouter
Section titled “ReactRouter”Source:
src/Hetzner/Website/ReactRouter.ts
Deploy a React Router v7 app (framework mode) to a Hetzner Cloud Server: the SSR server as a systemd unit on port 3000, static assets baked into the unit.
The build runs through
@alchemy.run/frontend-frameworks/react-router with the
@alchemy.run/frontend-frameworks/react-router/node deploy target — both
must be installed in your project, alongside @react-router/dev,
react-router, and vite.
Your vite.config.ts needs no adapter wiring. React Router’s server
build is a ServerBuild manifest rather than a request handler, so the
integration makes the server pass’s build input a module that wraps the
manifest with createRequestHandler and packages the resulting fetch
handler as a Node HTTP server.
React Server Components (React Router’s unstable RSC plugin) and
multi-environment builds are not supported yet — the build fails with an
actionable error when more than one server entry is emitted.
ReactRouter: Creating React Router Sites
Section titled “ReactRouter: Creating React Router Sites”Basic React Router App
const site = yield* Hetzner.Website.ReactRouter("Web", { rootDir: "./app",});Custom Domain
const site = yield* Hetzner.Website.ReactRouter("Web", { rootDir: "./app", domain: "app.example.com", zone,});ReactRouter: Server Configuration
Section titled “ReactRouter: Server Configuration”Process Environment
const site = yield* Hetzner.Website.ReactRouter("Web", { rootDir: "./app", env: { API_BASE: "https://api.example.com", },});Read An Environment Variable From A Loader
export function loader() { return { apiBase: process.env.API_BASE ?? "unset" };}SolidStart
Section titled “SolidStart”Source:
src/Hetzner/Website/SolidStart.ts
Deploy a SolidStart application to a Hetzner Cloud Server: the SSR server as a systemd unit on port 3000, static assets (prerendered pages included) baked into the unit.
The build runs through @alchemy.run/frontend-frameworks/solidstart with
the @alchemy.run/frontend-frameworks/solidstart/node deploy target —
both must be installed in your project, alongside @solidjs/start and
@solidjs/vite-plugin-nitro-2.
Your vite.config.ts needs no adapter wiring: the integration drives the
project’s own vite build and appends its own nitro plugin instance
carrying nitro’s node preset.
SolidStart: Creating SolidStart Sites
Section titled “SolidStart: Creating SolidStart Sites”Basic SolidStart App
const site = yield* Hetzner.Website.SolidStart("Web", { rootDir: "./app",});Custom Domain
const site = yield* Hetzner.Website.SolidStart("Web", { rootDir: "./app", domain: "app.example.com", zone,});SolidStart: Server Configuration
Section titled “SolidStart: Server Configuration”const site = yield* Hetzner.Website.SolidStart("Web", { rootDir: "./app", env: { API_BASE: "https://api.example.com", },});SolidStart: Prerendering
Section titled “SolidStart: Prerendering”The integration owns the nitro plugin instance (a nitroV2Plugin() in
your vite.config.* is rejected), so nitro options — prerendering
included — go on the nitro prop. Prerendered pages are baked into the
unit and served as static assets.
const site = yield* Hetzner.Website.SolidStart("Web", { rootDir: "./app", nitro: { prerender: { routes: ["/", "/about"] } },});StaticSite
Section titled “StaticSite”Source:
src/Hetzner/Website/StaticSite.ts
A Hetzner Service that serves static assets built by a shell command.
StaticSite runs a build command (e.g. npm run build), packs the
output directory into the unit archive, and deploys a tiny static-file
server (GET assets, /health, optional SPA / 404-page). Use this
when your site has its own build step — Hugo, Zola, Eleventy, or any
custom pipeline.
For Vite-based projects, prefer Hetzner.Website.Vite.
Dev and Build carry constant logical ids, so they are namespaced
under id. The Service stays in the caller’s namespace (same as
Cloudflare.Website.StaticSite).
StaticSite: Basic Usage
Section titled “StaticSite: Basic Usage”Deploying a Hugo site
const site = yield* Hetzner.Website.StaticSite("Blog", { command: "hugo --minify", outdir: "public",});SPA-style routing
const site = yield* Hetzner.Website.StaticSite("App", { command: "npm run build", outdir: "dist", spa: true,});StaticSite: Building from a Subdirectory
Section titled “StaticSite: Building from a Subdirectory”const site = yield* Hetzner.Website.StaticSite("Web", { cwd: "apps/web", command: "npm run build", outdir: "dist",});StaticSite: Local Development
Section titled “StaticSite: Local Development”const site = yield* Hetzner.Website.StaticSite("App", { command: "npm run build", outdir: "dist", dev: { command: "npm run dev" },});SvelteKit
Section titled “SvelteKit”Source:
src/Hetzner/Website/SvelteKit.ts
Deploy a SvelteKit application to a Hetzner Cloud Server: kit’s SSR server as a systemd unit on port 3000, static assets (prerendered pages included) baked into the unit.
The build runs through @alchemy.run/frontend-frameworks/sveltekit with
the @alchemy.run/frontend-frameworks/sveltekit/node deploy target.
SvelteKit: Creating SvelteKit Sites
Section titled “SvelteKit: Creating SvelteKit Sites”Basic SvelteKit App
const site = yield* Hetzner.Website.SvelteKit("Web", { rootDir: "./app",});Custom Domain
const site = yield* Hetzner.Website.SvelteKit("Web", { rootDir: "./app", domain: "app.example.com", zone,});TanStackStart
Section titled “TanStackStart”Source:
src/Hetzner/Website/TanStackStart.ts
Deploy a TanStack Start application to a Hetzner Cloud Server: the SSR server as a systemd unit on port 3000, static assets baked into the unit.
The build runs through
@alchemy.run/frontend-frameworks/tanstack-start with the
@alchemy.run/frontend-frameworks/tanstack-start/node deploy target —
both must be installed in your project, alongside @tanstack/react-start
(or @tanstack/solid-start) and vite.
Your vite.config.ts needs no adapter wiring: TanStack Start is pure
Vite, so the integration drives the project’s own vite build, forces
the SSR bundle to be self-contained, and wraps its fetch handler as a
Node HTTP server.
TanStackStart: Creating TanStack Start Sites
Section titled “TanStackStart: Creating TanStack Start Sites”Basic TanStack Start App
const site = yield* Hetzner.Website.TanStackStart("Web", { rootDir: "./app",});Custom Domain
const site = yield* Hetzner.Website.TanStackStart("Web", { rootDir: "./app", domain: "app.example.com", zone,});TanStackStart: Server Configuration
Section titled “TanStackStart: Server Configuration”Process Environment
const site = yield* Hetzner.Website.TanStackStart("Web", { rootDir: "./app", env: { API_BASE: "https://api.example.com", },});Read An Environment Variable From A Server Function
const getApiBase = createServerFn({ method: "GET" }).handler(() => ({ apiBase: process.env.API_BASE,}));Vinext
Section titled “Vinext”Source:
src/Hetzner/Website/Vinext.ts
Deploy a vinext application to a Hetzner Cloud
Server: vinext’s Vite build then a long-running startProdServer systemd
unit on port 3000. Does not use the Cloudflare Worker entry
(vinext/server/fetch-handler).
The dist/ output is packed into the unit archive. vinext,
react, react-dom, and react-server-dom-webpack are installed on
the unit with npm install rather than bundled.
During alchemy dev the site is vinext dev and no cloud resources
are declared; Alchemy.remote() opts back into the live Service.
Vinext: Creating vinext Sites
Section titled “Vinext: Creating vinext Sites”Basic vinext App
const site = yield* Hetzner.Website.Vinext("Web", { rootDir: "./app",});Custom Domain
const site = yield* Hetzner.Website.Vinext("Web", { rootDir: "./app", domain: "app.example.com", zone,});Redis data cache
ISR / "use cache" default to in-process memory. Set env.REDIS_URL on
this resource for a durable Redis store; the adapter is injected automatically.
const site = yield* Hetzner.Website.Vinext("Web", { env: { REDIS_URL: "redis://cache.internal:6379", },});Source:
src/Hetzner/Website/Vite.ts
Deploy a plain Vite application to a Hetzner Cloud
Server: vite build output served by a static-file systemd unit on
port 3000. For client-only projects — React/Vue/Solid SPAs,
index.html multi-page apps — whose entire deployable output is
static assets.
The build runs through @alchemy.run/frontend-frameworks/vite with the
@alchemy.run/frontend-frameworks/vite/node deploy target — the package
must be installed in your project. During alchemy dev the site is
Vite’s own dev server and no cloud resources are created.
Vite: Creating Vite Sites
Section titled “Vite: Creating Vite Sites”Basic Vite SPA
const site = yield* Hetzner.Website.Vite("Web");Project in a Subdirectory
const site = yield* Hetzner.Website.Vite("Web", { rootDir: "./app",});Existing Server
const server = yield* Hetzner.Server("box", { serverType: "cpx12", image: "ubuntu-24.04", location: "fsn1",});const site = yield* Hetzner.Website.Vite("Web", { server });Vite: Multi-Page Sites
Section titled “Vite: Multi-Page Sites”const site = yield* Hetzner.Website.Vite("Docs", { assets: { notFoundHandling: "404-page" },});Vite: Custom Domain
Section titled “Vite: Custom Domain”const site = yield* Hetzner.Website.Vite("Web", { domain: "app.example.com", zone,});Vite: Build Configuration
Section titled “Vite: Build Configuration”const site = yield* Hetzner.Website.Vite("Docs", { outDir: "build", base: "/docs/",});Vite: Local Development
Section titled “Vite: Local Development”// `alchemy dev` starts `vite` programmatically: site.url is the local// dev server (HMR included); no Server or Service is created.const site = yield* Hetzner.Website.Vite("Web");Source:
src/Hetzner/Website/Vocs.ts
Deploy a Vocs documentation project to a Hetzner
Cloud Server. Static assets first, then Vocs’ Waku RSC handler
(/about → about/index.html, otherwise SSR).
Vocs: Creating Vocs Sites
Section titled “Vocs: Creating Vocs Sites”Vocs Documentation Site
const docs = yield* Hetzner.Website.Vocs("Docs", { rootDir: "./docs",});Custom Output Directory
const docs = yield* Hetzner.Website.Vocs("Docs", { rootDir: "./docs", outDir: "build",});Source:
src/Hetzner/Website/Waku.ts
Deploy a Waku application to a Hetzner Cloud Server:
the RSC server as a systemd unit on port 3000, static assets (SSG
pages included) baked into the unit. Prerendered pages are served
extensionless (/about not /about/).
Waku: Creating Waku Sites
Section titled “Waku: Creating Waku Sites”Basic Waku App
const site = yield* Hetzner.Website.Waku("Web", { rootDir: "./app",});Custom Domain
const site = yield* Hetzner.Website.Waku("Web", { rootDir: "./app", domain: "app.example.com", zone,});