Skip to content

Websites

Alchemy deploys frontends to Railway with a family of Railway.Website resources. Each one builds your project programmatically and deploys it as a Service from a container image — Node on port 3000, health check /health — with no railway.toml and no adapter to put in the framework config. Your framework’s own config file (vite.config.ts, astro.config.*, nuxt.config.ts, …) loads natively; Alchemy layers its Node container integration on top.

Omit project and Alchemy creates a Railway.Project. Pass project to put the site next to other Services in an existing Project.

The live path generates a Dockerfile and uploads it; Railway builds the image. No GHCR. No Docker daemon on your machine. alchemy dev never creates a Project or Service.

The live URL is the generated https://{name}.up.railway.app, or https://{domain} when you pass domain (a CustomDomain on port 3000).

  • Vite — client-only Vite apps (React, Vue, Solid SPAs, index.html multi-page sites); a tiny static-file server serves the vite build output.
  • Astro — Astro sites, server-rendered on Node or fully static; your astro.config.* loads natively.
  • Nextjs — Next.js as a long-running Node process (next build, then next({ dev: false })). Not OpenNext.
  • Nuxt — Nuxt apps through nitro’s Node server; your nuxt.config.ts loads natively. Do not set nitro.preset.
  • ReactRouter — React Router v7 in framework mode, built through your own vite build.
  • SolidStart — SolidStart 2.x SSR; Alchemy appends nitro’s node preset to your vite build.
  • SvelteKit — SvelteKit SSR plus prerendered assets; the Node adapter is injected. Do not set kit.adapter.
  • TanStackStart — TanStack Start (React or Solid), built through your own vite build.
  • Waku — Waku (React Server Components) on Node, with SSG pages baked into the image.
  • Octane — OctaneJS SSR. Select node() from @alchemy.run/frontend-frameworks/octane/node-adapter in octane.config.ts.
  • Foldkit — client-only Foldkit SPA; deep links fall back to index.html.
  • Vocs — prerendered Vocs docs; extensionless pages (/aboutabout/index.html).
  • StaticSite — any build command’s output directory (Hugo, Zola, Eleventy).

The return is { url, service, project }service and project are undefined under alchemy dev.

Shared props: rootDir, memo, env (process environment on the Service — not Worker bindings), dev, domain, project. Builds are memoized by content-hashing the input files — an unchanged project skips the build.

Framework Resource Guide
React / Vue / Solid SPA Vite Vite
TanStack Start (React & Solid) TanStackStart TanStack Start
React Router ReactRouter React Router
SolidStart SolidStart SolidStart
Astro Astro Astro
Next.js Nextjs Next.js
Nuxt Nuxt Nuxt
SvelteKit SvelteKit SvelteKit
Waku Waku Waku
OctaneJS Octane Octane
Foldkit Foldkit Foldkit
Vocs Vocs Vocs
Zola, Hugo, or any static generator StaticSite Static sites

See examples/railway-website-vite for a Vite SPA in a shared Project.

Use the resource named after your framework. Astro, Nextjs, Nuxt, ReactRouter, SolidStart, SvelteKit, TanStackStart, Waku, Octane, Foldkit, and Vocs each drive that framework’s programmatic build and know its output layout, config surface, and dev server.

Use Vite when the whole deployable output is static assets — a React, Vue, or Solid SPA, or an index.html-per-route multi-page app. SSR frameworks that wrap Vite (Astro, SvelteKit, Octane, …) have their own resources; Vite never starts a framework server module.

Use StaticSite when the build is an arbitrary shell command that emits a directory of files.

Top-level env is copied onto process.env before build and dev, and onto the Railway Service at deploy. Client inlining is whatever the framework already does (VITE_* for Vite). It is not Worker bindings and not AWS server.environment.

const site = yield* Railway.Website.Vite("Web", {
project,
env: {
VITE_API_URL: api.url,
},
});

Server code reads process.env. Pair a site with Postgres in the same Project the same way you would any other Service.

alchemy dev runs the framework’s own dev server (native HMR) instead of deploying. site.url is the local address and no Project or Service is created. Wrap the site in Alchemy.remote() to deploy the live path even during dev.

const site = yield* Railway.Website.Astro("Web", {
project,
domain: "app.example.com",
});

domain attaches a Railway.CustomDomain (targetPort: 3000). url becomes https://app.example.com instead of the generated *.up.railway.app.