You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Fly.io上Next.js预渲染路由构建时PostgreSQL连接失败求助

解决Fly.io部署Next.js App目录API路由预渲染时的PostgreSQL连接问题

核心原因

Fly.io的构建阶段无法直接访问Fly托管的Postgres实例,且默认不会加载应用的secrets(secrets仅在运行阶段生效)。Next.js App Router的API路由如果是静态预渲染(默认GET请求会尝试静态生成),构建时会执行路由内的数据库查询,导致连接失败。

简便解决方案

方案1:强制API路由动态运行(最快捷)

在你的/api/my-api-route/route.js(或.ts)文件顶部添加以下代码,让Next.js在构建时跳过预渲染,部署后运行时再执行数据库查询:

export const dynamic = 'force-dynamic';

这样构建阶段不会执行数据库操作,部署后应用会使用Fly secrets中配置的DATABASE_URL连接Postgres,无需修改构建流程。

方案2:安全传递构建阶段所需的DATABASE_URL

如果需要保留静态预渲染,可通过Fly的构建秘密(Build Secrets)安全传递DATABASE_URL到构建环境:

  1. 执行部署命令时传递构建秘密:
fly deploy --build-secret DATABASE_URL=$(fly secrets get DATABASE_URL)
  1. 修改生成的Dockerfile,在npm run build步骤挂载构建秘密:
# 替换原有的npm run build步骤
RUN --mount=type=secret,id=DATABASE_URL,env=DATABASE_URL npm run build

此方法不会将DATABASE_URL明文写入镜像或暴露在构建日志中,同时构建阶段能正常连接Postgres完成预渲染。

方案3:构建阶段使用Mock数据

如果不需要静态预渲染的真实数据,可在代码中判断构建环境,返回mock数据:

import { NextResponse } from 'next/server';
import { Pool } from 'pg';

export async function GET() {
  // 判断是否为Fly构建阶段
  const isBuildStage = process.env.NODE_ENV === 'production' && process.env.FLY_BUILD_STAGE === 'true';
  
  if (isBuildStage) {
    // 返回mock数据跳过真实查询
    return NextResponse.json([{ id: 1, name: 'Mock Data' }]);
  }

  // 运行阶段执行真实查询
  const pool = new Pool({ connectionString: process.env.DATABASE_URL });
  const res = await pool.query('SELECT * FROM test');
  await pool.end();
  
  return NextResponse.json(res.rows);
}

部署时传递构建秘密设置环境变量:

fly deploy --build-secret FLY_BUILD_STAGE=true

为什么之前的方法无效

  • ENV DATABASE_URL="postgres://:memory:":pg包不支持内存PostgreSQL,无法正常执行查询。
  • Dockerfile写入实际DATABASE_URL:会将敏感信息明文打包进镜像,存在安全风险,且URL变更后需重新修改Dockerfile。
  • --build-arg传递:参数会暴露在构建日志中,不安全,且Fly构建环境默认限制了对内部Postgres实例的访问(即使拿到URL,构建阶段也无法连接)。

内容的提问来源于stack exchange,提问作者Ilya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 17:55:12