· deno / fresh / astro

Deno Fresh vs Astro — framework nào chiến thắng năm 2026?

Astro là lựa chọn an toàn cho hầu hết các trang năm 2026. Fresh 2.x thắng cold-start edge nếu đội bạn dùng Deno — hệ sinh thái non trẻ là cái giá phải trả.

Bởi

2.370 từ · 12 phút đọc

Astro là lựa chọn ít rủi ro hơn cho hầu hết các trang nặng nội dung trong năm 2026. Sự sâu rộng của hệ sinh thái, tích hợp CMS, và khả năng tạo trang tĩnh đã được kiểm chứng trong production đều khiến nó trở thành lựa chọn mặc định hiển nhiên. Fresh 2.x chiến thắng nếu đội của bạn đã quen làm việc với Deno và độ trễ khởi động lạnh ở edge là yêu cầu bắt buộc — cải tiến 9–12× trong Fresh 2.3.3 là có thực, nhưng bạn sẽ phải trả giá bằng sự non trẻ của hệ sinh thái.

Dành cho ai

Các developer đang lựa chọn giữa hai framework theo kiến trúc island cho một trang nặng nội dung triển khai lên edge. Nếu bạn đã quyết định dùng stack Node.js, bài so sánh này không dành cho bạn — giá trị của Fresh gần như hoàn toàn gắn với runtime Deno. Nếu bạn đang xây dựng trang tài liệu hoặc blog chạy CMS mà không cần runtime, hãy xem Astro vs Eleventy thay thế.

Những gì chúng tôi đã thử nghiệm

Deno Fresh 2.3.3 (phát hành ngày 2026-04-28 — bản build ổn định đầu tiên sau khi quá trình chuyển đổi 2.x hoàn tất vào 2025-09-09) so với Astro 6.3.1 (tháng 5 năm 2026). Workload thử nghiệm: một trang nội dung 5 trang với một route động — một trang danh sách sản phẩm được server-render từ một mock API. Triển khai lên Cloudflare Workers để đo hiệu suất SSR. Các chỉ số cold-start của Fresh do đội Deno tự công bố (thông báo Fresh 2.0 beta). Không có benchmark độc lập từ bên thứ ba nào so sánh hai công cụ này được công bố công khai tính đến tháng 5 năm 2026 — phương pháp đo được ghi chú theo từng nhận định.

Kiến trúc island

Cả hai framework đều không gửi JavaScript xuống trình duyệt theo mặc định. Đó là điểm duy nhất hai bên giống nhau.

Fresh dùng convention thư mục islands/. Bất kỳ component nào đặt vào đó sẽ được hydrate; mọi thứ còn lại là HTML được server-render. Preact là thư viện UI tích hợp sẵn. Từ Fresh 2.3+ trở đi, các trang không có island sẽ không gửi bất kỳ JavaScript nào xuống — không có cả runtime shim. Nếu bạn đang xây dựng trang tài liệu hoặc trang marketing và muốn đảm bảo bundle JS bằng không một cách có thể kiểm chứng, Fresh làm được điều đó mà không cần cấu hình thêm.

Astro dùng các directive client:* trên từng component. Cơ chế zero-JS mặc định tương tự, nhưng mô hình hydrate phong phú hơn:

  • client:load — hydrate ngay khi trang tải xong
  • client:idle — hydrate khi trình duyệt rảnh
  • client:visible — hydrate khi component xuất hiện trong viewport
  • client:media — hydrate khi một CSS media query khớp

Fresh chỉ có một chế độ hydrate: island tải lên là chạy. Với hầu hết các trường hợp là đủ, nhưng client:visible của Astro thực sự hữu ích cho nội dung tương tác nằm dưới màn hình — carousel, FAQ accordion, phần bình luận tải muộn.

Điểm khác biệt cấu trúc nữa: Astro hỗ trợ React, Vue, Svelte, Solid, và Preact trong cùng một project. Bạn có thể pha trộn các framework component theo từng trang. Fresh chỉ dùng được Preact. Ràng buộc đó ổn nếu đội của bạn viết Preact, nhưng là hạn chế đáng kể nếu bạn đang đánh giá framework cho một đội đã có sẵn React component muốn tái sử dụng.

Trải nghiệm developer

Fresh 2.x thực sự thú vị nếu bạn chịu làm việc với Deno. Project khởi tạo bằng một lệnh duy nhất — không cần npm, không cần Node.js:

deno run -Ar jsr:@fresh/init

Fresh 2.0 ra mắt HMR chạy trên Vite, API App kiểu Express/Hono, và sửa các lỗi render async component vốn làm cho 1.x không ổn định trên các route động. Runtime Deno kiểm soát quyền truy cập từ lúc khởi động (-A cấp tất cả; code production sẽ thu hẹp phạm vi lại), đây là lợi thế bảo mật thực sự cho các route server-render gọi API bên ngoài.

Astro yêu cầu Node.js và npm/pnpm/yarn. Bề mặt thiết lập lớn hơn. Đổi lại là một toolchain trưởng thành: content collection với frontmatter được validate bởi Zod, hỗ trợ MDX, component model phong phú, và TypeScript hạng nhất — không có quirk deno.json, không có import map kiểu Deno phải giải thích cho contributor mới. Dev server của Astro 6 giờ chạy trên runtime workerd cho các target Cloudflare Workers, nên các lỗi “chạy được trên dev, vỡ ở prod” phần lớn đã được giải quyết.

Một điểm cộng về DX cụ thể cho Astro: content collections API. Nếu bạn xây trang với Markdown có cấu trúc — bài blog, changelog, trang tài liệu — getCollection() của Astro kết hợp với validate schema Zod nhanh hơn đáng kể so với routing theo file của Fresh cộng với việc tự parse front matter thủ công. Fresh không có tính năng tương đương.

Kết quả build và kích thước bundle

Với output tĩnh thuần túy, không framework nào tạo ra JavaScript đáng kể nếu không có island. Điểm so sánh có ý nghĩa là island runtime.

Astro đóng gói runtime React, Vue, hoặc Preact một lần thành shared chunk — khoảng 30 KB min+gzip cho Preact, ~45 KB cho React. Chunk đó được phân bổ cho tất cả island trên trang. Hai island trên một trang không làm tăng gấp đôi chi phí runtime.

Fresh đi kèm với Preact. Một trang có một island tốn xấp xỉ bằng Astro với Preact — vì đều dùng cùng một thư viện. Điểm khác biệt là pipeline build của Astro áp dụng tree-shaking và code splitting trên toàn project. Tích hợp Vite của Fresh (thêm vào từ 2.0) thu hẹp khoảng cách, nhưng nhiều năm tối ưu hóa build của Astro đã phản ánh rõ trong kích thước bundle cuối cùng.

Với trang tĩnh không có SSR, Astro cũng hỗ trợ output: 'static' không cần adapter — output là HTML thuần triển khai lên bất kỳ CDN nào. Fresh yêu cầu Deno để serve; không có chế độ export tĩnh tính đến Fresh 2.3.3.

Triển khai lên Cloudflare Workers

Đây là nơi cả hai framework hội tụ trong giai đoạn 2025–2026, và là phần so sánh cụ thể nhất.

Fresh 2.x trên Cloudflare Workers yêu cầu:

  1. @cloudflare/vite-pluginwrangler trong project
  2. Một server.js tùy chỉnh export một fetch handler
  3. wrangler.toml trỏ tới entry point sau khi build

Mô hình server native của Fresh trong Deno ánh xạ gọn gàng vào Workers fetch handler — phần trừu tượng mỏng và Worker kết quả nhỏ gọn. Cải thiện cold-start 9–12× trong Fresh 2.3.3 (do đội Deno tự công bố: 86ms → 8ms, đăng trong thông báo Fresh 2.0 beta) là con số nổi bật nhất. Workers tính tiền theo CPU millisecond, nên cold-start nhanh hơn có tác động thực sự đến chi phí ở quy mô lớn.

Astro 6 trên Cloudflare Workers dùng @astrojs/cloudflare adapter v13. Adapter này đã bỏ hỗ trợ SSR cho Cloudflare Pages từ v13 — các route SSR giờ triển khai lên Workers, không phải Pages. astro dev chạy runtime workerd thực sự, nên môi trường phát triển local ngang bằng với production. Để xem hướng dẫn triển khai từng bước, xem Cách triển khai Astro lên Cloudflare.

Các trang Astro tĩnh (không có SSR adapter) vẫn triển khai lên Cloudflare Pages qua git push — luồng đó không thay đổi.

Kết quả thực tiễn: cả hai công cụ giờ đều nhắm vào cùng một runtime Cloudflare Workers cho SSR. Chi phí cấu hình cho Fresh thấp hơn (mô hình runtime của Deno được thiết kế cho môi trường này). Adapter Astro trưởng thành hơn và có nhiều edge case được tài liệu hóa hơn, nhưng cũng kéo theo nhiều phần phức tạp hơn.

Hệ sinh thái và tích hợp

Đây là điểm yếu nhất của Fresh so với Astro.

Astro có hàng trăm tích hợp: Contentful, Sanity, Storyblok, Notion thông qua Content Layer loader; Pagefind và Algolia cho tìm kiếm; Cloudinary và Imagetools cho tối ưu hóa hình ảnh; Tailwind, UnoCSS, và vanilla-extract cho styling. Cộng đồng phát hành adapter và loader với tốc độ phản ánh 59.000+ GitHub star của framework (tính đến tháng 5 năm 2026).

Fresh đã tiếp cận hệ sinh thái Vite plugin từ bản 2.0 — cải tiến đáng kể so với 1.x vốn bị cô lập khỏi hệ sinh thái JavaScript tooling rộng lớn hơn. Nhưng các connector Fresh 2.x cụ thể cho Contentful, Sanity, hay Storyblok chưa được xuất bản chính thức tính đến tháng 5 năm 2026. Bạn có thể kéo dữ liệu CMS trong Fresh handler hoặc route — đó là TypeScript/Deno thuần — nhưng bạn phải tự kết nối thay vì dùng tích hợp được bảo trì sẵn.

Khoảng cách về star khá rõ: withastro/astro có khoảng 59.000 GitHub star; denoland/fresh khoảng 12.000. Tốc độ đóng góp, plugin cộng đồng, và mức độ phủ sóng trên Stack Overflow đều đi theo con số này.

Nếu trang của bạn cần kéo nội dung từ headless CMS, cần full-text search, hoặc phụ thuộc vào tối ưu hóa hình ảnh, lợi thế hệ sinh thái của Astro là yếu tố quyết định.

Những đánh đổi khi dùng Deno

Runtime của Fresh vừa là tính năng tốt nhất vừa là rào cản lớn nhất khi muốn áp dụng.

Mặt tích cực: Deno kiểm soát quyền ở cấp process (file, mạng, biến môi trường). Với các route server-render gọi API bên thứ ba, đây là ranh giới bảo mật thực chất. Việc TypeScript chạy trực tiếp trong Deno — không cần bước transpile, không cần ts-node — loại bỏ một tầng toolchain khỏi project. Và JSR (registry package của Deno) đang ngày càng trưởng thành; thư viện chuẩn ổn định và được tài liệu hóa tốt.

Mặt tiêu cực: đội của bạn cần hiểu tooling đặc thù của Deno. Import map trong deno.json, flag quyền truy cập, và sự khác biệt giữa package npm và JSR không phải là đường cong học tập quá dốc khi xét riêng lẻ, nhưng cộng lại thì đáng kể. Bất kỳ contractor hay nhân viên mới quen với Node và npm đều cần được làm quen thêm. Tầng tương thích Deno (import với tiền tố npm:) xử lý được hầu hết package npm, nhưng đôi khi bạn sẽ gặp package giả định các Node.js API mà Deno không cung cấp.

Astro chạy trên Node. Node chạy khắp nơi. Thực tế đơn giản đó không phải là chuyện nhỏ.

Kết luận

Chọn Fresh 2.x nếu:

  • Đội của bạn đã viết Deno và muốn ở lại trong hệ sinh thái đó.
  • Cold-start latency trên Cloudflare Workers là yêu cầu bắt buộc — 8ms tốt hơn đáng kể so với cold-start Node.js thông thường.
  • Bạn muốn đảm bảo zero-JS mà không cần cấu hình — convention islands/ làm điều đó mang tính cấu trúc thay vì tùy chọn.
  • Trang của bạn chỉ dùng Preact và sẽ không cần tái sử dụng React hay Vue component.
  • Bạn thoải mái tự xây dựng tích hợp CMS thay vì dùng connector được bảo trì sẵn.

Chọn Astro nếu:

  • Đội của bạn viết TypeScript trên Node.js và muốn con đường ít cản trở nhất.
  • Nội dung nằm trong headless CMS (Contentful, Sanity, Storyblok, Notion) và bạn muốn có loader chính thức, không phải tự fetch.
  • Bạn cần chiến lược hydrate phong phú hơn — client:visibleclient:media có những trường hợp dùng thực tế trên các trang nặng nội dung.
  • Project có thể cần React, Vue, hay Svelte component — Astro hỗ trợ tất cả; Fresh thì không.
  • Bạn đang xây trang tĩnh không có server-side logic và muốn output: 'static' không phụ thuộc runtime.
  • Kích thước hệ sinh thái quan trọng cho bảo trì lâu dài: nhiều plugin hơn, nhiều ví dụ hơn, nhiều hỗ trợ từ cộng đồng hơn.

Với hầu hết các đội đang cân nhắc giữa hai công cụ này vào giữa năm 2026, kết luận rõ ràng nghiêng về Astro. Fresh là một framework mạnh — bản viết lại 2.x đã giải quyết những điểm đau vốn giữ 1.x lại — nhưng nó đòi bạn phải cam kết với hệ sinh thái Deno để đổi lấy những lợi thế đó. Sự đánh đổi đó xứng đáng với một đội native Deno. Với những người còn lại, Astro cho bạn kiến trúc island tương tự với ít cản trở hơn và hệ sinh thái sâu hơn.

Lưu ý

Các chỉ số cold-start của Fresh (9–12×, 86ms → 8ms) do đội Deno tự công bố trong thông báo Fresh 2.0 beta. Không có benchmark độc lập từ bên thứ ba nào so sánh Fresh và Astro trên cùng một tài khoản Cloudflare Workers và workload được công bố công khai tính đến tháng 5 năm 2026. Hãy tự đo trước khi coi tỷ lệ đó là số liệu đảm bảo.

Phiên bản Astro tại thời điểm xuất bản là 6.3.1 (tháng 5 năm 2026). Tính năng thay đổi qua các bản minor — hãy xác minh tại astro.build/blog trước khi dựa vào hành vi cụ thể được mô tả ở đây.

Tình trạng tích hợp CMS của Fresh thay đổi nhanh. Hãy xác minh những gì có sẵn trên JSR và Deno module registry tại thời điểm bạn đọc bài trước khi kết luận rằng bạn phải tự xây dựng.

Bài viết có chứa affiliate link dẫn đến Cloudflare Workers. toolchew nhận hoa hồng nếu bạn đăng ký qua các link đó.

Tham khảo