搭博客选框架的经历:Astro、Hugo、Next.js
概述
静态博客是每个开发者都想过要搭的东西。2026 年,选择不是变少了,而是更多了——每个方案都有自己的生态和拥趸。
我在搭 SelfStack 这个博客时把三个主流方案都试了一遍(Hugo 最早、Next.js 过渡、最终选了 Astro),这篇文章从实际体验出发做一次深度对比。不列参数表格充字数,只说真实使用中的感受和决策依据。
一、三个方案的核心定位
Astro — 内容优先的静态站点框架
Astro 的口号是”内容优先的 Web 框架”。它的核心理念是岛屿架构(Islands Architecture)——页面大部分是纯静态 HTML,只在需要交互的地方加载 JS。
- 语言:TypeScript + JSX(.astro 文件)
- 模板:.astro 组件、支持 MDX
- 构建方式:静态站点生成(SSG)+ 服务端渲染(SSR)
- 发布:2021 年,当前稳定版 6.x
- 维护方:Astro 团队
Astro 是三者中最年轻、最专注”内容网站”这个场景的框架。
Hugo — 老牌经典,快如闪电
Hugo 是用 Go 语言写的静态站点生成器,以构建速度闻名。它的理念是”一个二进制搞定一切”——不需要 Node.js、不需要依赖管理。
- 语言:Go(模板语言是 Go Templates)
- 模板:Go Templates + .html
- 构建方式:纯静态站点生成
- 发布:2013 年,当前稳定版 0.14x
- 维护方:Bjørn Erik Pedersen 及社区
Hugo 是三者中年龄最大的,也是最”纯粹”的静态站点生成器——它只做静态站点,不做别的。
Next.js — React 生态的全栈框架
Next.js 是 Vercel 维护的全栈 React 框架。虽然它不是一个专门的”博客框架”,但它的 SSG 能力 + React 生态使其成为搭建博客的常见选择。
- 语言:TypeScript + React(JSX)
- 模板:React 组件
- 构建方式:SSG + SSR + ISR(增量静态再生)
- 发布:2016 年,当前稳定版 15.x
- 维护方:Vercel
Next.js 是三者中最重的——它什么都能做,但如果你的目标只是”搭个博客”,它的能力是过剩的。
一句话定位
Hugo → "一碗面":简单直接,吃就完事Astro → "套餐":搭配灵活,体验舒适Next.js → "自助餐":什么都有,但需要你自己搭配二、架构设计对比
2.1 构建原理
Hugo 的原理最直接:读取 Markdown + 模板 → 直接输出 HTML。没有虚拟 DOM、没有水合(hydration)、没有任何 JavaScript 运行时。
Markdown → Hugo → HTML(纯静态)模板 → CSS/JS(文件复制)Astro 的原理是在构建时把 .astro 组件渲染成 HTML,页面中交互部分(Islands)按需加载对应的 JS。
.astro → 服务端渲染 → HTML + 部分 CSS.md → └─ 交互组件(.svelte/.react/.vue) → 按需 JSNext.js 通过 getStaticProps / generateStaticParams 在构建时生成静态页面,但它仍然保留了一个 Node.js 运行时用于 SSR 和 API Routes。
React 组件 → 构建时 SSG → HTML + JS bundle.md/.mdx → └─ API Routes(Node.js 运行时) └─ ISR(按需重新生成)2.2 内容管理
# 三者都支持的标准 frontmatter---title: Hello Worlddate: 2026-06-09tags: [blog]---| 维度 | Hugo | Astro | Next.js |
|---|---|---|---|
| 内容格式 | Markdown(.md) | .md / .mdx | .md / .mdx |
| 内容目录 | content/ 目录 | src/content/(Content Collections) | 自己组织 |
| 内容查询 | 全局变量(.Site.RegularPages) | Astro Content Collections API | 自己写逻辑 |
| 分类/标签 | 内建支持 | 需自己定义 schema | 需自己写 |
| 多语言 | 内建 i18n 系统 | 需要自己做或集成库 | 需要自己做 |
| 图片优化 | 需要 shortcode | Image 组件 | next/image |
Astro 的 Content Collections 是三者中做得最好的——类型安全、结构化校验、自动生成 API:
---// Astro Content Collections —— 类型安全import { getCollection } from 'astro:content';
const posts = await getCollection('posts');// posts 的类型根据 content.config.ts 自动推断// 有发布时间、标签等字段约束// 直接写错字段名 IDE 会报错---
{posts.map(post => <a href={post.slug}>{post.data.title}</a>)}Hugo 的内容查询依赖模板层面的全局变量,没有类型安全:
{{ range .Site.RegularPages }} <a href="{{ .RelPermalink }}">{{ .Title }}</a>{{ end }}<!-- Hugo 不会检查 .Title 是否存在,模板运行时报错 -->2.3 模板系统
Hugo 的 Go Templates 学习曲线最高:
{{/* Hugo Go Templates */}}{{ define "main" }}<div class="posts"> {{ range (.Paginate .Site.RegularPages).Pages }} <article> <h2><a href="{{ .RelPermalink }}">{{ .Title }}</a></h2> <time>{{ .Date.Format "2006-01-02" }}</time> {{ .Summary }} </article> {{ end }} {{ template "_internal/pagination.html" . }}</div>{{ end }}Astro 的 .astro 文件语法最自然(JSX-like):
---// Astro 组件import Layout from '../layouts/Layout.astro';import { getCollection } from 'astro:content';
const posts = await getCollection('posts');const { pagination } = Astro.props;---
<Layout title="博客列表"> <div class="posts"> {pagination.data.map(post => ( <article> <h2><a href={`/${post.slug}/`}>{post.data.title}</a></h2> <time>{post.data.published.toLocaleDateString()}</time> <p>{post.data.description}</p> </article> ))} </div></Layout>Next.js 就是标准 React 组件:
// Next.js App Routerimport Link from 'next/link';
interface Post { slug: string; title: string; date: string;}
export default async function BlogList() { const posts: Post[] = await getPosts();
return ( <div className="posts"> {posts.map(post => ( <article key={post.slug}> <h2><Link href={`/${post.slug}/`}>{post.title}</Link></h2> <time>{post.date}</time> </article> ))} </div> );}2.4 项目结构对比
Hugo 的项目结构有固定的约定,你的内容必须严格按约定放:
my-hugo-site/├── archetypes/ # 内容模板├── content/ # Markdown 内容│ └── posts/├── layouts/ # 模板│ ├── _default/│ ├── partials/│ └── index.html├── static/ # 静态资源├── assets/ # 需要构建的资源├── config.toml # 配置文件└── themes/ # 主题Astro 的模式自由度高,但社区有惯例:
my-astro-site/├── src/│ ├── components/ # UI 组件│ ├── content/ # Content Collections│ │ └── posts/│ ├── layouts/ # 页面布局│ ├── pages/ # 路由页面│ ├── config/ # 站点配置│ └── styles/ # 全局样式├── public/ # 静态资源├── astro.config.mjs # Astro 配置└── package.jsonNext.js 强制约定文件系统路由(App Router):
my-next-site/├── app/│ ├── layout.tsx # 根布局│ ├── page.tsx # 首页│ ├── posts/│ │ ├── [slug]/│ │ │ └── page.tsx│ │ └── page.tsx│ └── globals.css├── content/ # 自己组织的内容目录├── components/ # React 组件├── lib/ # 工具函数├── next.config.ts # Next.js 配置└── package.json三、开发体验对比
3.1 上手难度
Hugo 的上手曲线最陡:Go Templates 语法特别,配置项多(config.toml 可以写几百行),主题系统有自己的约定。如果你的目标是”改主题不说话”,Hugo 可以很快;如果你要自己写模板,需要学的东西不少。
Astro 的上手曲线最平缓:.astro 文件就是 HTML + JS 混合,和写 React/HTML 没有本质区别。Content Collections 开箱即用,安装即有一个完整可用的博客脚手架。
Next.js 的上手看 React 基础:如果你已经熟悉 React,上手 Next.js 没什么问题。如果不熟悉 React,需要先学 React 再学 Next.js。App Router 的 Server Component 模型和传统 React 差异很大,即使有 React 经验也需要适应期。
3.2 热更新速度
Hugo 的 hugo server 冷启动极快(毫秒级),修改后即时刷新,没有 JS bundle 的过程。这是 Go 语言编译速度的天然优势。
Astro 的 astro dev 也很快(秒级启动),HMR 体验顺滑。修改 .astro 文件只更新对应页面,不会全量重建。
Next.js 的 next dev 启动较慢(5-15 秒,取决于项目大小),修改后的 Turbopack(如果启用)做了大量优化,但速度仍然不如前两者。
冷启动速度:Hugo >>> Astro > Next.js热更新速度:Hugo > Astro >> Next.js3.3 内容编写体验
写博客的核心体验是”写 Markdown → 刷新看到效果”。
Hugo 支持标准的 Markdown,但扩展功能(如表格、提示框、代码高亮)需要 shortcode。
Astro 的 Markdown 体验最好——原生支持 MDX,可以在 Markdown 中直接使用组件:
---title: 用 MDX 写文章---
这是一篇普通的 Markdown 文章。
<Note type="tip"> 这是 MDX 组件,直接在 Markdown 中使用</Note>
<Gallery> <Image src="/photo1.jpg" alt="照片1" /> <Image src="/photo2.jpg" alt="照片2" /></Gallery>Next.js 也支持 MDX,但需要额外的配置(@next/mdx),配置起来比 Astro 复杂一些。
3.4 生态与插件
Hugo 的”插件”体系是 shortcode + 模板片段。生态集中在主题层面,有丰富的主题市场,但功能扩展能力有限。
Astro 的集成体系成熟:官方集成覆盖了最常用的场景,社区集成也在快速增长。
Astro 的集成是首屈一指的——你想要的功能基本都有官方或社区集成。
Next.js 的”生态”其实就是 React 生态。你能找到的 npm 包最多,但每个都需要自己集成配置。
生态丰富度:Next.js(Node.js 生态系统)> Astro >> Hugo集成开箱度:Astro > Hugo > Next.js3.5 构建性能
Hugo 在这个维度是碾压级的。
以 1000 篇文章的博客为例:
全量构建时间: Hugo: < 1 秒 Astro: ~5-10 秒 Next.js: ~30-60 秒(纯 SSG)Hugo 的构建速度是 Go 语言级别的——它不依赖任何 JS 运行时,直接解析模板和 Markdown 输出 HTML。如果你有上万篇文章,Hugo 是唯一能保持秒级构建的方案。
Astro 的构建速度在几百篇文章的范围内完全可接受(几秒到十几秒),已经很快了。
Next.js 的纯静态构建速度一般,而且随着页面数量增加,构建时间线性增长。如果使用增量静态再生(ISR),可以解决首次构建慢的问题,但又引入了运行时依赖。
四、部署与运维
4.1 输出产物
Hugo 输出纯静态文件——一个完全自包含的目录:
hugo --minify# 输出到 ./public/public/├── index.html├── posts/├── tags/├── css/├── js/└── ...# 直接扔到任何静态文件服务器即可Astro 同样输出纯静态文件(如果使用 SSG 模式):
npm run build# 输出到 ./dist/dist/├── index.html├── posts/├── _astro/ # 资源文件(哈希命名)└── ...# 扔到任何静态服务器Next.js 输出两种东西:静态文件 + Node.js 运行时(如果使用 API Routes 或 ISR):
npm run build# 输出到 .next/.next/├── server/ # 服务端代码├── static/ # 静态资源└── ...# 需要一个 Node.js 运行时(Vercel / 自己的服务器)4.2 托管选项
| 平台 | Hugo | Astro | Next.js |
|---|---|---|---|
| GitHub Pages | ✅ 完美 | ✅ 完美 | ⚠️ 需要适配 |
| Cloudflare Pages | ✅ 完美 | ✅ 完美 | ⚠️ 有限支持 |
| Netlify | ✅ 完美 | ✅ 完美 | ✅ 完美 |
| Vercel | ✅ 完美 | ✅ 完美 | ✅ 原生最优 |
| 自托管 Nginx | ✅ 扔文件 | ✅ 扔文件 | ⚠️ 需要 Node.js |
| 对象存储(S3/R2) | ✅ 直接上传 | ✅ 直接上传 | ❌ 不支持 |
Hugo 和 Astro 的纯静态输出可以部署在任何静态文件托管上——这是它们最大的运维优势。
Next.js 的部署选择受限:Vercel 是原生平台,自托管需要 Node.js 环境,Cloudflare Pages 的支持不完整。
4.3 运维复杂度
运维复杂度:Next.js > Astro ≈ HugoHugo 和 Astro 的运维基本上就是”上传文件”四个字。CI/CD 流程简单到极致:
# Hugo/Astro 的典型 CIname: Deployon: [push]jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm install && npm run build # Hugo 甚至不需要 npm install - run: npx pagefind --site dist # Astro 可选 - uses: cloudflare/pages-action@v1 # 部署到 CloudflareNext.js 的 CI/CD 相对复杂,尤其是自托管场景(需要 pm2、反向代理、环境变量管理等)。
五、实际使用体验
5.1 Hugo —— 我在 2023 年的体验
最早我用的就是 Hugo。它的构建速度确实让人印象深刻——上千篇文章一秒不到就构建完成。主题市场丰富,找到一个合适的主题就能很快上线。
但真正开始写内容后,痛点就来了:
- 想改一个细小的布局,需要学 Go Templates 的语法,文档难啃
- 想加一个功能(比如图片懒加载),要么找 shortcode 要么自己写
- 主题的”自定义”路径不直观,经常需要 override 整个模板文件
- 非开发者使用难度大 —— 如果只写内容不碰模板,Hugo 可以。但只要你需要定制,就要学一套和主流前端完全不同的技术栈。
5.2 Next.js —— 我在 2024 年的尝试
作为一个前端开发者,Next.js 是我的自然选择。React 生态熟悉、组件复用方便、Vercel 部署丝滑。
但用了一段时间后也发现了问题:
- 我只想写个博客,但 Next.js 给我的是一整套全栈框架
- App Router 的学习曲线比预期的陡 —— Server Component、RSC、
'use client'的边界需要理解 - 构建速度慢,100 篇文章的站点构建要 30 秒以上
- 部署锁定 Vercel —— 自托管太麻烦
- “能力过剩” —— 博客不需要 ISR、不需要 API Routes、不需要中间件,但这些都在 bundle 里
5.3 Astro —— 最终选择
最后选 Astro 的原因很简单:它在 Hugo 和 Next.js 之间找到了最佳平衡点。
- 开发体验好:写 .astro 文件就像写 HTML + JS,零学习成本
- 内容管理强大:Content Collections 的类型安全让我这种重视可靠性的人很安心
- 组件生态灵活:可以在 Astro 中用 React/Svelte/Vue 组件,不需要选边站
- 性能优秀:岛屿架构让页面几乎不加载 JS,速度快
- 部署自由:纯静态输出,扔到任何地方都能跑
- 集成丰富:MDX、Tailwind、Sitemap、RSS 全部官方集成,一行配置搞定
SelfStack 这个博客就是用 Astro + Svelte + Tailwind 搭建的,目前体验非常满意。
5.4 三者的典型用户画像
Hugo 适合谁: ├── 非前端开发者(后端/运维/Go 开发者) ├── 大内容站点(数千篇以上) ├── 不想碰 Node.js 生态的人 └── 只要博客能用就行,不想折腾
Astro 适合谁: ├── 前端开发者 ├── 内容创作者 + 开发者混合身份 ├── 对页面性能和 JS 体积有要求的人 ├── 想要灵活性和生态(React/Vue/Svelte 混用) └── 需要 Content Collections 类型安全的人
Next.js 适合谁: ├── React 重度用户 ├── 需要 API Routes / 全栈能力的站点 ├── 电商/应用类网站(不只是博客) └── 准备用 Vercel 部署的人六、选型建议
6.1 决策树
Q: 你有多少篇文章?├── < 10 篇:随便选,哪个学得快用哪个├── 10 ~ 500 篇│ ├── 会前端 → Astro│ └── 不会前端 → Hugo│ └── 必须用 React → Next.js├── 500 ~ 5000 篇│ ├── 性能优先 → Hugo│ └── 体验优先 → Astro└── > 5000 篇 → Hugo6.2 如果你是初学者
想做博客 → 会编程 ├── 会前端(HTML/CSS/JS)→ Astro(最推荐) ├── 会 Go 或不想学前端 → Hugo └── 只会 React → Next.js想做博客 → 不会编程 ├── 完全不会写代码 → WordPress / Notion 更合适 └── 愿意学一点 → Astro + 主题模板6.3 我的个人建议
Astro 是 2026 年搭建内容类站点(博客、文档站、公司官网)的最佳选择。它在三个方案中取得了最好的平衡:
- 比 Hugo 更现代、更好扩展、开发体验更好
- 比 Next.js 更专注、更轻量、部署更自由
- 两边的优点它都占了,两边的缺点它都避开了
如果你已经在用 Hugo 而且用得很顺手,没有迁移的必要。如果你已经在用 Next.js 而且需要它的全栈能力,也没必要换成 Astro。
但如果你正在选型阶段,或者对现有方案不满意——Astro 值得一试。
七、快速开始的命令对比
# Hugohugo new site my-blogcd my-bloggit initgit submodule add https://github.com/theNewDynamic/gohugo-theme-ananke themes/anankeecho "theme = 'ananke'" >> hugo.tomlhugo new posts/my-first-post.mdhugo server -D
# Astropnpm create astro@latest my-blog -- --template blogcd my-blogpnpm dev
# Next.jsnpx create-next-app@latest my-blog -- --typescript --tailwindcd my-blog# 还需要自己配置 MDX、内容管理等...npm run dev从零到能在浏览器看到内容,Astro 只需要两行命令。这不是偶然——Astro 从一开始就是为”内容网站”这个场景设计的。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!