SolidStart
SolidStart builds through Vite: the solidStart() plugin in your
vite.config.ts owns routing, SSR, and the server entry, and a
single vite build produces the whole app. That makes it a pure-Vite
project, so Cloudflare.Website.Vite
deploys it directly — no adapter config, no Wrangler file, no manual
entrypoint.
Using TanStack Start with Solid instead? See TanStack Start.
Configure Vite
Section titled “Configure Vite”Your vite.config.ts is just the SolidStart plugin — Alchemy layers
its Cloudflare integration on top when it builds:
import { defineConfig } from "vite";
import { solidStart } from "@solidjs/start/config";
export default defineConfig({ plugins: [solidStart()],});Because SolidStart is fully expressed as a Vite plugin, Alchemy’s
programmatic vite build picks up the client assets and the SSR
server bundle from this one config — the server bundle becomes the
deployed Worker, the client output becomes its static assets.
Add it to the Stack
Section titled “Add it to the Stack”Yield Cloudflare.Website.Vite from your Stack with nodejs_compat
enabled:
import * as Alchemy from "alchemy";import * as Cloudflare from "alchemy/Cloudflare";import * as Effect from "effect/Effect";
export default Alchemy.Stack( "CloudflareSolidStartExample", { providers: Cloudflare.providers(), state: Cloudflare.state(), }, Effect.gen(function* () { const worker = yield* Cloudflare.Website.Vite("CloudflareSolidStart", { compatibility: { flags: ["nodejs_compat"], }, });
return { url: worker.url, }; }),);The nodejs_compat flag is required because SolidStart’s SSR server
bundle uses Node APIs at runtime; without it the deployed Worker
fails to start.
Hand-rolled SolidJS SSR
Section titled “Hand-rolled SolidJS SSR”You don’t need SolidStart to server-render Solid. The
examples/cloudflare-solidjs-ssr
example uses plain vite-plugin-solid with SSR enabled and declares
an ssr environment whose input is a hand-written server entry:
import { dirname, resolve } from "node:path";import { fileURLToPath } from "node:url";import { defineConfig } from "vite";import solidPlugin from "vite-plugin-solid";
const __dirname = dirname(fileURLToPath(import.meta.url));
export default defineConfig({ plugins: [solidPlugin({ ssr: true })], environments: { ssr: { build: { emptyOutDir: false, rolldownOptions: { input: resolve(__dirname, "src/entry-server.tsx"), }, }, }, },});src/entry-server.tsx default-exports a standard Worker fetch
handler that calls Solid’s renderToStringAsync and injects the
result (plus the hydration script) into the HTML template — that
file becomes the Worker entry, while the client build ships as
static assets.
Deploy with runWorkerFirst
Section titled “Deploy with runWorkerFirst”Because the Worker itself renders every page, requests must reach it
before the asset layer answers — set assets.runWorkerFirst:
import * as Alchemy from "alchemy";import * as Cloudflare from "alchemy/Cloudflare";import * as Effect from "effect/Effect";
export default Alchemy.Stack( "CloudflareSolidJSSSRExample", { providers: Cloudflare.providers(), state: Cloudflare.state(), }, Effect.gen(function* () { const worker = yield* Cloudflare.Website.Vite("SolidJSSrr", { compatibility: { flags: ["nodejs_compat"], }, assets: { runWorkerFirst: true, }, });
return { url: worker.url, }; }),);With runWorkerFirst: true the SSR handler sees every request first
and delegates to the ASSETS binding itself for static files —
without it, a request matching a built asset (like /index.html)
would be served directly and never hit your renderer.
Deploy
Section titled “Deploy”bun alchemy deployAlchemy runs the Vite build, uploads the client assets, deploys the
SSR bundle as the Worker, and prints the stack’s url output.
Inputs are content-hashed, so re-deploying an unchanged project
skips the build entirely.
Local dev
Section titled “Local dev”bun alchemy devalchemy dev boots Vite’s own dev server programmatically — HMR and
instant module updates work as in a plain SolidStart project, while
any bound backend resources are the real cloud resources.
Environment variables and bindings
Section titled “Environment variables and bindings”Both env channels of the Vite resource apply unchanged: VITE_-prefixed
env entries are inlined into the client bundle as
import.meta.env.<KEY> at build time, and everything else attaches
to the SSR Worker as runtime bindings. See
the Vite resource page for how each
channel works.