最近想分享一个比较实用的话题:Vibe Coding 做出来的 Next.js 应用应该怎么部署,以及怎么给它做全球加速。
这类应用通常有三种形态:
- 纯静态应用:只有前端页面,不需要数据库,也没有服务端逻辑。
- 前端 → Supabase(SDK / REST):浏览器通过 Supabase 的客户端 SDK 或 REST 接口读写数据,由 RLS 负责数据权限。
- 前端 → Next.js 服务端 → Supabase / 外部服务:Next.js 服务端可以通过 API、SSR、Server Component 或 Server Action,承载更复杂的权限与业务逻辑。
三者的部署方式并不一样。纯静态应用可以直接放到 CDN 或边缘节点;如果只是简单的数据读写,可以让浏览器直连 Supabase;如果应用需要隐藏服务端密钥、执行复杂业务逻辑,或者要在服务端生成页面,就需要让请求经过 Next.js 服务端。
这里的“经过 Next.js 服务端”不等于一定存在一个传统 API。SSR 或 Server Component 可以在服务器直接读取 Supabase 后生成页面;Route Handler 或 Server Action 则更常用于浏览器操作触发的读写。它们经常组合使用,但解决的是不同问题。
第三种形态还有一个特别需要注意的点:服务端要尽量靠近数据库。
既然 Next.js 服务端承担了 API、SSR 或 Server Action 的工作,它就会频繁访问数据库和其他外部服务。不能为了全球访问把服务端部署在海外,但数据库还在大陆,尤其是一次请求中存在多次服务端与数据库之间的来回调用时,跨区域延迟会不断叠加,最后用户感受到的反而是更慢。
所以,选择服务端部署区域时,应该先看数据库在哪里,再看用户主要在哪里。DCDN 可以加速用户到边缘节点这一段,但不能消除服务端与数据库之间的远距离调用。
一、前端直连 Supabase 时要注意什么?
浏览器里的代码和用户是同一侧的,用户可以看到前端发出的请求。因此,浏览器直连 Supabase 时,不能把安全寄托在“用户看不到接口”上。
不过,浏览器直连 Supabase 并不等于天然不安全。Supabase 的 anon key 本来就可以放在前端,真正负责数据隔离的是数据库的 RLS 策略和用户权限。新增、修改、删除等操作也可以通过 RLS 安全完成,但规则必须配置正确。
如果还需要隐藏 service-role key、调用第三方私密 API、执行复杂业务规则,或者不希望把数据处理过程暴露在浏览器中,就应该由 Next.js 的服务端逻辑承接请求,在服务端完成鉴权、权限判断和数据库操作。
二、用函数服务运行 Next.js
我最近体验的是火山引擎的函数服务。它的思路是:把应用代码交给云端,由云端在容器中运行,并提供一个可以公开访问的域名。
在这种部署方式中,Next.js 的前端页面和服务端逻辑可以由同一套应用承载。你还可以为函数设置实例策略:
- 动态实例:请求到来时再启动实例,成本较低,但可能遇到冷启动。
- 预留实例:提前启动固定数量的实例,响应更快,但会持续占用资源。
我原本以为预留实例一定更贵,后来发现并不完全如此。因为资源提前锁定后,调度成本更低,在访问量较大的场景下,预留实例反而可能更划算。
如果只是开发环境,流量很少,可以使用动态实例;如果访问量比较稳定,或者比较在意首个请求的响应速度,可以考虑预留实例。
另外,不管是动态实例还是预留实例,每个实例都有自己的并发配置。平台给出的默认并发值可能是 100,但不要直接照搬这个默认值。因为默认实例的内存和 CPU 通常并不高,Next.js 的 SSR 或 API 在高并发下会让多个请求争抢同一个实例的资源,容易出现排队、超时或错误。
这种情况下,单实例并发宁可先设得低一些,再结合 CPU、内存、响应时间和错误率做压测,逐步调高。实例数量和单实例并发是两个不同的参数,都需要根据实际负载调整。
三、先确认平台支持的 Node.js 版本
不同服务商对 Next.js 的运行环境要求并不一样,不能只因为本地项目能跑,就直接把它部署到任意平台。
以火山引擎为例,当前官方部署文档要求本地准备 Node.js 20.x,并选择 Native Node.js 20.x 运行时。更高版本不要轻易使用,至少要先确认平台当前的运行时支持范围,以及 Next.js 和依赖是否兼容。
如果使用 veFaaS CLI 部署,官方流程是:CLI 在项目目录中探测框架、构建命令、产物路径和启动命令,然后进入依赖安装和构建流程,再把构建结果部署到云端。也就是说,针对这条 CLI 部署路径,构建主要发生在本地,云端负责接收并运行部署产物,并不是把完整源码交给云端再临时构建。
因此,部署前最好让本地 Node.js 版本和平台运行时保持一致。我更推荐配合 veFaaS CLI 和对应的 Skill 使用:CLI 负责真实执行,Skill 负责提示运行时、构建配置和常见排障路径。
四、为什么还要在函数服务前面加一层 DCDN?
函数服务解决的是“代码在哪里运行”,但它本身不等于全球加速。用户的请求仍可能需要跨较远的网络访问函数实例。
一种做法是在函数服务前面接入 DCDN,把它作为统一的访问入口。这样可以让静态资源尽量在边缘节点命中,同时把动态请求转发回函数服务。
但仅仅把 DCDN 挂上去还不够,关键是要配置缓存和条件路由。
静态资源:尽量缓存
Next.js 生成的静态资源通常可以缓存较长时间,例如 _next 路径下的资源。这些文件一般带有版本化或哈希信息,内容变化后 URL 也会变化,适合交给 CDN 缓存。
动态接口:默认不要缓存
登录状态、用户信息和数据库查询结果都可能是动态内容,尤其是 /api/ 下的接口,通常不应该直接套用静态缓存规则。
可以通过条件路由区分静态资源和动态请求:静态资源走缓存,API 和其他动态页面回源到函数服务。具体规则要结合自己的路由结构验证,不能只凭路径名称盲目配置。
五、DCDN 里几个值得检查的配置
HTTP/2
HTTP/2 可以帮助同一个连接并发处理多个请求,对动态请求和包含多个资源的页面比较有帮助。
Gzip
Gzip 可以压缩 HTML、CSS、JavaScript 等文本资源,通常收益明显,性能损耗也较小,一般建议开启。
HTTPS
HTTPS 是生产环境的基本配置。除了保护传输内容,现代浏览器的许多能力也依赖安全连接。
六、DCDN 的加速范围
DCDN 通常有大陆、海外和全球三种加速范围。具体怎么选,取决于用户分布,而不是简单跟着函数服务所在区域走。如果缺少可以国内备案的域名,就选海外加速即可。
结论:函数服务 + DCDN 适合什么场景?
如果你的 Next.js 应用需要服务端执行(例如 SSR、Route Handler 或 Server Action),或者需要让服务端安全地连接数据库,那么“函数服务 + DCDN”是一种相对直观的方案:
- 函数服务负责运行 Next.js 和服务端逻辑;
- DCDN 负责静态资源缓存和网络加速;
- 条件路由负责区分静态请求和动态请求;
- 实例策略负责在响应速度与成本之间做取舍。
站点部署好之后,我还推荐用 Chrome DevTools 的性能分析工具跑一遍,看看首屏加载、静态资源、网络请求和脚本执行方面还有哪些值得优化的地方。部署完成不等于性能优化结束,实际访问数据和浏览器分析结果,才是下一轮调整的依据。