Railway.Website reference
Source:
src/Railway/Website/Astro.ts
Deploy an Astro application to Railway: the Node
SSR bundle (assets first, then the Astro fetch handler) on one
Railway.Service. Pages render on demand by default
(output: "server"); pages that export const prerender = true are
prerendered at build time and served as static files. With
astro: { output: "static" } every page is prerendered and the deploy
is assets-only.
The build runs through @alchemy.run/frontend-frameworks/astro with the
@alchemy.run/frontend-frameworks/astro/node deploy target (a Node
adapter is injected — your astro.config.* must not declare one).
During alchemy dev the site is Astro’s own dev server and no cloud
resources are created. Alchemy.remote() opts back into the live
Service path.
Astro: Creating Astro Sites
Section titled “Astro: Creating Astro Sites”const site = yield* Railway.Website.Astro("Web", { rootDir: "./app",});Astro: Static Sites
Section titled “Astro: Static Sites”const site = yield* Railway.Website.Astro("Docs", { rootDir: "./docs", astro: { output: "static" }, errorPage: "404.html",});Astro: Server Configuration
Section titled “Astro: Server Configuration”const site = yield* Railway.Website.Astro("Web", { rootDir: "./app", env: { API_BASE: "https://api.example.com", },});Source:
src/Railway/Website/Cdn.ts
Enable Railway’s built-in CDN on a Website Service. Static assets
(by Content-Type) are cached at the edge; HTML follows
CdnProps.htmlCaching.
Foldkit
Section titled “Foldkit”Source:
src/Railway/Website/Foldkit.ts
Deploy a Foldkit app to Railway: a Vite SPA with
unmatched paths falling back to index.html so deep links boot the
Foldkit router. Same Node static-file Service as Vite.
Foldkit apps are client-only Vite projects — the Foldkit Vite plugin in
the app’s vite.config.ts composes with the project’s own Vite build.
During alchemy dev the site is Vite’s own dev server and no cloud
resources are created. Alchemy.remote() opts back into the live
Service path.
Foldkit: Deploying a Foldkit App
Section titled “Foldkit: Deploying a Foldkit App”Foldkit app
const site = yield* Railway.Website.Foldkit("Website");Foldkit project in a subdirectory
const site = yield* Railway.Website.Foldkit("Website", { rootDir: "applications/web",});Foldkit: Single-Page Application Routing
Section titled “Foldkit: Single-Page Application Routing”const site = yield* Railway.Website.Foldkit("Website", { assets: { notFoundHandling: "404-page" },});Nextjs
Section titled “Nextjs”Source:
src/Railway/Website/Nextjs.ts
Deploy a Next.js application to Railway as a long-running Node process:
next build, then a serve entry that import("next") +
next({ dev: false }).prepare() + getRequestHandler() on PORT
(default 3000). Not OpenNext — those wrappers are Lambda/workerd.
The image npm installs next, react, and react-dom, and bakes
.next plus public/ into /app.
During alchemy dev the site is Next’s own dev server (next dev) and
no cloud resources are declared; Alchemy.remote() opts back into the
full live deployment.
Nextjs: Creating Next.js Sites
Section titled “Nextjs: Creating Next.js Sites”const site = yield* Railway.Website.Nextjs("Web", { rootDir: "./app",});Nextjs: Server Configuration
Section titled “Nextjs: Server Configuration”const site = yield* Railway.Website.Nextjs("Web", { rootDir: "./app", env: { API_BASE: "https://api.example.com", },});Source:
src/Railway/Website/Nuxt.ts
Deploy a Nuxt application to Railway: the nitro Node server plus
prerendered assets on one Railway.Service. The Node deploy target
enforces nitro’s node preset; do not set nitro.preset.
During alchemy dev the site is Nuxt’s own dev server and no cloud
resources are created. Alchemy.remote() opts back into the live
Service path.
Nuxt: Creating Nuxt Sites
Section titled “Nuxt: Creating Nuxt Sites”const site = yield* Railway.Website.Nuxt("Web", { rootDir: "./app",});Nuxt: Server Configuration
Section titled “Nuxt: Server Configuration”const site = yield* Railway.Website.Nuxt("Web", { rootDir: "./app", env: { NUXT_PUBLIC_API_BASE: "https://api.example.com", },});Octane
Section titled “Octane”Source:
src/Railway/Website/Octane.ts
Deploy an OctaneJS application to Railway:
Octane’s SSR server plus client assets on one Railway.Service.
Railway.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.
During alchemy dev the site is Octane/Vite’s own dev server and no
cloud resources are created. Alchemy.remote() opts back into the live
Service path.
Octane: Creating Octane Sites
Section titled “Octane: Creating Octane Sites”const site = yield* Railway.Website.Octane("Web", { rootDir: "./app",});Octane: Server Configuration
Section titled “Octane: Server Configuration”const site = yield* Railway.Website.Octane("Web", { rootDir: "./app", env: { API_BASE: "https://api.example.com", },});ReactRouter
Section titled “ReactRouter”Source:
src/Railway/Website/ReactRouter.ts
Deploy a React Router v7 app (framework mode)
to Railway: the SSR server plus client assets on one Railway.Service.
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 wraps the manifest with createRequestHandler and packages
the resulting fetch handler as a Node HTTP server on port 3000.
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.
During alchemy dev the site is React Router’s own Vite dev server and
no cloud resources are created. Alchemy.remote() opts back into the
live Service path.
ReactRouter: Creating React Router Sites
Section titled “ReactRouter: Creating React Router Sites”Basic React Router App
const site = yield* Railway.Website.ReactRouter("Web", { rootDir: "./app",});Custom Domain
const site = yield* Railway.Website.ReactRouter("Web", { rootDir: "./app", domain: "app.example.com",});ReactRouter: Server Configuration
Section titled “ReactRouter: Server Configuration”Process Environment
const site = yield* Railway.Website.ReactRouter("Web", { rootDir: "./app", env: { GREETING: "Hello from React Router on Railway!", },});Read An Environment Variable From A Loader
export function loader() { return { apiBase: process.env.API_BASE ?? "unset" };}SolidStart
Section titled “SolidStart”Source:
src/Railway/Website/SolidStart.ts
Deploy a SolidStart application to Railway:
the SSR server plus client assets (prerendered pages included) on one
Railway.Service.
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.
During alchemy dev the site is SolidStart’s own Vite dev server and no
cloud resources are created. Alchemy.remote() opts back into the live
Service path.
SolidStart: Creating SolidStart Sites
Section titled “SolidStart: Creating SolidStart Sites”Basic SolidStart App
const site = yield* Railway.Website.SolidStart("Web", { rootDir: "./app",});Custom Domain
const site = yield* Railway.Website.SolidStart("Web", { rootDir: "./app", domain: "app.example.com",});SolidStart: Server Configuration
Section titled “SolidStart: Server Configuration”const site = yield* Railway.Website.SolidStart("Web", { rootDir: "./app", env: { GREETING: "Hello from SolidStart on Railway!", },});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
Service image and served as static files.
const site = yield* Railway.Website.SolidStart("Web", { rootDir: "./app", nitro: { prerender: { routes: ["/", "/about"] } },});StaticSite
Section titled “StaticSite”Source:
src/Railway/Website/StaticSite.ts
A Railway Service that serves static assets built by a shell command.
StaticSite runs a build command (e.g. npm run build), content-hashes
the output directory, and deploys the result as a Node static-file
server on one Railway.Service. Use this when your site has its own
build step that produces a directory of files — Hugo, Zola, Eleventy, or
any custom pipeline.
For Vite-based projects, prefer Railway.Website.Vite which handles building automatically.
Cloudflare DX: top-level command + outdir (Command.BuildProps).
Only Command.Build("Build") / Command.Dev("Dev") are pushed under
the site id; the Service stays in the caller namespace.
During alchemy dev, dev.command skips the build and is the site.
Without dev.command, the site still builds and a local static server
serves outdir — no Project or Service is created.
StaticSite: Basic Usage
Section titled “StaticSite: Basic Usage”Deploying a Hugo site
const site = yield* Railway.Website.StaticSite("Blog", { command: "hugo --minify", outdir: "public",});SPA-style routing
const site = yield* Railway.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* Railway.Website.StaticSite("Web", { cwd: "apps/web", command: "npm run build", outdir: "dist",});StaticSite: Local Development
Section titled “StaticSite: Local Development”const site = yield* Railway.Website.StaticSite("App", { command: "npm run build", outdir: "dist", dev: { command: "npm run dev" },});SvelteKit
Section titled “SvelteKit”Source:
src/Railway/Website/SvelteKit.ts
Deploy a SvelteKit application to Railway: kit’s SSR server plus
prerendered assets on one Railway.Service. The Node deploy target
injects an in-memory kit adapter; do not set adapter in kit.
During alchemy dev the site is SvelteKit’s own dev server and no cloud
resources are created. Alchemy.remote() opts back into the live
Service path.
SvelteKit: Creating SvelteKit Sites
Section titled “SvelteKit: Creating SvelteKit Sites”const site = yield* Railway.Website.SvelteKit("Web", { rootDir: "./app",});SvelteKit: Server Configuration
Section titled “SvelteKit: Server Configuration”const site = yield* Railway.Website.SvelteKit("Web", { rootDir: "./app", env: { API_BASE: "https://api.example.com", },});TanStackStart
Section titled “TanStackStart”Source:
src/Railway/Website/TanStackStart.ts
Deploy a TanStack Start application to
Railway: the SSR server plus client assets on one Railway.Service.
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 on port 3000.
During alchemy dev the site is TanStack Start’s own Vite dev server
and no cloud resources are created. Alchemy.remote() opts back into
the live Service path.
TanStackStart: Creating TanStack Start Sites
Section titled “TanStackStart: Creating TanStack Start Sites”Basic TanStack Start App
const site = yield* Railway.Website.TanStackStart("Web", { rootDir: "./app",});Custom Domain
const site = yield* Railway.Website.TanStackStart("Web", { rootDir: "./app", domain: "app.example.com",});TanStackStart: Server Configuration
Section titled “TanStackStart: Server Configuration”Process Environment
const site = yield* Railway.Website.TanStackStart("Web", { rootDir: "./app", env: { GREETING: "Hello from TanStack Start on Railway!", },});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/Railway/Website/Vinext.ts
Deploy a vinext application to Railway as a
long-running Node process: vinext’s Vite build, then vinext’s production
server (startProdServer) on PORT (default 3000). Not the
Cloudflare Worker path — those wrappers are workerd.
The image npm installs vinext, react, react-dom, and
react-server-dom-webpack, and bakes dist/ into /app.
During alchemy dev the site is vinext’s own dev server (vinext dev) and no cloud resources are declared; Alchemy.remote() opts
back into the full live deployment.
Vinext: Creating vinext Sites
Section titled “Vinext: Creating vinext Sites”const site = yield* Railway.Website.Vinext("Web", { rootDir: "./app",});Vinext: Server Configuration
Section titled “Vinext: Server Configuration”Process Environment
const site = yield* Railway.Website.Vinext("Web", { rootDir: "./app", env: { GREETING: "Hello from vinext on Railway!", },});Redis data cache
const project = yield* Railway.Project("Project");const redis = yield* Railway.Redis("Cache", { project });const site = yield* Railway.Website.Vinext("Web", { project, redis,});Source:
src/Railway/Website/Vite.ts
Deploy a plain Vite application to Railway: static
assets (the vite build output) served by a generated Node static-file
server on one Railway.Service. 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. Your project’s own vite.config.*
(plugins included) drives the build.
During alchemy dev the site is Vite’s own dev server (native HMR) and
no cloud resources are created — the site’s url is the dev server’s
local address. Alchemy.remote() opts back into the full deployment.
SSR frameworks that wrap Vite deploy through their own composites (Railway.Website.Astro, Railway.Website.SvelteKit, Railway.Website.Octane, …) — this composite never creates a framework server module.
Vite: Creating Vite Sites
Section titled “Vite: Creating Vite Sites”Basic Vite SPA
const site = yield* Railway.Website.Vite("Web");Project in a Subdirectory
const site = yield* Railway.Website.Vite("Web", { rootDir: "./app",});Existing Project
const project = yield* Railway.Project("Site");const site = yield* Railway.Website.Vite("Web", { project,});Vite: Multi-Page Sites
Section titled “Vite: Multi-Page Sites”const site = yield* Railway.Website.Vite("Docs", { assets: { notFoundHandling: "404-page" },});Vite: Build Configuration
Section titled “Vite: Build Configuration”const site = yield* Railway.Website.Vite("Docs", { vite: { 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 Project or Service is created.const site = yield* Railway.Website.Vite("Web");Source:
src/Railway/Website/Vocs.ts
Deploy a Vocs documentation project to Railway: static
assets first, then Vocs’ Waku RSC handler (/about not /about/) from
one Railway.Service.
Requires @alchemy.run/frontend-frameworks, vocs, and Vocs’ Waku peer
dependencies in the project.
During alchemy dev the site is Vocs’ own dev server and no cloud
resources are created. Alchemy.remote() opts back into the live
Service path.
Vocs: Deploying a Vocs Site
Section titled “Vocs: Deploying a Vocs Site”const docs = yield* Railway.Website.Vocs("Docs", { rootDir: "./docs",});Vocs: Custom Build Output
Section titled “Vocs: Custom Build Output”// vocs.config.ts: defineConfig({ outDir: "build" })const docs = yield* Railway.Website.Vocs("Docs", { rootDir: "./docs", outDir: "build",});Source:
src/Railway/Website/Waku.ts
Deploy a Waku application to Railway: the RSC server
plus SSG pages on one Railway.Service. The Node deploy target selects
waku’s node adapter; do not set unstable_adapter. SSG pages are
served extensionless (/about).
During alchemy dev the site is Waku’s own dev server and no cloud
resources are created. Alchemy.remote() opts back into the live
Service path.
Waku: Creating Waku Sites
Section titled “Waku: Creating Waku Sites”const site = yield* Railway.Website.Waku("Web", { rootDir: "./app",});Waku: Server Configuration
Section titled “Waku: Server Configuration”const site = yield* Railway.Website.Waku("Web", { rootDir: "./app", env: { API_BASE: "https://api.example.com", },});