1---
2title: Astro
3description: Deploy Astro SSR or a fully static site to Prisma Compute with Prisma.Website.Astro, running on Bun with native Astro dev locally.
4sidebar:
5 order: 11
6---
7
8import { Code, Tabs, TabItem } from "@astrojs/starlight/components";
9
10export const devDeps = "@alchemy.run/frontend-frameworks @vercel/nft";
11
12`Prisma.Website.Astro` builds an [Astro](https://astro.build) project
13with the shared Node target and runs it on **Bun in Prisma Compute**.
14Assets are served first, then the Astro SSR handler. Fully static
15output uses a static-file server on the same Compute runtime. Both
16paths upload a `tar.gz` artifact, not a container image.
17
18## Install
19
20Install the build-time integration in your Astro project. The resource
21loads its `/astro` and `/astro/node` exports:
22
23<Tabs syncKey="pkgManager">
24 <TabItem label="bun" icon="bun"><Code code={`bun add -d ${devDeps}`} lang="sh" /></TabItem>
25 <TabItem label="npm" icon="npm"><Code code={`npm install -D ${devDeps}`} lang="sh" /></TabItem>
26 <TabItem label="pnpm" icon="pnpm"><Code code={`pnpm add -D ${devDeps}`} lang="sh" /></TabItem>
27 <TabItem label="yarn" icon="seti:yarn"><Code code={`yarn add -D ${devDeps}`} lang="sh" /></TabItem>
28</Tabs>
29
30## Configure Astro
31
32Your `astro.config.*` loads natively, including integrations and Vite
33plugins. Do not declare an `adapter`: Alchemy injects the Node-target
34adapter and rejects a conflicting adapter. The deployed runtime is Bun,
35not a Node container.
36
37## Declare the Website
38
39```typescript
40// alchemy.run.ts
41import * as Prisma from "alchemy/Prisma";
42
43export const Website = Prisma.Website.Astro("Website");
44```
45
46Pass `rootDir` when `package.json` is not at `.`. Omit `project` to
47create a database-less Prisma project on live deploy, or pass an
48existing project.
49
50## Add it to the Stack
51
52```typescript
53// alchemy.run.ts
54import * as Alchemy from "alchemy";
55import * as Effect from "effect/Effect";
56
57export default Alchemy.Stack(
58 "MyAstroSite",
59 { providers: Prisma.providers(), state: Alchemy.localState() },
60 Effect.gen(function* () {
61 const site = yield* Website;
62 return { url: site.url };
63 }),
64);
65```
66
67Pages render on demand by default. A page with
68`export const prerender = true` is generated at build time and served
69as a file. `site.url` is the Compute endpoint on deploy.
70
71## Add environment variables
72
73```diff lang="typescript"
74export const Website = Prisma.Website.Astro("Website", {
75+ env: {
76+ GREETING: "Hello from Alchemy!",
77+ API_BASE: "https://api.example.com",
78+ },
79});
80```
81
82`env` accepts strings or `Redacted` values. It is applied before build
83and dev and passed to Compute as process environment, not Worker bindings.
84
85## Read the environment in server code
86
87```astro
88---
89// src/pages/index.astro
90const greeting = process.env.GREETING ?? "hello";
91---
92
93<h1>{greeting}</h1>
94```
95
96Server-rendered pages read the Bun process environment. Astro inlines
97`PUBLIC_*` values at build time, so keep secrets out of those keys.
98
99## Fully static sites
100
101```typescript
102export const Website = Prisma.Website.Astro("Website", {
103 astro: { output: "static" },
104 assets: { notFoundHandling: "404-page" },
105});
106```
107
108Every page is prerendered. There is no Astro request handler, but
109**Compute still runs the static-file server**. This is not a CDN-only
110deployment. `assets.notFoundHandling` applies to static output:
111`"404-page"` serves `404.html` for misses; `"single-page-application"`
112returns the index page with status 200.
113
114## Astro configuration
115
116Keep integrations and plugins in your native config:
117
118```typescript
119// astro.config.ts
120import { defineConfig } from "astro/config";
121import react from "@astrojs/react";
122import tailwindcss from "@tailwindcss/vite";
123
124export default defineConfig({
125 site: "https://blog.example.com",
126 integrations: [react()],
127 vite: { plugins: [tailwindcss()] },
128});
129```
130
131The `astro` bag holds deploy-specific overrides:
132
133```typescript
134export const Website = Prisma.Website.Astro("Website", {
135 astro: { site: "https://preview.example.com" },
136});
137```
138
139Alchemy owns `adapter` and defaults `output` to `"server"`, even when
140the file sets another output. Select static output on the resource.
141The bag also exposes `base`, `srcDir`, `publicDir`, `outDir`, and
142`trailingSlash`.
143
144## Local dev
145
146`bun alchemy dev` starts Astro's own server with HMR; the Website
147creates no Prisma resources. `site.url` is the local address.
148`.pipe(Alchemy.remote())` opts into the live deployment during dev.
149
150## Custom domain
151
152```typescript
153export const Website = Prisma.Website.Astro("Website", {
154 domain: "app.example.com",
155});
156```
157
158`Prisma.CustomDomain` requires the app to be on the project's current
159default branch. Configure its returned `dnsRecords` yourself and verify
160status before routing traffic. See
161[Custom domains](/prisma/frontend/websites#custom-domains).
162
163## Where next
164
165- [Astro API](/providers/prisma/website/astro).
166- [Astro example](https://github.com/alchemy-run/alchemy/tree/main/examples/prisma-website-astro).
167- [Static sites](/prisma/frontend/static-site) and [Websites](/prisma/frontend/websites).
168- [Compute apps](/prisma/compute/apps) and [Setup](/prisma/setup).