· astro / astro-6 / review

Astro 6: Có Gì Mới, Điều Gì Hỏng và Nên Nâng Cấp Không?

Astro 6 đáng nâng cấp. Node 22 là yêu cầu mới, legacy Content Collections đã bị loại bỏ, Zod 4 âm thầm phá vỡ schema. Đây là chính xác những gì sẽ hỏng.

Bởi

2.017 từ · 11 phút đọc

Astro 6 ra mắt với dev server được thiết kế lại, Fonts API tích hợp sẵn, và Live Content Collections chính thức ổn định. Cái giá phải trả nằm ở những ràng buộc bị loại bỏ: Node 22 là phiên bản tối thiểu, toàn bộ legacy Content Collections API đã biến mất, và Zod 4 sẽ âm thầm phá vỡ các schema dựa vào type coercion. Nếu bạn đang chạy Astro 4 hoặc 5, việc nâng cấp có thể xứng đáng — nhưng nên biết trước mình đang bước vào cái gì.

Ai nên đọc bài này

Các developer đang vận hành site Astro 4 hoặc 5 và muốn biết liệu có nên nâng cấp ngay hay chờ thêm. Đây không phải bài giải thích “Astro là gì” — bài này giả sử bạn đã quen với công cụ này.

Môi trường kiểm thử

Astro 6.3.1 chạy trên Node 24.12.0 với pnpm 10.33.0, trên một content-collections site (toolchew.com — 732 trang, Markdown-first, Tailwind 4 qua Vite plugin, không có UI framework islands). Các con số build bên dưới lấy từ ba lần chạy warm sau khi bỏ đi một lần cold-start. Phần cứng: Apple M-series MacBook.

Tính năng mới thực sự có ích

Dev server ngang hàng với production

Thay đổi đáng chú ý nhất trong Astro 6 lại vô hình trong quá trình phát triển — cho đến khi nó cứu bạn khỏi một bug chỉ xuất hiện ở production. astro dev được thiết kế lại chạy Environment API của Vite bên dưới, nghĩa là dev server thực thi trong cùng runtime với production. Cả lớp bug kiểu “chạy được trên dev” thu hẹp đáng kể.

Điều này có tác động lớn nhất nếu bạn deploy lên Cloudflare Workers. Adapter @astrojs/cloudflare được xây dựng lại giờ chạy workerd (runtime open-source của Cloudflare) ở mọi giai đoạn: dev, preview, và build. Bạn có Durable Objects, KV Namespaces, R2 Storage, và Analytics Engine bindings thực sự trong astro dev — không polyfill, không bất ngờ lúc deploy. Để xem hướng dẫn thiết lập chi tiết, xem Cách Deploy Astro lên Cloudflare.

Fonts API tích hợp sẵn

Tự host font giờ là tính năng cốt lõi. Astro 6 tự xử lý việc tải file, cache, tạo fallback, và inject <link rel="preload">. Các provider bao gồm Google Fonts, Fontsource, Bunny, và các npm package cài cục bộ.

// astro.config.mjs
export default defineConfig({
  fonts: [{
    provider: 'google',
    name: 'Inter',
    styles: ['normal'],
    weights: [400, 700]
  }]
})

Nếu bạn đang dùng experimental.fonts: true trong Astro 5, hãy xóa nó đi — tính năng này đã ổn định và flag cũ sẽ gây lỗi config.

Content Security Policy API

CSP giờ ổn định — hoạt động trên cả static và SSR mode, tất cả adapter chính thức. Các thẻ <script><style> inline được tự động hash.

export default defineConfig({
  security: { csp: true }
})

Xóa mọi flag experimental.csp khỏi config hiện tại.

Live Content Collections

Ổn định từ Astro 6 (trước đây là experimental trong 5.10). getLiveCollection()getLiveEntry() lấy nội dung tại thời điểm request, để cập nhật từ CMS hiện ra mà không cần rebuild. Hữu ích cho inventory, nội dung có giới hạn truy cập, hoặc bất kỳ nguồn dữ liệu nào thay đổi nhanh hơn chu kỳ deploy. Với site chủ yếu tĩnh, tính năng này chỉ thêm latency mà không mang lại lợi ích — cứ dùng build-time collections là đủ.

Thử nghiệm: queued rendering

Tuyên bố chính thức là “render nhanh hơn tới 2×”. Thuật toán mới thay thế renderer đệ quy bằng một depth-first queue và tái sử dụng component instances giữa các trang qua node pooling (mặc định 1.000 nodes).

export default defineConfig({
  experimental: {
    queuedRendering: { enabled: true }
  }
})

Chúng tôi chạy astro build trên toolchew.com (732 trang, content collections, không có islands) với và không có flag này trên Astro 6.3.1:

Lần chạyKhông có queued renderingCó queued rendering
13.21s6.81s (*)
22.99s3.03s
33.07s3.00s
43.08s3.03s
Trung vị (lần 2–4)3.07s3.03s

(*) Lần 1 bỏ qua — cold-start variance ảnh hưởng đến cả hai điều kiện như nhau.

Kết luận: không có cải thiện đáng kể trên workload này. Tuyên bố “2×” có thể đúng với các app nhiều component có cây .astro lồng sâu. Trên site Markdown-first, điểm nghẽn là disk I/O và Vite transform, không phải thuật toán render. Bật tính năng này nếu bạn có nhiều component lồng nhau; bỏ qua nếu site chủ yếu là Markdown.

Thay đổi có thể gây lỗi trong Astro 6

Node 22 là phiên bản tối thiểu mới

Node 18 và Node 20 không còn được hỗ trợ. Phiên bản tối thiểu là Node 22.12.0. Kiểm tra các deployment target của bạn trước khi nâng cấp.

Netlify và Vercel đều hỗ trợ Node 22 từ đầu năm 2026. Cloudflare Pages cũng hỗ trợ. Shared hosting và một số CI template cũ có thể vẫn mặc định Node 18 — hãy cập nhật chúng trước, nếu không quá trình nâng cấp sẽ dừng lại ở bước deploy.

Các API bị loại bỏ

Danh sách đầy đủ có trong hướng dẫn migration v6 chính thức, nhưng đây là những cái có khả năng cao sẽ ảnh hưởng đến bạn:

Đã loại bỏThay thế
<ViewTransitions /><ClientRouter /> từ astro:transitions
Astro.glob()import.meta.glob() hoặc getCollection()
Flag legacy.collectionsContent Layer API với loaders
src/content/config.tssrc/content.config.ts
serializeActionResult()getActionContext()
astro.config.cjs / .ctsDùng .mjs, .js, .ts, hoặc .mts

Nếu bạn đã trì hoãn việc migration Astro.glob() từ Astro 5, giờ không còn cách nào trì hoãn thêm. Chạy astro check trước khi nâng cấp — lệnh này sẽ phát hiện mọi API đã bị loại bỏ trong project của bạn.

Migration lên Zod 4

Astro 6 dùng Zod 4. Các thay đổi API không nhỏ và một số sẽ gây lỗi âm thầm.

// Error messages
{ message: "bad input" }   // Zod 3 — bị bỏ qua ở runtime
{ error: "bad input" }     // Zod 4 — đúng

// Defaults với transforms
views: z.string().transform(Number).default("0")  // Zod 3 — lỗi âm thầm
views: z.string().transform(Number).default(0)    // Zod 4 — đúng

// Import path
import { z } from 'astro:schema'  // deprecated
import { z } from 'astro/zod'     // đúng

Có một community codemod tại github.com/nicoespeon/zod-v3-to-v4. Chạy nó trước khi nâng cấp, không phải sau khi bạn đã mắc kẹt với schema lỗi bí ẩn.

Thay đổi mặc định trong i18n routing

i18n.routing.redirectToDefaultLocale đổi giá trị mặc định từ true thành false. Nếu site bạn phụ thuộc vào tự động redirect locale, cần thêm lại tường minh:

i18n: {
  routing: {
    prefixDefaultLocale: true,
    redirectToDefaultLocale: true  // ngầm định trong v5; nay phải khai báo rõ
  }
}

Astro 6 không còn loại bỏ dấu gạch ngang cuối khỏi heading ID được tạo từ heading dạng code. Một heading như ## `<Picture />` trước đây tạo ra #picture — nay tạo ra #picture-. Mọi anchor link đến heading chứa inline code hoặc ký tự đặc biệt sẽ âm thầm hỏng sau khi nâng cấp. Hãy kiểm tra các anchor link trước khi đưa lên production.

import.meta.env luôn là string

Các biến môi trường giờ luôn được inline dưới dạng string và không bao giờ được coerce. Biến boolean env nay là "true" hoặc "false" dưới dạng string.

// v5 — hoạt động được
const enabled: boolean = import.meta.env.ENABLED

// v6 — phải coerce tường minh
const enabled = import.meta.env.ENABLED === "true"

// Biến private phải dùng process.env
const dbPassword = process.env.DB_PASSWORD

Khả năng tương thích với các integration

Tailwind 4: bỏ @astrojs/tailwind

Integration @astrojs/tailwind đã deprecated. Tailwind 4 tích hợp trực tiếp qua Vite plugin — không cần package riêng của Astro. Site toolchew đã chạy theo cách này:

import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  vite: {
    plugins: [tailwindcss()],
  },
})

Đây là toàn bộ cấu hình Tailwind. Không cần tailwind.config.js, không cần @astrojs/tailwind trong mảng integrations.

MDX: nâng lên 5.1.0+ trước khi chạy npm install

@astrojs/[email protected] được ship với peer dependency ghim vào dải alpha của Astro 6 (^6.0.0-alpha.0). Semver của npm loại trừ nghiêm ngặt các bản stable khỏi dải pre-release, nên một lần npm install mới trên project Astro 6.0.4 với MDX 5.0.0 sẽ báo lỗi:

npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! Found: [email protected]
npm ERR! Could not resolve dependency:
npm ERR! peer astro@"^6.0.0-alpha.0" from @astrojs/[email protected]

Cái này dễ nhầm thành bug của Astro 6. Thực ra đây là vấn đề packaging của MDX, không phải Astro. Cách sửa là nâng MDX lên @astrojs/[email protected]+ trước khi chạy install. Nếu vì lý do nào đó bạn vẫn phải dùng 5.0.0, hãy thêm npm override:

"overrides": { "@astrojs/mdx": { "astro": "^6.0.0" } }

Xem GitHub issue #15924 để biết đầy đủ câu chuyện.

React, Svelte, Vue

Không có breaking change nào được ghi nhận trong các UI framework integration. Các integration này tiếp nhận dev server thống nhất một cách âm thầm — component giờ render trong cùng runtime context với production khi chạy astro dev.

Lưu ý bảo mật

Các phiên bản trước 6.1.6 có lỗ hổng XSS mức độ trung bình qua sanitization </script> chưa đầy đủ trong define:vars. Bản stable hiện tại (6.3.1 tại thời điểm viết) đã an toàn. Không chạy bất kỳ thứ gì dưới 6.1.6 trên production.

Kết luận

Nâng cấp ngay nếu:

  • Bạn deploy lên Cloudflare Workers — dev runtime thống nhất với workerd là lý do thuyết phục nhất để chuyển.
  • Bạn đang bắt đầu dự án mới — không có gánh nặng migration, và bạn có CSP cùng Fonts API ngay từ đầu.
  • Site của bạn là blog + content collections với logic schema tối giản — việc migration mất khoảng 1–3 tiếng, phần lớn là kiểm tra Node 22 trên deployment target.

Nếu bạn vẫn đang cân nhắc giữa Astro và Next.js, xem so sánh Next.js vs Astro để nắm rõ sự khác biệt ở cấp độ framework.

Chờ thêm nếu:

  • Bạn có site nhiều MDX đang dùng đúng @astrojs/[email protected] — nâng MDX lên trước, xác nhận 5.1.0+ cài được, rồi mới migrate Astro.
  • Bạn có Zod schema tùy biến nhiều — chạy codemod trên một branch riêng và sửa hết lỗi trước khi đụng vào phiên bản Astro.
  • Bạn có i18n routing và chưa kiểm tra thay đổi mặc định redirectToDefaultLocale — 10 phút bây giờ đổi lấy tránh một lỗi redirect âm thầm trên production.

Bỏ qua experimental.queuedRendering trừ khi bạn đã đo được bottleneck render cụ thể trên project nhiều component. Với content-collection site, overhead không đáng kể.

Lưu ý thêm

Các con số build bên trên đến từ một máy duy nhất (Apple M-series) chạy Node 24 trên site nhiều nội dung không có UI framework islands. Kết quả queued rendering có thể khác trên các app nhiều component — tuyên bố chính thức dựa trên app có cây component sâu, không phải Markdown pipeline. Hãy benchmark project của chính bạn trước khi đưa ra quyết định dựa vào con số hiệu năng này.

Chúng tôi chưa thử nghiệm Rust compiler (experimental.rustCompiler) — tính năng này vẫn còn sớm và team không khuyến nghị dùng cho production.

Tài liệu tham khảo