# Build a marketing site with Astro (/docs/guides/compute/astro-marketing-site) > For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL. Build a static marketing site with Astro, serve it from a Node server, and deploy it to Prisma Compute with Prisma Composer. Location: Guides > Build on Compute > Build a marketing site with Astro ## Introduction [#introduction] This guide builds a small marketing site with [Astro](https://astro.build) (a home page, a pricing page, and an about page) and deploys it to [Prisma Compute](https://www.prisma.io/docs/compute). Every page is rendered to static HTML at build time, so the site needs no database and no Prisma ORM. Compute runs a server process, not a folder of files. The one Astro-specific step is adding the Node adapter, which keeps your pages static and adds a small server that serves them. Every command below was run end to end, including the deploy. ## Prerequisites [#prerequisites] * [Node.js](https://nodejs.org) 24 or later * A [Prisma Data Platform account](https://pris.ly/pdp), free to create. You only need it for the deploy step. ## 1. Scaffold the site [#1-scaffold-the-site] Create an Astro project from the minimal template: #### bun ```bash bun create astro@latest marketing-site --template minimal --install --no-git --yes cd marketing-site ``` #### pnpm ```bash pnpm create astro@latest marketing-site --template minimal --install --no-git --yes cd marketing-site ``` #### yarn ```bash yarn create astro@latest marketing-site --template minimal --install --no-git --yes cd marketing-site ``` #### npm ```bash npm create astro@latest -- marketing-site --template minimal --install --no-git --yes cd marketing-site ``` ```text no-copy ✔ Project initialized! ■ Template copied ■ Dependencies installed next Liftoff confirmed. Explore your project! ``` The template gives you one page, `src/pages/index.astro`, and an empty `astro.config.mjs`. ## 2. Build the pages [#2-build-the-pages] Add a shared layout with the header and navigation every page uses: ```astro title="src/layouts/Base.astro" --- interface Props { title: string; description: string; } const { title, description } = Astro.props; --- {title}
Acme
``` Replace the home page and add the other two pages: ```astro title="src/pages/index.astro" --- import Base from "../layouts/Base.astro"; ---

Ship faster with Acme

Everything your team needs to go from idea to production.

See pricing ``` ```astro title="src/pages/pricing.astro" --- import Base from "../layouts/Base.astro"; const plans = [ { name: "Starter", price: "$0", blurb: "For side projects." }, { name: "Team", price: "$29", blurb: "For growing teams." }, ]; ---

Pricing

``` ```astro title="src/pages/about.astro" --- import Base from "../layouts/Base.astro"; ---

About Acme

We build tools for teams that ship.

``` Run `npm run dev` and open [http://localhost:4321](http://localhost:4321) to check the pages, then stop the dev server. ## 3. Add the Node adapter [#3-add-the-node-adapter] Compute needs a server entrypoint to run. A plain Astro build only produces HTML files, so add the Node adapter in standalone mode: #### bun ```bash bunx astro add node --yes ``` #### pnpm ```bash pnpm dlx astro add node --yes ``` #### yarn ```bash yarn dlx astro add node --yes ``` #### npm ```bash npx astro add node --yes ``` ```js title="astro.config.mjs" // @ts-check import { defineConfig } from 'astro/config'; import node from '@astrojs/node'; // https://astro.build/config export default defineConfig({ adapter: node({ mode: 'standalone' }) }); ``` Leave `output` unset. It defaults to `"static"`, so every page is still rendered at build time. The adapter adds a server that serves those files. Build to confirm: #### bun ```bash bun run build ``` #### pnpm ```bash pnpm run build ``` #### yarn ```bash yarn build ``` #### npm ```bash npm run build ``` ```text no-copy [build] output: "static" [build] mode: "server" [build] adapter: @astrojs/node [build] Building server entrypoints... prerendering static routes ├─ /about/index.html (+7ms) ├─ /pricing/index.html (+3ms) ├─ /index.html (+4ms) ✓ Completed in 50ms. [build] Server built in 815ms [build] Complete! ``` The pages land in `dist/client/` and the server lands in `dist/server/entry.mjs`. Compute runs that server. ## 4. Declare the app with Prisma Composer [#4-declare-the-app-with-prisma-composer] [Prisma Composer](https://www.prisma.io/docs/composer) describes what to deploy. Install it, plus the Prisma CLI as a dev dependency: #### bun ```bash bun add @prisma/composer @prisma/composer-prisma-cloud bun add --dev prisma ``` #### pnpm ```bash pnpm add @prisma/composer @prisma/composer-prisma-cloud pnpm add -D prisma ``` #### yarn ```bash yarn add @prisma/composer @prisma/composer-prisma-cloud yarn add --dev prisma ``` #### npm ```bash npm install @prisma/composer @prisma/composer-prisma-cloud npm install -D prisma ``` Declare the service and point it at the Astro server entry. `dir` is the build output directory, and `entry` is the server file inside it: ```ts title="service.ts" import node from "@prisma/composer/node"; import { compute } from "@prisma/composer-prisma-cloud"; export default compute({ name: "web", deps: {}, build: node({ module: import.meta.url, dir: "./dist", entry: "server/entry.mjs" }), }); ``` The root module is the app. Its name becomes the project name on Compute: ```ts title="module.ts" import { module } from "@prisma/composer"; import web from "./service.ts"; export default module("marketing-site", ({ provision }) => { provision(web); }); ``` The deploy config tells the CLI where to deploy. The `region` applies when the first deploy creates the project: ```ts title="prisma.config.ts" import { defineConfig as composer } from "@prisma/composer/config"; import { nodeBuild } from "@prisma/composer/node/control"; import { prismaCloud, prismaState } from "@prisma/composer-prisma-cloud/control"; import { definePrismaConfig } from "prisma/config"; export default definePrismaConfig({ composer: composer({ extensions: [prismaCloud({ region: "us-east-1" }), nodeBuild()], state: prismaState(), }), }); ``` Composer writes local state to `.alchemy/` and `.prisma-composer/`. Add both to `.gitignore`: ```bash title=".gitignore" /.alchemy /.prisma-composer ``` ## 5. Run it locally [#5-run-it-locally] Run the built site the way Compute will. No account is needed: #### bun ```bash bun run build bunx prisma dev module.ts ``` #### pnpm ```bash pnpm run build pnpm prisma dev module.ts ``` #### yarn ```bash yarn build yarn prisma dev module.ts ``` #### npm ```bash npm run build npx prisma dev module.ts ``` ```text no-copy dev: ready web: http://localhost:3000 ``` `dev` keeps running. From a second terminal in the same directory, check each route. `prisma dev url web` prints the URL of the `web` service, whichever port it got: ```bash curl -s -o /dev/null -w "%{http_code}\n" "$(npx prisma dev url web)/pricing" ``` ```text no-copy 200 ``` Composer hands the server its port, so you do not set `PORT` or `HOST` yourself. Stop `dev` with `Ctrl+C`. ## 6. Deploy to Prisma Compute [#6-deploy-to-prisma-compute] Sign in once. It opens your browser: #### bun ```bash bunx prisma auth login ``` #### pnpm ```bash pnpm prisma auth login ``` #### yarn ```bash yarn prisma auth login ``` #### npm ```bash npx prisma auth login ``` Then build and deploy: #### bun ```bash bun run build bunx prisma deploy module.ts ``` #### pnpm ```bash pnpm run build pnpm prisma deploy module.ts ``` #### yarn ```bash yarn build yarn prisma deploy module.ts ``` #### npm ```bash npm run build npx prisma deploy module.ts ``` ```text no-copy Plan: 4 to create, 1 tasks ... marketing-site └─ web compute-service cps_abc123 https://abc123.ewr.prisma.build ... Done: 5 succeeded (16.8s) ``` The deploy creates a project named `marketing-site` in your workspace and prints the live URL. If a project with that name already exists and its deploy state cannot be verified, the deploy stops with `HostedStateBootstrapError`; rename the module in `module.ts` or pass `--name `. Verify the live site: ```bash curl -s https://abc123.ewr.prisma.build/ | grep -o '

.*

' ``` ```text no-copy

Ship faster with Acme

``` ## 7. Ship a change [#7-ship-a-change] Edit a page, then build and deploy again: ```astro title="src/pages/index.astro"

Ship faster with Acme

// [!code --]

Ship faster with Acme, now on Prisma Compute

// [!code ++] ``` #### bun ```bash bun run build bunx prisma deploy module.ts ``` #### pnpm ```bash pnpm run build pnpm prisma deploy module.ts ``` #### yarn ```bash yarn build yarn prisma deploy module.ts ``` #### npm ```bash npm run build npx prisma deploy module.ts ``` ```text no-copy Plan: 2 to update, 1 to replace, 1 tasks ... marketing-site └─ web compute-service cps_abc123 https://abc123.ewr.prisma.build ``` The deploy reuses the project and keeps the URL. Fetch it again and you get the new heading. To deploy on every push instead of from your terminal, see [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push). ## Common gotchas [#common-gotchas] **`ASSEMBLE.BUILD_FAILED`: no built entry at `dist/server/entry.mjs`.** Either the Node adapter is missing, so the build only wrote HTML files, or you ran `dev` or `deploy` before `npm run build`. Add the adapter (step 3), build, and run the command again. Composer never runs your build for you, so always build before `deploy`; otherwise it ships whatever is already in `dist/`. **Setting `output: "server"`.** You don't need it for a marketing site. It renders every page per request instead of serving prebuilt HTML. Leave `output` at its static default, and opt a single page into request-time rendering with `export const prerender = false` when you need one. ## Use with your agent [#use-with-your-agent] To delegate this guide to your coding agent, copy the prompt below and hand it over: ```text Build a static Astro marketing site and deploy it to Prisma Compute. Follow https://www.prisma.io/docs/guides/compute/astro-marketing-site.md. 1. Scaffold: `npm create astro@latest -- marketing-site --template minimal --install --no-git --yes`, then work in `marketing-site`. 2. Build the pages I describe (default: a shared layout in `src/layouts/Base.astro` plus home, pricing, and about pages). Keep every page static; do not set `output: "server"`. 3. Run `npx astro add node --yes` so `astro.config.mjs` uses `node({ mode: "standalone" })`. Run `npm run build` and confirm `dist/server/entry.mjs` exists. 4. Install `@prisma/composer` and `@prisma/composer-prisma-cloud`, and `prisma` as a dev dependency. Add `service.ts`, `module.ts`, and `prisma.config.ts` exactly as the guide shows, and add `/.alchemy` and `/.prisma-composer` to `.gitignore`. 5. Run `npx prisma dev module.ts --detach`, curl each page under `$(npx prisma dev url web)` and confirm a 200, then run `npx prisma dev stop`. 6. Deploy: check `npx prisma auth whoami`; if I am not signed in, stop and ask me to run `npx prisma auth login`. Then run `npm run build` followed by `npx prisma deploy module.ts`, and curl the printed URL to confirm the home page renders. ``` Install the [Prisma Compute agent skill](https://www.prisma.io/docs/ai/tools/skills) so your agent knows the deploy workflow: #### bun ```bash bunx skills add prisma/skills --skill prisma-compute ``` #### pnpm ```bash pnpm dlx skills add prisma/skills --skill prisma-compute ``` #### yarn ```bash yarn dlx skills add prisma/skills --skill prisma-compute ``` #### npm ```bash npx skills add prisma/skills --skill prisma-compute ``` Prompts that map to this guide: * "Add a blog to my Astro marketing site and redeploy it to Prisma Compute." * "Put my Prisma Compute site on a custom domain." * "Set up deploy on push for this site." ## Next steps [#next-steps] * [Add a custom domain](https://www.prisma.io/docs/compute/domains) to the deployed site. * [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push) so every Git push deploys, with a preview for every branch. * [Use Prisma ORM with Astro](https://www.prisma.io/docs/guides/frameworks/astro) when the site needs data, like a waitlist form backed by Prisma Postgres.