Deploy to Node and Deno
Purpose and Scope
Astro deployments fall into two broad categories: static output, where every route is built ahead of time, and on-demand rendering, where a runtime server handles requests. Node and Deno are both JavaScript runtimes that can run on-demand Astro output, but they occupy different operational spaces. Node is the conventional server runtime for standalone processes and middleware-style hosting. Deno can run a built server entry locally or on Deno Deploy, including edge-oriented JavaScript, TypeScript, and WebAssembly environments described by Astro’s deployment guide.
For Node, the official adapter is @astrojs/node. The integration guide describes it as the adapter for deploying on-demand rendered routes and features to Node targets, including server islands, actions, and sessions. For Deno, the official deployment guide describes both static deployment and on-demand rendering through @deno/astro-adapter. Static sites do not need an adapter in either family; the adapter becomes important when a route, page option, action, session, or server-side feature needs runtime execution instead of prebuilt HTML.
Sources: .github/workflows/build-sandbox-image.yml, .github/workflows/examples-deploy.yml, .changeset/sharp-bags-build.md
Relevant Source Files
.github/workflows/build-sandbox-image.yml— Shows a repository-maintained container image build and publish workflow using Docker Buildx, GitHub Container Registry, immutable action pins, and cache configuration. This is useful deployment evidence for runtime-server packaging patterns, even though it builds the repository sandbox image rather than an application adapter output..github/workflows/examples-deploy.yml— Shows how changes underexamples/**trigger a deployment-side rebuild through a Netlify build hook. It is a concrete CI signal for how Astro example deployments can be refreshed from repository changes..changeset/sharp-bags-build.md— Records a deployment/runtime correctness fix for prerendering failures in a workerd environment. It demonstrates that deployment adapters must surface rendering errors duringastro buildinstead of producing silently truncated HTML.configs/tsconfig.build.json— Defines the shared TypeScript package build shape: source undersrc, emitted output underdist, and build metadata underdist/._cache/ts_build/build.tsbuildinfo.packages/astro-prism/tsconfig.build.json— Extends the shared build configuration and addsvirtual.d.ts, illustrating how packages that expose virtual types can customize the standard package build input set.packages/astro-rss/tsconfig.build.json— Extends the shared build configuration without extra overrides, illustrating the default package build contract for published Astro packages.
Runtime Choices: Static, Node, and Deno
Start a deployment decision by asking whether the project needs a server at request time. A default Astro project can be deployed as static files, and the official Deno guide explicitly states that no extra configuration is required for a static Astro site. The same principle applies to Node: if Astro is only acting as a static site builder, the Node integration guide says you do not need an adapter. This matters because a static deployment has fewer moving parts: the host serves generated files, and there is no application process to boot, monitor, or scale.
When the project uses on-demand rendering, the runtime becomes part of the architecture. In Node, install the adapter with npx astro add node, or manually add @astrojs/node and configure it in astro.config.mjs. The official Node example uses adapter: node({ mode: 'standalone' }), which produces an output suitable for a Node process. The same guide also describes middleware mode for integrating with another HTTP server such as Express, so the deployment pattern is not only “run Astro” but also “embed Astro in a broader Node service” when needed.
For Deno, the official guide separates the same static and on-demand concerns. To enable on-demand rendering for Deno Deploy or a self-hosted Deno server, install @deno/astro-adapter, import it in astro.config.mjs, set output: 'server', and configure adapter: deno(). The guide’s local production preview command runs the built server entry with Deno permissions, for example deno run --allow-net --allow-read --allow-env ./dist/server/entry.mjs. Those permissions are part of the deployment contract: the runtime must be allowed to listen, read build assets, and access environment variables.
Configuration and Build Flow
A Node-oriented on-demand project typically has a configuration file shaped like this: define the Astro config, import the Node adapter, and pass an adapter option that matches the target server style. In standalone mode, the built output is intended to boot as its own server. In middleware mode, Astro is part of another Node HTTP stack. Deno’s on-demand configuration is similar in intent but different in adapter and runtime command: the built server entry is launched by deno run with explicit permissions rather than by a Node process.
// astro.config.mjs
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';
export default defineConfig({
adapter: node({ mode: 'standalone' }),
});// astro.config.mjs
import { defineConfig } from 'astro/config';
import deno from '@deno/astro-adapter';
export default defineConfig({
output: 'server',
adapter: deno(),
});Inside the repository, package builds follow a shared TypeScript convention that is relevant to adapters and deployment packages even when the application deployment happens elsewhere. The shared build config roots package source at src, emits compiled output to dist, and stores TypeScript incremental state under a cache path inside dist. Individual packages such as astro-rss can inherit that contract directly, while packages such as astro-prism can extend the input set with a virtual declaration file. This keeps published packages predictable for downstream deployment workflows.
Sources: configs/tsconfig.build.json, packages/astro-prism/tsconfig.build.json, packages/astro-rss/tsconfig.build.json
CI/CD and Deployment Signals
The repository’s CI files show two deployment-adjacent patterns that are useful when designing production workflows for runtime-server targets. The sandbox workflow builds a Docker image from a known Dockerfile, logs in to GitHub Container Registry, uses Docker Buildx, and publishes both a latest tag and a content-derived hash tag. That pattern is a good model for server deployments that need reproducible container images: pin the build inputs, publish immutable tags, and use build cache only as an acceleration layer rather than as the identity of the release.
The examples deployment workflow shows a lighter model: changes under examples/** trigger a GitHub Actions job that calls a hosted build hook. Instead of building and publishing an image inside the repository workflow, it delegates the rebuild to Netlify through a secret build hook URL. For Astro apps, this pattern fits static preview sites and hosted example environments. For Node or Deno server deployments, the same event-driven idea can be reused, but the receiving platform must build and run the adapter output rather than merely publish static assets.
Sources: .github/workflows/build-sandbox-image.yml, .github/workflows/examples-deploy.yml
Runtime Correctness and Failure Surfacing
On-demand rendering changes where failures can occur. A static build can fail while prerendering, but a server-rendered deployment can also fail while streaming a response, reading an environment variable, or executing adapter-specific runtime code. The changeset about workerd prerendering is not a Node or Deno adapter note, but it captures an important deployment invariant: rendering errors must be surfaced as build failures with clear messages, not swallowed while emitting incomplete HTML. That lesson applies across runtimes because build correctness is part of deployment correctness.
When validating a Node or Deno deployment, test both the build step and the runtime entrypoint. For Node standalone output, run the generated server process the same way the host will run it and request representative pages, endpoints, actions, and sessions. For Deno output, run the documented deno run command with the required permissions and verify the built server entry can read assets and environment variables. In CI, prefer checks that fail the workflow when rendering or prerendering fails; a successful exit with truncated output should be treated as a release blocker.
Sources: .changeset/sharp-bags-build.md
Practical Deployment Checklist
Use this checklist when moving an Astro project to a Node or Deno runtime. First, decide whether the site is static or on-demand rendered. If static, build the project and deploy the generated assets to any compatible host. If on-demand, install the runtime-specific adapter, confirm astro.config.mjs matches the intended runtime, and choose whether Node should run standalone or as middleware. For Deno, ensure the production command grants network, read, and environment access to the built server entry.
Second, align CI with the deployment target. Container-based Node deployments should resemble the repository’s sandbox image workflow: build from committed inputs, publish to a registry, and tag releases predictably. Hosted preview or example sites can use a build-hook pattern like the examples workflow, where repository changes notify the deployment platform. Finally, add validation that exercises the actual runtime output, not only TypeScript compilation. Read next about server-side rendering, adapter integrations, deployment overview, actions, and sessions to understand which features require a server runtime.