Vocs
Railway.Website.Vocs deploys a Vocs
documentation project as one
Railway.Service from a container
image. Vocs prerenders static HTML; a Node static-file server
serves extensionless pages (/about not /about/). Your vocs.config.* loads natively — there is
no adapter to install.
Install
Section titled “Install”The build integration is not bundled with alchemy. Install
@alchemy.run/frontend-frameworks; the resource loads
/vocs/node 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-frameworksThe project also needs vocs and Vocs’ Waku peer dependencies.
Configure Vocs
Section titled “Configure Vocs”Your vocs.config.* file loads natively — title, sidebar, and any
other Vocs options work exactly as they do outside Alchemy:
import { defineConfig } from "vocs/config";
export default defineConfig({ title: "Docs", sidebar: [ { text: "Home", link: "/" }, { text: "Guide", link: "/guide" }, ],});If vocs.config.* sets outDir, pass the same value on the
resource (default "dist") so generated output stays outside the
rebuild hash:
export const Website = Railway.Website.Vocs("Website", { rootDir: "./docs", outDir: "build",});Declare the Website
Section titled “Declare the Website”Declare the site as a module-level const (rather than inline in the Stack):
import * as Railway from "alchemy/Railway";
export const Website = Railway.Website.Vocs("Website", { rootDir: "./docs",});Omit project to create a Railway.Project under this site’s
namespace. Pass an existing Railway.Project when the site should
live next to other Services:
export const Site = Railway.Project("Site");
export const Website = Railway.Website.Vocs("Website", { rootDir: "./docs", project: Site,});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( "MyVocsSite", { providers: Railway.providers(), state: Alchemy.localState(), }, Effect.gen(function* () { const site = yield* Website; return { url: site.url }; }),);The live URL is the generated https://{name}.up.railway.app
(site.service.url). The Service listens on port 3000 with
healthcheck: "/health". site.service and site.project are set
on deploy.
Add environment variables
Section titled “Add environment variables”Top-level env is copied onto process.env before build and
alchemy dev, and onto the Service at deploy:
export const Website = Railway.Website.Vocs("Website", { rootDir: "./docs", env: { DOCS_TITLE: "Hello from Alchemy!", },});These are process environment variables, not Worker bindings.
Read the environment
Section titled “Read the environment”Vocs prerenders at build time, so page content that reads
process.env is baked into the HTML. The same values are set on
the hosted Node process; there is no request-time Vocs server.
const title = process.env.DOCS_TITLE ?? "Docs";Local development
Section titled “Local development”alchemy dev runs Vocs’ own dev server (native HMR) instead of
deploying; site.url is the local address and no Railway resources
are created (service and project are undefined). Wrap the
site in Alchemy.remote() to deploy the live
Service even during dev:
export const Website = Railway.Website.Vocs("Website", { rootDir: "./docs",}).pipe(Alchemy.remote());Custom domain
Section titled “Custom domain”domain is a hostname string. Alchemy attaches a
CustomDomain (targetPort: 3000); url
becomes https://{domain} instead of *.up.railway.app:
export const Website = Railway.Website.Vocs("Website", { rootDir: "./docs", domain: "docs.example.com",});Where next
Section titled “Where next”Vocsreference — every prop and attribute- Projects and Services — the container the site runs in
- Custom domains — hostnames on a Service
- Railway — the Railway provider hub