Astro is a modern web framework purpose-built for content-driven websites. Its defining characteristic is zero JavaScript shipped to the client by default — a philosophy enforced by its Islands Architecture, where interactive components are explicitly opted into client-side hydration. The framework is distributed as a TypeScript monorepo with over 6,100 files, maintained by the withastro organization and built around a core package (packages/astro/) surrounded by official integrations, language tooling, and shared utilities.
This guide covers architecture, configuration, deployment, security, and internals for administrators, platform engineers, and contributors working at the framework level.
1. Architecture Overview
1.1 High-Level Request Pipeline
Astro's runtime is structured as a layered pipeline that handles both development and production requests through a common abstract base, then specializes at the edges.
CLI (yargs-parser)
│
▼
Config Resolution (Zod v4 validation)
│
▼
Vite Dev Server ───────────────────────── Build (AppPipeline)
│ │
▼ ▼
DevPipeline AppPipeline
│ │
└──────────────┬────────────────────────────── ┘
▼
RenderContext (per-request)
├── Middleware chain (sequence())
├── Actions (defineAction)
├── Sessions (driver-based)
├── Cache (provider-based)
└── Routing (file-based + redirects)
The Pipeline abstract class in packages/astro/src/core/base-pipeline.ts defines this contract. AppPipeline in packages/astro/src/core/app/pipeline.ts is the production implementation. During development, an equivalent dev pipeline is used; they share the same RenderContext instantiation and middleware sequencing logic.
Important
The
output: "hybrid"mode was removed in a prior major release. The only valid values foroutputare"static"(default) and"server". Any configuration referencing"hybrid"must be migrated before upgrading.
1.2 Class Hierarchy
Pipeline (abstract)
└── AppPipeline
BaseApp
└── App
└── NodeApp
AstroError (extends Error)
├── CompilerError
├── CSSError
├── MarkdownError
├── InternalError
└── AggregateError
AstroUserError (extends Error — separate hierarchy)
MarkdocError (extends Error)
BodySizeLimitError (extends Error)
AstroTelemetry
GlobalConfig
AstroCheck
RouteCache
NodePool
HTMLStringCache
RenderContext
NodeApp in packages/astro/src/core/app/node.ts extends App with Node.js-specific adapter helpers, including BodySizeLimitError handling for oversized request bodies.
1.3 Vite Environment Model
Astro uses Vite as its build and dev-server foundation, and defines four named Vite environments:
| Environment | When Used | Purpose |
|---|---|---|
ssr |
Build and dev | Server-side rendering of pages and endpoints |
client |
Build | Client-side JavaScript bundles shipped to browsers |
astro |
Dev only | Runnable environment for the Astro dev process itself |
prerender |
Build | Static page rendering during the production build |
These are defined in packages/astro/src/core/constants.ts alongside ASTRO_VERSION, redirect status codes, middleware symbols, and Vite environment name constants.
Note
The
astroVite environment is a development-only concept. Production builds only usessr,client, andprerender. Tooling that introspects Vite environments should handle the absence of theastroenvironment in production builds gracefully.
1.4 Monorepo Structure
The repository is a pnpm workspace managed by Turborepo:
withastro/astro/
├── packages/
│ ├── astro/ # Core framework
│ │ ├── src/
│ │ │ ├── cli/ # CLI commands (yargs-parser dispatch)
│ │ │ ├── core/ # Pipeline, config, errors, routing
│ │ │ ├── actions/ # Server actions runtime (defineAction)
│ │ │ ├── assets/ # Image optimization, fonts, SVG (50K+ chars)
│ │ │ ├── config/ # Config loading and resolution
│ │ │ ├── env/ # astro:env module
│ │ │ ├── i18n/ # Internationalization
│ │ │ ├── runtime/ # Client/server runtime, dev toolbar
│ │ │ └── types/ # Public TypeScript types
│ │ ├── components/ # Built-in components (Code, Debug)
│ │ └── test/ # Test fixtures (hundreds)
│ ├── integrations/ # Official integrations (node, vercel, cloudflare, etc.)
│ ├── language-tools/ # VS Code extension, LSP, TS plugin, astro-check
│ ├── create-astro/ # Project scaffolding CLI
│ ├── astro-rss/ # RSS feed generation
│ ├── astro-prism/ # Prism syntax highlighting
│ ├── markdown/ # Markdown processing
│ ├── telemetry/ # Anonymous usage tracking
│ ├── internal-helpers/ # Shared utilities (fs, path, etc.)
│ ├── underscore-redirects/ # _redirects file generation for Netlify/Cloudflare
│ ├── upgrade/ # Version upgrade CLI
│ └── db/ # Astro DB (CLI + core)
├── examples/ # Starter templates
├── benchmark/ # Performance benchmarks
├── scripts/ # Build/test scripts
└── .changeset/ # Changeset versioning
1.5 Key Source Modules Reference
| Module | Path | Purpose |
|---|---|---|
| CLI Entry | packages/astro/src/cli/index.ts |
Command dispatch (yargs-parser), lazy imports |
| Config Schema | packages/astro/src/core/config/schemas/base.ts |
Zod v4 schema, ASTRO_CONFIG_DEFAULTS |
| Base Pipeline | packages/astro/src/core/base-pipeline.ts |
Abstract Pipeline class — middleware, actions, sessions, cache, server islands, routing |
| App Pipeline | packages/astro/src/core/app/pipeline.ts |
Production pipeline (AppPipeline extends Pipeline) |
| App | packages/astro/src/core/app/app.ts |
App extends BaseApp — production request handler |
| NodeApp | packages/astro/src/core/app/node.ts |
NodeApp extends App — Node.js adapter helpers |
| RenderContext | packages/astro/src/core/render-context.ts |
Per-request rendering context |
| Middleware | packages/astro/src/core/middleware/ |
sequence(), noop middleware, handler types |
| Errors | packages/astro/src/core/errors/ |
All error classes |
| Error Overlay | packages/astro/src/core/errors/overlay.ts |
Dev error overlay (shadow DOM, dark/light theme) |
| Constants | packages/astro/src/core/constants.ts |
ASTRO_VERSION, redirect codes, middleware symbols |
| Vite Setup | packages/astro/src/core/create-vite.ts |
Vite config creation |
| Actions Runtime | packages/astro/src/actions/runtime/server.ts |
defineAction(), ActionError, ActionInputError |
| Image Utils | packages/astro/src/assets/utils/ |
17 files — SVG handling, image transforms, responsive images |
| Font System | packages/astro/src/assets/fonts/ |
Font optimization, format detection, CSS generation |
| Events/Telemetry | packages/astro/src/events/ |
Telemetry event tracking |
| Telemetry | packages/telemetry/src/ |
AstroTelemetry class, GlobalConfig for persistent settings |
| Language Server | packages/language-tools/language-server/src/ |
LSP for .astro files |
| Astro Check | packages/language-tools/astro-check/src/ |
CLI diagnostics tool |
| TS Plugin | packages/language-tools/ts-plugin/src/ |
TypeScript language service plugin |
| VS Code Extension | packages/language-tools/vscode/src/ |
VS Code extension entry |
| RSS | packages/astro-rss/src/ |
RSS feed generation |
| Prism | packages/astro-prism/src/ |
Prism syntax highlighting |
| Underscore Redirects | packages/underscore-redirects/src/ |
_redirects file generation for Netlify/Cloudflare |
| Internal Helpers | packages/internal-helpers/src/ |
6 files — shared utilities (fs, path, etc.) |
| Create Astro | packages/create-astro/src/ |
Project scaffolding wizard |
1.6 Islands Architecture
The Islands Architecture is the conceptual core of Astro. Each page renders as static HTML by default; interactive UI components are explicit "islands" that get hydrated on the client. Hydration is controlled via client:* directives (client:load, client:idle, client:visible, client:media, client:only). This model means:
- The baseline is zero JavaScript delivered to the browser
- Each island is independently hydrated
- Server-rendered HTML is complete before any JS loads
- Multiple UI framework renderers can coexist on a single page
Tip
Islands Architecture is most impactful on content-heavy sites. For highly interactive applications, the zero-JS-by-default model still applies, but islands may cover most of the page. Evaluate whether Astro's model fits the application's interactivity profile before committing.
1.7 Middleware and Actions Architecture
Middleware in Astro is composed via the sequence() utility, which chains middleware functions in order. Each middleware receives the request context and a next function. The middleware chain is resolved by RenderContext per request.
Server Actions, defined with defineAction() in packages/astro/src/actions/runtime/server.ts, provide a type-safe RPC layer callable from client components. Actions can throw ActionError (general) or ActionInputError (validation failure). The action body size is limited by security.actionBodySizeLimit (default 1MB).
2. System Requirements
2.1 Runtime Requirements
| Component | Minimum Version | Notes |
|---|---|---|
| Node.js | 22.12.0 | Enforced at runtime; earlier versions are unsupported |
| pnpm | 10.30.3 | Required for monorepo development; enforced via preinstall hook and only-allow |
| TypeScript | ~5.9.3 | Bundled; projects may use any compatible version |
Warning
The Node.js minimum is 22.12.0. This is enforced in the monorepo build tooling. Adapter-deployed serverless environments must also meet this requirement — Vercel, Netlify, and Cloudflare Workers all support Node.js 22, but verify the specific runtime version in your platform's settings before deploying.
2.2 Development Tooling
| Tool | Purpose |
|---|---|
Turborepo (turbo) |
Monorepo task orchestration and caching |
| Vitest | Unit and integration testing |
| Playwright | End-to-end testing (Firefox) |
| Biome | Linting and formatting (primary) |
| ESLint | Secondary linting |
| Prettier | Secondary formatting |
| Changesets | Versioning and changelog management |
| esbuild | Package bundling |
astro-scripts |
Internal build scripts |
knip |
Dead code detection |
2.3 Optional Runtime Dependencies
| Feature | Dependency | Notes |
|---|---|---|
| Image optimization | sharp |
Default image service; required for <Image> transforms in SSR/SSG |
| MDX support | @astrojs/mdx |
Official integration |
| Markdoc support | @astrojs/markdoc |
Official integration |
| SVGO optimization | Configured via experimental.svgo |
Only when flag enabled |
3. Configuration Reference
3.1 Configuration File
Astro loads configuration from astro.config.mjs (or .ts, .js, .cjs) at the project root. The schema is defined as a Zod v4 schema in packages/astro/src/core/config/schemas/base.ts with explicit defaults tracked in ASTRO_CONFIG_DEFAULTS.
A minimal configuration:
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
site: 'https://example.com',
output: 'static',
});
A server-rendered configuration with adapter:
// astro.config.mjs
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';
export default defineConfig({
output: 'server',
adapter: node({ mode: 'standalone' }),
});
3.2 Top-Level Options
| Option | Type | Default | Description |
|---|---|---|---|
root |
string |
'.' |
Project root directory |
srcDir |
string |
'./src' |
Source directory |
publicDir |
string |
'./public' |
Static assets directory |
outDir |
string |
'./dist' |
Build output directory |
cacheDir |
string |
'./node_modules/.astro' |
Cache directory |
site |
string (URL) |
— | Fully-qualified deployed site URL; used for canonical URLs and sitemaps |
base |
string |
'/' |
Base path when deploying to a subdirectory |
trailingSlash |
'always' | 'never' | 'ignore' |
'ignore' |
Trailing slash enforcement on routes |
output |
'static' | 'server' |
'static' |
Output mode; 'hybrid' was removed |
compressHTML |
boolean |
true |
Minify HTML output during build |
scopedStyleStrategy |
'where' | 'class' | 'attribute' |
'attribute' |
Strategy for scoping component styles |
adapter |
object |
— | SSR adapter (required when output: 'server') |
integrations |
array |
[] |
Integration list |
vite |
object |
{} |
Vite configuration overrides |
redirects |
Record<string, string | {status, destination}> |
{} |
URL redirect rules |
prerenderConflictBehavior |
'error' | 'warn' | 'ignore' |
'warn' |
Behavior when prerendering conflicts are detected |
3.3 Build Options (build.*)
| Option | Type | Default | Description |
|---|---|---|---|
build.format |
'file' | 'directory' | 'preserve' |
'directory' |
Output file organization format |
build.client |
string |
'./client/' |
Client-side assets output directory |
build.server |
string |
'./server/' |
Server-side output directory |
build.assets |
string |
'_astro' |
Sub-directory for generated asset files |
build.assetsPrefix |
string | {fallback: string, ...} |
— | CDN prefix for asset URLs |
build.serverEntry |
string |
'entry.mjs' |
Server entry point filename |
build.redirects |
boolean |
true |
Generate redirect files during build |
build.inlineStylesheets |
'always' | 'auto' | 'never' |
'auto' |
Control stylesheet inlining |
build.concurrency |
number (≥1) |
1 |
Number of pages to build concurrently |
Tip
Increasing
build.concurrencycan significantly reduce build time for large sites. Start with4and adjust based on available CPU cores. High values may cause memory pressure on resource-constrained build machines.
3.4 Server Options (server.*)
| Option | Type | Default | Description |
|---|---|---|---|
server.host |
string | boolean |
false |
Dev server host binding; true binds to 0.0.0.0 |
server.port |
number |
4321 |
Dev server port |
server.open |
string | boolean |
false |
Open browser on dev server start |
server.headers |
OutgoingHttpHeaders |
— | Custom HTTP headers served by dev server |
server.allowedHosts |
string[] | true |
[] |
Hostnames allowed to access the dev server |
3.5 Image Options (image.*)
| Option | Type | Default | Description |
|---|---|---|---|
image.service.entrypoint |
string |
'astro/assets/services/sharp' |
Image optimization service module |
image.service.config |
Record |
{} |
Image service configuration |
image.endpoint.route |
string |
'/_image' |
Route for the image optimization endpoint |
image.endpoint.entrypoint |
string |
— | Custom image endpoint module |
image.domains |
string[] |
[] |
Allowed external image domains |
image.remotePatterns |
array |
[] |
Allowed remote image URL patterns |
image.layout |
'constrained' | 'fixed' | 'full-width' | 'none' |
— | Default image layout |
image.objectFit |
string |
— | Default CSS object-fit for images |
image.objectPosition |
string |
— | Default CSS object-position for images |
image.breakpoints |
number[] |
— | Responsive image breakpoints |
image.responsiveStyles |
boolean |
false |
Auto-inject responsive CSS styles |
Remote image patterns support these fields:
// astro.config.mjs
export default defineConfig({
image: {
remotePatterns: [
{
protocol: 'https',
hostname: '**.example.com',
port: '',
pathname: '/images/**',
},
],
},
});
Caution
Allowing overly broad remote patterns (e.g.,
hostname: '**') effectively disables remote image restrictions. Always scoperemotePatternsto the domains you control or trust. Unrestricted patterns allow arbitrary third-party images to be proxied and processed by your image service.
3.6 Markdown Options (markdown.*)
| Option | Type | Default | Description |
|---|---|---|---|
markdown.syntaxHighlight |
{type: 'shiki'|'prism', excludeLangs?} | false |
{type: 'shiki'} |
Syntax highlighting engine |
markdown.shikiConfig.theme |
string |
(bundled default) | Shiki theme name |
markdown.shikiConfig.themes |
Record |
{} |
Multiple themes (light/dark) |
markdown.shikiConfig.langs |
array |
[] |
Additional Shiki language grammars |
markdown.shikiConfig.langAlias |
Record |
{} |
Language name aliases |
markdown.shikiConfig.wrap |
boolean | null |
— | Code block line wrapping |
markdown.shikiConfig.transformers |
array |
[] |
Shiki transformer plugins |
markdown.shikiConfig.defaultColor |
'light' | 'dark' | string | false |
— | Default color scheme for dual-theme mode |
markdown.remarkPlugins |
array |
[] |
Remark plugin list |
markdown.rehypePlugins |
array |
[] |
Rehype plugin list |
markdown.remarkRehype |
object |
(defaults) | Options passed to remark-rehype |
markdown.gfm |
boolean |
true |
GitHub Flavored Markdown support |
markdown.smartypants |
boolean | object |
(defaults) | Smart typography (quotes, dashes) |
3.7 Security Options (security.*)
| Option | Type | Default | Description |
|---|---|---|---|
security.checkOrigin |
boolean |
true |
Validate Origin header on form submissions and actions (CSRF protection) |
security.allowedDomains |
array of {hostname?, protocol?, port?} |
[] |
Domains permitted beyond same-origin |
security.actionBodySizeLimit |
number |
1048576 (1MB) |
Maximum request body size for server actions |
security.serverIslandBodySizeLimit |
number |
1048576 (1MB) |
Maximum request body size for server islands |
security.csp |
boolean | {algorithm, directives?, styleDirective?, scriptDirective?} |
false |
Content Security Policy configuration |
3.8 Internationalization Options (i18n)
The i18n block is optional. When present, defaultLocale and locales are required.
| Option | Type | Description |
|---|---|---|
i18n.defaultLocale |
string |
Default locale code (e.g., 'en') |
i18n.locales |
array of string | {path, codes} |
Supported locales |
i18n.domains |
Record<string, URL> |
Per-locale domain mapping |
i18n.fallback |
Record<string, string> |
Fallback locale chain |
i18n.routing |
'manual' | {prefixDefaultLocale?, redirectToDefaultLocale?, fallbackType?} |
Routing strategy |
// astro.config.mjs — multilingual site example
export default defineConfig({
i18n: {
defaultLocale: 'en',
locales: ['en', 'fr', { path: 'pt', codes: ['pt', 'pt-BR'] }],
routing: {
prefixDefaultLocale: false,
redirectToDefaultLocale: true,
},
fallback: {
fr: 'en',
},
},
});
3.9 Environment Variable Schema (env.*)
| Option | Type | Default | Description |
|---|---|---|---|
env.schema |
object |
{} |
Type-safe environment variable declarations |
env.validateSecrets |
boolean |
false |
Validate secret env vars at build time |
3.10 Prefetch Options (prefetch)
| Option | Type | Description |
|---|---|---|
prefetch |
boolean | {prefetchAll?, defaultStrategy?} |
Enable prefetching; true enables with defaults |
prefetch.defaultStrategy |
'tap' | 'hover' | 'viewport' | 'load' |
When to prefetch links |
3.11 Dev Toolbar Options (devToolbar.*)
| Option | Type | Default | Description |
|---|---|---|---|
devToolbar.enabled |
boolean |
true |
Show the dev toolbar during development |
devToolbar.placement |
'bottom-left' | 'bottom-center' | 'bottom-right' |
— | Toolbar screen position |
3.12 Font Options (fonts)
The fonts option accepts an array of FontFamilySchema objects for built-in font optimization. This connects to the font system in packages/astro/src/assets/fonts/, which handles format detection, CSS generation, and serving optimized font files.
3.13 Session Options (session)
The optional session block configures server-side session storage using a driver-based architecture. When using the Node.js adapter with no driver configured, filesystem sessions are auto-enabled.
3.14 Legacy Options (legacy.*)
| Option | Type | Default | Description |
|---|---|---|---|
legacy.collectionsBackwardsCompat |
boolean |
false |
Enable backwards-compatible content collections behavior |
3.15 Experimental Options (experimental.*)
These flags are subject to change or removal. Do not rely on them in production without evaluating stability.
| Option | Type | Default | Description |
|---|---|---|---|
experimental.clientPrerender |
boolean |
false |
Enable Speculation Rules API for client-side prerendering |
experimental.contentIntellisense |
boolean |
false |
Enhanced content collection IntelliSense in VS Code |
experimental.chromeDevtoolsWorkspace |
boolean |
false |
Chrome DevTools workspace integration |
experimental.svgo |
boolean | SvgoConfig |
false |
SVGO optimization for SVG assets |
experimental.cache |
CacheSchema |
— | Response caching configuration |
experimental.routeRules |
RouteRulesSchema |
— | Per-route configuration rules |
experimental.rustCompiler |
boolean |
false |
Use the Rust-based Astro compiler |
experimental.queuedRendering |
{enabled?, poolSize?, contentCache?} |
{enabled: false} |
Queued rendering via NodePool |
Note
experimental.queuedRenderinguses theNodePoolclass to manage concurrent rendering workers. ThepoolSizeoption controls parallelism.contentCacheenables theHTMLStringCachefor caching rendered HTML strings between requests.
4. Deployment & Scaling
4.1 Deployment Modes
Astro supports two fundamental output modes:
| Mode | Config | Use Case |
|---|---|---|
static |
output: 'static' |
Pre-rendered HTML; host anywhere (CDN, object storage, static host) |
server |
output: 'server' + adapter |
On-demand SSR; requires a runtime environment |
Static output produces a complete dist/ directory deployable to any CDN or static host without server infrastructure.
Server output requires an adapter that produces a deployable artifact for the target platform.
4.2 Node.js Adapter (@astrojs/node)
The Node.js adapter supports two modes, and the mode option is required — omitting it throws an AstroError.
// astro.config.mjs — standalone mode
import node from '@astrojs/node';
export default defineConfig({
output: 'server',
adapter: node({ mode: 'standalone' }),
});
// astro.config.mjs — middleware mode (Express/Fastify compatible)
import node from '@astrojs/node';
export default defineConfig({
output: 'server',
adapter: node({ mode: 'middleware' }),
});
Standalone mode: Includes a built-in HTTP server. Run the output with node ./dist/server/entry.mjs.
Middleware mode: Exports an Express/Fastify-compatible middleware function. Integrate it into an existing Node.js server.
Node Adapter Options
| Option | Type | Default | Description |
|---|---|---|---|
mode |
'standalone' | 'middleware' |
Required | Deployment mode |
bodySizeLimit |
number |
1GB | Maximum request body size |
staticHeaders |
object |
— | HTTP headers injected for static file responses |
experimentalDisableStreaming |
boolean |
— | Disable response streaming |
Node Adapter Environment Variables
| Variable | Purpose |
|---|---|
ASTRO_NODE_AUTOSTART |
Auto-start the server in standalone mode |
ASTRO_NODE_LOGGING |
Control logging verbosity |
HOST |
Override the server host |
PORT |
Override the server port |
SERVER_CERT_PATH |
Path to TLS certificate for HTTPS |
SERVER_KEY_PATH |
Path to TLS private key for HTTPS |
HTTPS is enabled automatically when both SERVER_CERT_PATH and SERVER_KEY_PATH are set.
4.3 Vercel Adapter (@astrojs/vercel)
The Vercel adapter deploys to Vercel's serverless or edge runtime.
// astro.config.mjs
import vercel from '@astrojs/vercel';
export default defineConfig({
output: 'server',
adapter: vercel(),
});
Key capabilities:
- ISR (Incremental Static Regeneration): Combine static generation with on-demand revalidation
- Skew Protection: When
VERCEL_SKEW_PROTECTION_ENABLEDis set, the adapter syncs deployment identifiers maxDuration: Configure maximum function execution time (must be a positive number)VercelBuilderclass handles the build configuration and output format expected by Vercel's build system
Vercel Environment Variables
| Variable | Purpose |
|---|---|
VERCEL_DEPLOYMENT_ID |
Vercel deployment identifier (auto-set by Vercel) |
VERCEL_SKEW_PROTECTION_ENABLED |
Enable deployment skew protection (auto-set by Vercel) |
4.4 Cloudflare Adapter (@astrojs/cloudflare)
The Cloudflare adapter targets Cloudflare Workers and Cloudflare Pages.
// astro.config.mjs
import cloudflare from '@astrojs/cloudflare';
export default defineConfig({
output: 'server',
adapter: cloudflare(),
});
Key capabilities:
- Cloudflare Workers and Pages deployment
- Durable Objects support
- Custom entry file configuration
- Image service options for Cloudflare Images
Cloudflare Environment Variables
| Variable | Purpose |
|---|---|
CLOUDFLARE_VITE_BUILD |
Signal that a Cloudflare Vite build is occurring |
Warning
Cloudflare Workers have runtime constraints that differ from Node.js. The
nodejs_compatcompatibility flag must be enabled in your Cloudflare configuration when using Node.js-compatible APIs. A known issue (#16291) affects CSS nesting in the Cloudflare dev server — test in production preview environments when CSS nesting is used.
4.5 Netlify Adapter (@astrojs/netlify)
// astro.config.mjs
import netlify from '@astrojs/netlify';
export default defineConfig({
output: 'server',
adapter: netlify(),
});
Key capabilities:
- Automatic
_redirectsfile generation viapackages/underscore-redirects/ - Netlify Functions deployment
Known limitations:
context.rewrite()is not available in the Netlify adapterAstro.urlandAstro.cookieshave compatibility considerations in certain contexts
Netlify Environment Variables
| Variable | Purpose |
|---|---|
DEPLOY_ID |
Netlify deploy identifier (auto-set by Netlify) |
NETLIFY |
Netlify environment detection flag |
NETLIFY_LOCAL |
Local Netlify dev detection |
NETLIFY_DEV |
Netlify dev server detection |
4.6 Static Deployment
For output: 'static', the build output in outDir (default ./dist) is a complete set of static files deployable to any host:
# Build for static deployment
astro build
# dist/ can be deployed to:
# - GitHub Pages
# - Netlify (static)
# - Vercel (static)
# - Cloudflare Pages (static)
# - S3 + CloudFront
# - Any nginx/Apache host
Use build.assetsPrefix to point asset URLs at a CDN:
export default defineConfig({
build: {
assetsPrefix: 'https://cdn.example.com',
},
});
4.7 Concurrency and Scaling
For high-traffic SSR deployments, horizontal scaling at the load balancer level is the primary mechanism. The adapter handles individual requests; Astro itself does not manage process pools in standard deployments.
For build-time scaling, build.concurrency controls parallel page rendering. The experimental.queuedRendering feature provides a NodePool-based worker pool for controlled concurrency within a single process, with poolSize setting the pool size and contentCache enabling HTMLStringCache for repeated content.
5. Operations
5.1 Environment Variables Reference
| Variable | Source Module | Purpose |
|---|---|---|
ASTRO_TIMER_PATH |
core/config/timer.ts |
Timer output path for build profiling |
ASTRO_NODE_AUTOSTART |
node/preview.ts |
Auto-start Node adapter server |
ASTRO_NODE_LOGGING |
node/standalone.ts |
Node adapter logging control |
HOST |
node/preview.ts |
Node adapter server host override |
PORT |
node/standalone.ts |
Node adapter server port override |
SERVER_CERT_PATH |
node/standalone.ts |
HTTPS certificate file path |
SERVER_KEY_PATH |
node/standalone.ts |
HTTPS private key file path |
VERCEL_DEPLOYMENT_ID |
vercel/index.ts |
Vercel deployment ID |
VERCEL_SKEW_PROTECTION_ENABLED |
vercel/index.ts |
Vercel skew protection activation |
DEPLOY_ID |
netlify/index.ts |
Netlify deploy ID |
NETLIFY |
netlify/index.ts |
Netlify environment detection |
NETLIFY_LOCAL |
netlify/index.ts |
Local Netlify dev detection |
NETLIFY_DEV |
netlify/index.ts |
Netlify dev server detection |
CLOUDFLARE_VITE_BUILD |
cloudflare/index.ts |
Cloudflare build flag |
NODE_ENV |
various | Runtime environment (development/production) |
CI |
scripts/cmd/test.js |
CI environment detection |
5.2 Monitoring and Health
Astro does not include built-in health check endpoints. For SSR deployments, implement health checks at the adapter layer:
- Node standalone: Add a health check route to your server configuration
- Vercel/Netlify/Cloudflare: Use platform-native health monitoring
- All platforms: Monitor the
/route or a dedicated/healthendpoint added to your Astro project
5.3 Telemetry
Astro collects anonymous usage telemetry via packages/telemetry/. The AstroTelemetry class sends anonymized events about command usage, configuration choices, and build outcomes. Persistent telemetry preferences are stored by GlobalConfig.
Telemetry can be disabled:
# Disable telemetry
astro telemetry disable
# Enable telemetry
astro telemetry enable
# Check telemetry status
astro telemetry status
No personally identifiable information is collected. The telemetry system tracks aggregate patterns to inform framework development priorities.
5.4 Dev Error Overlay
During development, errors surface through the dev error overlay defined in packages/astro/src/core/errors/overlay.ts. The overlay renders in a shadow DOM to prevent style conflicts and supports both dark and light themes. It displays:
- Error class and message
- Stack trace with source file links
- Hint for known error patterns
Errors shown in the overlay correspond to the error class hierarchy — AstroError, CompilerError, CSSError, MarkdownError, InternalError, AggregateError — with user-facing errors (AstroUserError) rendered with actionable messaging.
5.5 Cache Directory
Astro uses ./node_modules/.astro as its default cache directory (cacheDir). This cache stores compiled component artifacts, type generation outputs, and build intermediates.
To clear the cache:
rm -rf ./node_modules/.astro
Note
CI environments should cache
./node_modules/.astrobetween runs to avoid redundant compilation. Include the cache key in your CI hash along withpnpm-lock.yamlandastro.config.*to invalidate appropriately when config changes.
5.6 Logging
Astro's logging is managed per-command and surfaces to stdout/stderr. The ASTRO_NODE_LOGGING environment variable controls log verbosity for the Node adapter. Production deployments should configure platform-native log aggregation (e.g., Vercel Log Drains, Netlify Log Streams, Cloudflare Workers Logpush).
6. Performance
6.1 Build Performance
Increase build concurrency:
// astro.config.mjs
export default defineConfig({
build: {
concurrency: 4, // parallelize page rendering
},
});
Inline stylesheets aggressively:
export default defineConfig({
build: {
inlineStylesheets: 'always', // eliminates render-blocking CSS requests
},
});
Use CDN for assets:
export default defineConfig({
build: {
assetsPrefix: 'https://cdn.example.com',
},
});
Cache the Astro cache directory in CI with a key based on pnpm-lock.yaml + astro.config.*.
6.2 Image Performance
The sharp-based image service (astro/assets/services/sharp) is the default and provides the best throughput. Configuration options in image.service.config are passed directly to sharp.
Responsive images via image.responsiveStyles: true auto-inject CSS for responsive layouts. Define image.breakpoints to control the set of generated sizes:
export default defineConfig({
image: {
breakpoints: [320, 640, 768, 1024, 1280, 1920],
responsiveStyles: true,
layout: 'constrained',
},
});
For SSR deployments, image transforms are computed on-demand at /_image (configurable via image.endpoint.route). High-traffic deployments should place a CDN in front of this endpoint and cache transformed images by URL.
6.3 JavaScript Bundle Performance
Astro's Islands Architecture inherently minimizes client JavaScript. Additional practices:
- Use
client:visibleinstead ofclient:loadfor below-the-fold islands — they hydrate only when entering the viewport - Use
client:idlefor non-critical islands to defer hydration until the main thread is idle - Use
client:onlyonly when server rendering is impossible (third-party widgets, browser-only APIs) - Prefer static components for content-only sections
6.4 HTML Performance
HTML compression is on by default (compressHTML: true). The HTML minification reduces whitespace in the rendered output. For content-heavy sites with large HTML payloads, this yields measurable transfer size reductions.
build.inlineStylesheets: 'auto' (the default) inlines small stylesheets and externalizes large ones. Tune with 'always' or 'never' based on profiling.
6.5 Prefetching
Prefetching reduces perceived navigation latency for multi-page sites:
export default defineConfig({
prefetch: {
prefetchAll: true, // prefetch all internal links
defaultStrategy: 'hover', // prefetch on hover
},
});
Strategy options and their behavior:
| Strategy | Trigger |
|---|---|
tap |
Prefetch on pointer down (minimal delay) |
hover |
Prefetch when hovering over a link |
viewport |
Prefetch links as they enter the viewport |
load |
Prefetch all eligible links on page load |
Tip
'viewport'strategy is ideal for paginated content or listicles where the next page link is visible before the user clicks.'hover'balances bandwidth with responsiveness for most content sites.
6.6 Queued Rendering (Experimental)
export default defineConfig({
experimental: {
queuedRendering: {
enabled: true,
poolSize: 4,
contentCache: true,
},
},
});
When enabled, server-side rendering is handled by a NodePool of workers. contentCache: true activates HTMLStringCache to cache rendered HTML strings for repeated identical requests. This is a significant architectural change — evaluate with load testing before enabling in production.
6.7 Build Profiling
Set ASTRO_TIMER_PATH to a file path to capture build timing data:
ASTRO_TIMER_PATH=./build-timings.json astro build
The timer output can identify slow routes, modules, or integrations contributing to build time.
7. Security
7.1 CSRF Protection
Origin checking is enabled by default via security.checkOrigin: true. This validates the Origin request header on form submissions and server action calls, preventing cross-site request forgery. The validation is handled in the middleware chain during request processing.
To allow cross-origin requests from trusted domains:
export default defineConfig({
security: {
checkOrigin: true,
allowedDomains: [
{ hostname: 'trusted-partner.com', protocol: 'https' },
],
},
});
Important
Never set
security.checkOrigin: falsein production SSR deployments unless you have an alternative CSRF mitigation. The origin check is a primary defense for server actions and form handlers against cross-site forgery attacks.
7.2 Content Security Policy
CSP is supported natively via security.csp:
export default defineConfig({
security: {
csp: {
algorithm: 'sha256',
directives: {
'default-src': ["'self'"],
'img-src': ["'self'", 'data:', 'https:'],
},
scriptDirective: {
// Hashes are auto-generated for inline scripts
},
styleDirective: {
// Hashes are auto-generated for inline styles
},
},
},
});
When CSP is configured with algorithm, Astro automatically generates content hashes for inline scripts and styles, eliminating the need for 'unsafe-inline' in most cases.
7.3 Body Size Limits
Two separate body size limits protect against large payload attacks:
export default defineConfig({
security: {
actionBodySizeLimit: 1048576, // 1MB — server actions
serverIslandBodySizeLimit: 1048576, // 1MB — server islands
},
});
The Node adapter has a separate bodySizeLimit option (default 1GB) at the HTTP layer, applied before Astro's routing. When BodySizeLimitError is thrown (from NodeApp), it surfaces as a 413 Payload Too Large response.
7.4 HTTPS in Node Adapter
Configure HTTPS via environment variables:
export SERVER_CERT_PATH=/path/to/cert.pem
export SERVER_KEY_PATH=/path/to/key.pem
node ./dist/server/entry.mjs
When both variables are set, the standalone Node server binds to HTTPS automatically.
7.5 Static File Headers
The Node adapter's staticHeaders option injects HTTP headers for static file responses. Use this to add security headers to static assets without a reverse proxy:
import node from '@astrojs/node';
export default defineConfig({
output: 'server',
adapter: node({
mode: 'standalone',
staticHeaders: {
'X-Content-Type-Options': 'nosniff',
'X-Frame-Options': 'DENY',
},
}),
});
7.6 Remote Image Security
Untrusted remote images processed by the image optimization service represent an SSRF risk. Restrict allowed origins:
export default defineConfig({
image: {
domains: ['images.example.com'],
remotePatterns: [
{
protocol: 'https',
hostname: '**.trusted-cdn.com',
},
],
},
});
Any image URL not matching domains or remotePatterns is rejected by the image endpoint.
7.7 Server Island Security
Server islands — dynamic components rendered server-side within otherwise static pages — accept POST requests with component state. The security.serverIslandBodySizeLimit cap prevents oversized payloads. The origin check (security.checkOrigin) applies to server island requests.
7.8 Actions Security
Server actions defined with defineAction() are accessible via POST requests. Security layers:
- Origin validation (when
security.checkOrigin: true) - Body size capped at
security.actionBodySizeLimit - Input validation via Zod schemas (throws
ActionInputErroron schema violations) - Error handling via
ActionErrorwith explicit HTTP status codes
Caution
Actions that accept file uploads or large payloads should explicitly set
security.actionBodySizeLimitabove the default 1MB. For public-facing forms, implement rate limiting at the CDN or reverse proxy layer — Astro does not include built-in rate limiting.
8. Developer Internals
8.1 Error Class Reference
All error classes are defined in packages/astro/src/core/errors/errors.ts and share a common root through AstroError:
| Class | Extends | Use Case |
|---|---|---|
AstroError |
Error |
Base for all framework errors; carries error code, hint, location |
CompilerError |
AstroError |
Errors from the Astro compiler (.astro file parsing) |
CSSError |
AstroError |
CSS processing failures (PostCSS, scoping, nesting) |
MarkdownError |
AstroError |
Markdown/MDX processing failures |
InternalError |
AstroError |
Internal framework errors; always indicates a framework bug |
AggregateError |
AstroError |
Multiple simultaneous errors (e.g., batch build failures) |
AstroUserError |
Error |
User-facing errors with actionable messaging (separate hierarchy) |
MarkdocError |
Error |
Errors from the Markdoc integration |
BodySizeLimitError |
Error |
Request body exceeded the configured size limit |
InternalError should never be thrown in normal operation — encountering one indicates a framework bug that should be reported to the withastro/astro issue tracker.
8.2 Pipeline Internals
The Pipeline abstract class in packages/astro/src/core/base-pipeline.ts defines the contract for all request handling. Key responsibilities:
- Composing the middleware chain via
sequence() - Resolving server actions
- Managing session initialization and teardown
- Cache provider coordination
- Server island request routing
- File-based route resolution
AppPipeline (production) implements this contract for serving requests from the built artifact. During development, an equivalent dev pipeline operates against the Vite dev server's module graph.
RenderContext (packages/astro/src/core/render-context.ts) is instantiated per request and carries:
- The incoming request object
- Resolved route parameters
- Middleware-modified locals
- Session reference
- Action result state
8.3 Config Loading
Configuration loading happens in two phases:
- File discovery: Astro looks for
astro.config.mjs,astro.config.ts,astro.config.js,astro.config.cjsat the project root - Schema validation: The loaded config is validated against the Zod v4 schema in
packages/astro/src/core/config/schemas/base.ts; unknown keys emit warnings, invalid values throwAstroUserError
ASTRO_CONFIG_DEFAULTS in the schema module defines all defaults, making the effective configuration always fully resolved with no partial states.
8.4 CLI Architecture
The CLI entry point at packages/astro/src/cli/index.ts uses yargs-parser for argument parsing with lazy imports for each subcommand. Lazy imports ensure the CLI starts fast — heavy dependencies (Vite, compiler) are only loaded when their command is actually invoked.
Commands are dispatched by subcommand name. Each command module is independently imported on demand.
8.5 Asset and Image Pipeline
The image pipeline in packages/astro/src/assets/utils/ (17 files) handles:
- SVG passthrough and optional SVGO optimization
- Image format detection and conversion
- Responsive image
srcsetgeneration - Remote image URL validation against configured patterns
- Sharp-based image transforms (resize, format conversion, quality)
The font system in packages/astro/src/assets/fonts/ manages:
- Font file format detection
@font-faceCSS generation- Font serving through the dev server and build output
- Integration with the
fontsconfiguration array
8.6 Writing an Integration
Astro integrations are objects with a name and hooks property. Hooks fire at defined lifecycle points during build and dev:
// my-integration.ts
import type { AstroIntegration } from 'astro';
export function myIntegration(): AstroIntegration {
return {
name: 'my-integration',
hooks: {
'astro:config:setup': ({ config, updateConfig, addRenderer, injectRoute }) => {
// Modify config, add routes, add renderers
updateConfig({
vite: {
plugins: [myVitePlugin()],
},
});
},
'astro:config:done': ({ config }) => {
// Read the final resolved config
},
'astro:server:setup': ({ server }) => {
// Access the Vite dev server
},
'astro:build:start': () => {
// Before the build starts
},
'astro:build:done': ({ dir, routes, pages }) => {
// After the build completes
},
},
};
}
Note
Integration hooks run in the order integrations are listed in
integrations: []. When multiple integrations modify the same config value viaupdateConfig, the last write wins. Design integrations to be composable and avoid assuming exclusive ownership of any config key.
8.7 Writing a Renderer Integration
UI framework renderers (React, Vue, Svelte, Preact, Solid) are a specialized form of integration that add addRenderer() calls in the astro:config:setup hook:
'astro:config:setup': ({ addRenderer }) => {
addRenderer({
name: 'my-framework',
serverEntrypoint: 'my-framework/server', // SSR render function
clientEntrypoint: 'my-framework/client', // Client hydration
});
},
The renderer's server entrypoint exports a render function; the client entrypoint exports a hydrate function. These are called by Astro's component runtime during SSR and client hydration respectively.
8.8 Official Integrations Reference
| Integration | Package | Source | Purpose |
|---|---|---|---|
| Node adapter | @astrojs/node |
node/src/ (11 files) |
Node.js standalone and middleware deployment |
| Cloudflare adapter | @astrojs/cloudflare |
cloudflare/src/ (7 files + 9 utils) |
Cloudflare Workers/Pages deployment |
| Vercel adapter | @astrojs/vercel |
vercel/src/ (3 files + 4 lib) |
Vercel serverless/edge deployment |
| Netlify adapter | @astrojs/netlify |
netlify/src/ (6 files + 1 lib) |
Netlify deployment |
| React | @astrojs/react |
react/src/ (12 files) |
React 18 & 19 renderer |
| Vue | @astrojs/vue |
vue/src/ (6 files) |
Vue 3 renderer |
| Svelte | @astrojs/svelte |
svelte/src/ (6 files) |
Svelte 5 renderer |
| Preact | @astrojs/preact |
preact/src/ (8 files) |
Preact renderer |
| Solid.js | @astrojs/solid-js |
solid/src/ |
Solid.js renderer |
| Alpine.js | @astrojs/alpinejs |
alpinejs/src/ (1 file) |
Alpine.js integration |
| MDX | @astrojs/mdx |
mdx/src/ (11 files) |
MDX (Markdown + JSX) support |
| Markdoc | @astrojs/markdoc |
markdoc/src/ (10 files) |
Markdoc authoring format support |
| Sitemap | @astrojs/sitemap |
sitemap/src/ (7 files) |
XML sitemap generation |
| Partytown | @astrojs/partytown |
partytown/src/ (2 files) |
Third-party script offloading to Web Workers |
8.9 Telemetry Internals
AstroTelemetry in packages/telemetry/src/ tracks anonymized events from packages/astro/src/events/. GlobalConfig handles persistent storage of telemetry consent. Events fire for CLI commands, integration usage, and build completion. No source code, configuration values, or file paths are included in telemetry payloads.
8.10 RouteCache
RouteCache caches the results of route matching and resolution. It is populated during the dev server startup and cleared on file changes that affect routing. In production builds, routing is resolved at build time; the route cache is not used at runtime in static deployments.
8.11 Contributing to the Monorepo
Setup:
# Clone the repository
git clone https://github.com/withastro/astro.git
cd astro
# Install dependencies (pnpm required)
pnpm install
# Build all packages
pnpm build
Common development tasks:
# Format code (Biome + Prettier)
pnpm format
# Lint (Biome + knip + ESLint)
pnpm lint
# Run all tests
pnpm test
# Run core package tests only
pnpm test:astro
# Run integration tests
pnpm test:integrations
# Run language tools tests
pnpm test:language-tools
# Run E2E tests (Playwright, Firefox)
pnpm test:e2e
# Run smoke tests for examples
pnpm test:smoke
# Run type checking tests
pnpm test:types
Creating a changeset:
pnpm changeset
Follow the prompts to select affected packages and describe the change. Changesets are consumed during release to generate changelogs and bump version numbers.
Building a release:
pnpm run release
This runs the build pipeline and publishes packages via Changesets.
Note
The monorepo enforces pnpm 10.30.3 via a
preinstallhook usingonly-allow. Runningnpm installoryarn installwill fail with an error instructing you to use pnpm. This enforcement is intentional to ensure lockfile consistency across all contributors.
9. Integration Points
9.1 Language Tooling
Astro provides first-class language tooling for .astro files through packages/language-tools/:
| Component | Package | Description |
|---|---|---|
| Language Server | @astrojs/language-server |
LSP implementation for .astro files — powers all editor integrations |
| VS Code Extension | astro-vscode |
VS Code extension using the language server |
| TypeScript Plugin | @astrojs/ts-plugin |
TypeScript language service plugin for .astro imports in .ts files |
| Astro Check | @astrojs/check |
CLI diagnostics tool for type checking .astro files |
Using astro-check in CI:
# Install
npm install --save-dev @astrojs/check typescript
# Run type checking
astro check
astro-check exits non-zero on type errors, making it suitable for CI pipelines. It uses the language server's diagnostic engine to type-check .astro component scripts, props, and expressions.
Note
The
tsconfcklibrary used by the language tooling has been discontinued (tracked in issue #16385). Monitor upstream developments for migration guidance. If you encounter errors related to tsconfig resolution in the language server, check for updates to@astrojs/language-server.
9.2 Vite Plugin Integration
Astro wraps Vite and exposes the Vite configuration via vite: {} in astro.config. Integrations can add Vite plugins via updateConfig() in the astro:config:setup hook.
Vite plugin caveats in Astro:
- Plugins run in multiple Vite environments (
ssr,client,prerender). Useenforceandapplyoptions appropriately - The
astroVite environment is dev-only; plugins must handle its absence in production - Avoid plugins that rely on
vite.config.js— Astro generates its Vite config dynamically viapackages/astro/src/core/create-vite.ts
9.3 RSS Feed Generation
@astrojs/rss in packages/astro-rss/ provides a utility for generating RSS feeds from Astro endpoints:
// src/pages/rss.xml.ts
import rss from '@astrojs/rss';
import { getCollection } from 'astro:content';
export async function GET(context) {
const posts = await getCollection('blog');
return rss({
title: 'My Blog',
description: 'My blog description',
site: context.site,
items: posts.map((post) => ({
title: post.data.title,
pubDate: post.data.date,
link: `/blog/${post.slug}/`,
})),
});
}
9.4 Sitemap Generation
@astrojs/sitemap in packages/integrations/sitemap/ generates sitemap-index.xml and per-page sitemaps during build:
import sitemap from '@astrojs/sitemap';
export default defineConfig({
site: 'https://example.com',
integrations: [sitemap()],
});
The site option is required for sitemap generation — without it, the integration cannot construct absolute URLs.
9.5 Underscore Redirects
packages/underscore-redirects/ generates _redirects files in the Netlify format, which Cloudflare Pages also supports. This package is used internally by the Netlify and Cloudflare adapters to translate Astro's redirects configuration into platform-native redirect rules.
9.6 Partytown Integration
@astrojs/partytown offloads third-party scripts (analytics, tag managers) to Web Workers using the Partytown library. This prevents third-party scripts from blocking the main thread:
import partytown from '@astrojs/partytown';
export default defineConfig({
integrations: [
partytown({
// Forward dataLayer.push calls from the worker to the main thread
config: { forward: ['dataLayer.push'] },
}),
],
});
9.7 Astro DB
packages/db/ provides Astro DB — a local and cloud-connected SQLite database layer. The DB package includes a substantial CLI (20K+ chars) and core runtime (27K+ chars). It integrates with Astro's content pipeline and provides typed table access.
9.8 Create Astro Scaffolding
packages/create-astro/ provides the project scaffolding wizard invoked via:
npm create astro@latest
The wizard guides through template selection, TypeScript preferences, and dependency installation. Templates are sourced from examples/ in the monorepo.
9.9 Prism Integration
packages/astro-prism/ provides a Prism-based syntax highlighting component. This predates Astro's Shiki integration (now the default). It remains for projects that prefer Prism's smaller bundle footprint or need Prism-specific language grammars.
To use Prism highlighting instead of Shiki:
export default defineConfig({
markdown: {
syntaxHighlight: {
type: 'prism',
excludeLangs: [],
},
},
});
10. Troubleshooting
10.1 output: 'hybrid' Configuration Error
Problem: Build fails with an error about invalid output value.
Cause: The hybrid output mode was removed. Configuration files from earlier Astro versions may still reference it.
Fix: Change output: 'hybrid' to output: 'server' in astro.config.*. All pages prerender by default in server mode; add export const prerender = false to pages that need on-demand rendering.
10.2 Node Adapter Mode Missing
Problem: AstroError thrown during build: mode is required.
Cause: @astrojs/node requires the mode option ('standalone' or 'middleware').
Fix:
adapter: node({ mode: 'standalone' }) // or 'middleware'
10.3 Dev Server Asset Errors (TypeError in assets/internal.js)
Problem: TypeError in assets/internal.js during development (issue #16309).
Cause: Usually caused by a version mismatch between astro and an integration, or a corrupted .astro cache.
Fix:
- Clear the cache:
rm -rf ./node_modules/.astro - Ensure all
@astrojs/*packages are on compatible versions - Restart the dev server
10.4 Vue Scoped Styles Lost After Navigation
Problem: Vue component scoped styles disappear after <ClientRouter> (View Transitions) navigation (issue #16334).
Cause: Known issue with how Vue's scoped style injection interacts with ClientRouter's page replacement.
Fix: Monitor the issue tracker for a patch. As a workaround, use global CSS or CSS Modules for styles that must persist across view transitions.
10.5 Components Not Rendered on Page Refresh in Dev
Problem: Page shows missing components after hard refresh in the dev server (issue #15925).
Cause: Module graph inconsistency in the dev environment.
Fix: Stop and restart the dev server. If the issue recurs, clear ./node_modules/.astro and restart.
10.6 CSS Missing with export const partial = true
Problem: CSS not injected when a page exports partial = true (issue #16296).
Cause: Partial pages bypass the normal HTML shell rendering, which includes CSS injection.
Fix: Manually include the CSS link in the partial's template, or inject styles via a shared stylesheet referenced by the parent page.
10.7 Cloudflare Dev Server CSS Nesting Issue
Problem: CSS nesting syntax causes errors in the Cloudflare adapter's local dev server (issue #16291).
Cause: The Cloudflare Workers runtime's CSS parser in the dev simulator does not support CSS nesting the same way as production.
Fix: Test CSS nesting in a Cloudflare Pages preview deployment rather than local dev. Use PostCSS with the postcss-nesting plugin as a compilation step to flatten nesting before it reaches the runtime.
10.8 UnoCSS @apply Incompatibility
Problem: UnoCSS @apply directives cause build errors or unexpected output (issue #16373).
Cause: Ordering conflict between UnoCSS's processing and Astro's CSS pipeline.
Fix: Configure UnoCSS's Vite plugin to run before Astro's CSS processing by adjusting plugin order in vite.plugins. Alternatively, avoid @apply and use UnoCSS's utility classes directly.
10.9 tsconfck Discontinuation
Problem: Language server errors related to tsconfig.json resolution (issue #16385).
Cause: The tsconfck library used by @astrojs/language-server has been discontinued.
Fix: Upgrade to the latest @astrojs/language-server version. The Astro team is tracking the migration away from tsconfck.
10.10 HTTPS Not Starting in Node Standalone
Problem: Node standalone server starts on HTTP despite setting cert/key paths.
Cause: Both SERVER_CERT_PATH and SERVER_KEY_PATH must be set simultaneously. Setting only one is ignored.
Fix: Verify both environment variables are exported before starting the server:
export SERVER_CERT_PATH=/path/to/cert.pem
export SERVER_KEY_PATH=/path/to/key.pem
node ./dist/server/entry.mjs
10.11 Image Optimization Failing in SSR
Problem: <Image> component throws errors during SSR.
Cause: The sharp package requires native binaries. Platform-specific builds (e.g., building on macOS, deploying to Linux) may have incompatible binaries.
Fix: Run npm rebuild sharp in the deployment environment, or configure the deployment platform to rebuild native modules. Alternatively, use a custom image service with image.service.entrypoint.
10.12 BodySizeLimitError on Large File Uploads
Problem: 413 errors when uploading files via server actions or server islands.
Cause: Default body size limits are 1MB for actions and server islands.
Fix: Increase the limits in security config:
export default defineConfig({
security: {
actionBodySizeLimit: 10 * 1024 * 1024, // 10MB
},
});
For very large files, consider pre-signed upload URLs directly to object storage instead of routing through Astro.
10.13 pnpm Version Mismatch in Monorepo
Problem: pnpm install fails with "This project requires pnpm X.Y.Z".
Cause: The monorepo enforces pnpm 10.30.3 via only-allow.
Fix: Install the correct pnpm version:
npm install -g pnpm@10.30.3
10.14 Build Failing Due to Missing site Config
Problem: Sitemap generation, canonical URLs, or RSS feeds produce incorrect output.
Cause: The site configuration option is not set.
Fix: Add site to astro.config.*:
export default defineConfig({
site: 'https://your-domain.com',
});
10.15 Prerender Conflicts
Problem: Build warnings or errors about prerender conflicts.
Cause: Two configurations are producing conflicting prerender decisions for the same route.
Fix: Set prerenderConflictBehavior: 'error' during development to catch conflicts early, then resolve by making prerender decisions explicit:
export default defineConfig({
prerenderConflictBehavior: 'error',
});
Quick Reference
Configuration Defaults Summary
| Config Key | Default |
|---|---|
output |
'static' |
base |
'/' |
trailingSlash |
'ignore' |
compressHTML |
true |
scopedStyleStrategy |
'attribute' |
build.format |
'directory' |
build.assets |
'_astro' |
build.serverEntry |
'entry.mjs' |
build.inlineStylesheets |
'auto' |
build.concurrency |
1 |
server.port |
4321 |
server.host |
false |
image.service.entrypoint |
'astro/assets/services/sharp' |
image.endpoint.route |
'/_image' |
image.responsiveStyles |
false |
markdown.syntaxHighlight.type |
'shiki' |
markdown.gfm |
true |
security.checkOrigin |
true |
security.actionBodySizeLimit |
1048576 (1MB) |
security.serverIslandBodySizeLimit |
1048576 (1MB) |
security.csp |
false |
devToolbar.enabled |
true |
legacy.collectionsBackwardsCompat |
false |
env.validateSecrets |
false |
experimental.clientPrerender |
false |
experimental.rustCompiler |
false |
experimental.queuedRendering.enabled |
false |
Adapter Compatibility Matrix
| Feature | Node | Vercel | Cloudflare | Netlify | Static |
|---|---|---|---|---|---|
| SSR | Yes | Yes | Yes | Yes | No |
| Server Actions | Yes | Yes | Yes | Yes | No |
| Server Islands | Yes | Yes | Yes | Yes | No |
| Sessions (auto) | Yes (filesystem) | — | — | — | No |
| ISR | — | Yes | — | — | — |
| HTTPS built-in | Yes | Platform | Platform | Platform | N/A |
context.rewrite |
Yes | Yes | Yes | No | N/A |
Vite Environments Reference
| Environment | Build | Dev | Purpose |
|---|---|---|---|
ssr |
Yes | Yes | Server-side rendering |
client |
Yes | No | Client bundles |
astro |
No | Yes | Dev process runtime |
prerender |
Yes | No | Static page generation |