配置体系
环境变量、Feature Flags、运行时配置——搞清楚什么变量控制什么功能。
本页是配置体系的完整指南,包含配置系统说明、所有环境变量速查和 Feature Flags 管理。
快速开始:4 个变量启动项目
01MVP 本地开发优先使用产品级 env,从产品自己的 .env.example 复制并修改:
cp products/01mvp/packages/config/.env.example products/01mvp/packages/config/.env根目录 packages/config/.env 是共享兜底。只有多个产品确实要共用同一批默认值时,再复制它:
cp packages/config/.env.example packages/config/.env本地开发至少需要下面 4 个变量:
DATABASE_URL -- PostgreSQL 连接字符串
postgresql://localhost:5432/myapp_dev本机 Homebrew PostgreSQL 可以不写用户名和密码,客户端会默认使用当前 macOS 用户。远程 PostgreSQL 使用服务商提供的完整连接串。
BETTER_AUTH_SECRET -- 认证签名密钥,至少 32 位字符
openssl rand -base64 32VITE_WEB_URL -- 站点公开地址
http://localhost:7001 # 开发环境
https://your-domain.com # 生产环境VITE_SERVER_URL -- API 公开地址
http://localhost:7001/api
https://your-domain.com/api安全提示
products/01mvp/packages/config/.env 和 packages/config/.env 都不要提交到 Git。生产环境通过部署平台的环境变量面板管理。
修改环境变量后需要重启 vpr @01mvp/product#dev 才会生效,TanStack Start 不会热加载环境变量的变化。另外,只有以 VITE_ 开头的变量才会暴露给浏览器端代码。
配置系统说明
共享环境变量 schema 位于 packages/config/src/server/env.ts 和 packages/config/src/web/env.isomorphic.ts。产品代码通过自己的 config 包读取这些变量,例如 01MVP 使用 @01mvp/config,OneSay 使用 @onesay/config。服务端变量只在 Worker / server runtime 使用;VITE_ 变量会进入浏览器端 bundle。
配置分为两类:
- 环境变量:通过
products/01mvp/packages/config/.env和共享兜底packages/config/.env管理,控制外部服务连接和密钥 - 运行时配置:通过各功能包的配置代码管理,控制功能开关和业务逻辑
环境变量优先级:以 VITE_ 开头的变量暴露给浏览器端代码,其余仅在服务端可用。
Monorepo 里的维护方式
这套模板把共享 env schema 放在 packages/config,再用产品级 config 包承接产品默认值。核心原因是很多能力会跨越多个 package:products/01mvp/packages/api 需要数据库、支付和存储,products/01mvp/packages/auth 需要登录密钥,products/01mvp/apps/web 需要浏览器可见的公开地址。把变量散落到每个 app 目录,后面会很容易出现同一个变量多个名字、多个默认值、多个说明。
推荐维护方式如下:
| 位置 | 作用 | 是否提交 |
|---|---|---|
packages/config/src/server/env.ts | 服务端变量 schema,包含密钥和运行时配置 | 是 |
packages/config/src/web/env.isomorphic.ts | 浏览器安全的 VITE_* 变量 schema | 是 |
packages/config/.env.example | 模板变量索引,只放占位值和默认值 | 是 |
products/01mvp/packages/config/.env.example | 01MVP 产品默认值和产品级变量示例 | 是 |
products/01mvp/packages/config/.env | 01MVP 本机开发真实值,优先级最高 | 否 |
packages/config/.env | 多产品共享的本机兜底值 | 否 |
products/01mvp/packages/config | 01MVP 产品默认值和产品级 env 包 | 是 |
products/onesay/packages/config | OneSay 产品默认值和产品级 env 包 | 是 |
| 部署平台 Variables / Secrets | 生产、预发等环境真实值 | 平台托管 |
以后 monorepo 增加新的产品时,先判断变量属于共享平台能力还是产品能力。共享变量定义放在 packages/config,产品默认值和产品级 .env.example 放在 products/<product>/packages/config。
本地脚本按下面顺序加载 env:产品 env 优先,shared env 作为兜底。这样 VITE_WEB_URL、VITE_SERVER_URL、EMAIL_FROM、AUTH_COOKIE_PREFIX 这类同名变量可以按产品覆盖。
products/<product>/packages/config/.env
packages/config/.env01MVP 项目初始化时,优先复制对应产品的示例文件:
cp products/01mvp/packages/config/.env.example products/01mvp/packages/config/.env如果一个变量只属于某个产品,优先把默认值放进该产品的 config 包,不要让其他产品代码直接读取它。
从旧项目迁移 env
从 Next.js 或旧项目迁过来时,不要直接复制整个 .env.local。先按新变量名映射,再确认哪些密钥会写生产资源。
| 旧变量 | 新变量 |
|---|---|
NEXT_PUBLIC_SITE_URL / BETTER_AUTH_URL | VITE_WEB_URL |
NEXT_PUBLIC_SITE_URL + /api | VITE_SERVER_URL |
NEXT_PUBLIC_GOOGLE_ANALYTICS_ID | VITE_GOOGLE_ANALYTICS_ID |
NEXT_PUBLIC_BAIDU_ANALYTICS_ID | VITE_BAIDU_ANALYTICS_ID |
NEXT_PUBLIC_UMAMI_WEBSITE_ID | VITE_UMAMI_WEBSITE_ID |
NEXT_PUBLIC_UMAMI_SCRIPT_URL | VITE_UMAMI_SCRIPT_URL |
NEXT_PUBLIC_TURNSTILE_SITE_KEY | VITE_TURNSTILE_SITE_KEY |
CAPTCHA_ENABLED | AUTH_CAPTCHA_ENABLED |
CAPTCHA_PROVIDER=turnstile | AUTH_CAPTCHA_MODE=cloudflare-turnstile |
S3_* / R2_* 用于 Drop 页面 | DROP_R2_* |
R2、S3、支付、数据库、认证密钥都可能连接真实外部服务。迁移前先确认本地命令是否允许写入这些资源。
完整环境变量列表
以下变量为项目启动所必需。
| 变量名 | 说明 | 必填 | 默认值 |
|---|---|---|---|
DATABASE_URL | PostgreSQL 连接字符串 | 是 | -- |
BETTER_AUTH_SECRET | 认证签名密钥(至少 32 位) | 是 | -- |
VITE_WEB_URL | 站点公开地址 | 是 | -- |
VITE_SERVER_URL | API 公开地址,通常是 VITE_WEB_URL/api | 是 | -- |
认证基础
| 变量名 | 说明 | 必填 | 默认值 |
|---|---|---|---|
BETTER_AUTH_SECRET | 认证签名密钥(至少 32 位) | 是 | -- |
AUTH_COOKIE_PREFIX | Better Auth cookie 前缀,产品 config 包提供默认值 | 否 | 01mvp-session |
COOKIE_DOMAIN | 跨子域 SSO Cookie 域名 | 否 | -- |
AUTH_ENABLE_EMAIL_VERIFICATION | 是否要求邮箱验证 | 否 | false |
AUTH_ENABLE_MAGIC_LINKS | 是否启用 Magic Link 登录 | 否 | false |
AUTH_ENABLE_PHONE | 是否启用手机号登录 | 否 | true |
AUTH_ENABLE_PASSKEYS | 是否启用 Passkey | 否 | true |
AUTH_ENABLE_TWO_FACTOR | 是否启用双因素认证 | 否 | true |
AUTH_ENABLE_WECHAT | 是否启用微信登录;仍需配置微信 OAuth 凭据 | 否 | false |
Google OAuth
| 变量名 | 说明 | 必填 | 默认值 |
|---|---|---|---|
GOOGLE_CLIENT_ID | Google OAuth Client ID | 否 | -- |
GOOGLE_CLIENT_SECRET | Google OAuth Client Secret | 否 | -- |
GitHub OAuth
| 变量名 | 说明 | 必填 | 默认值 |
|---|---|---|---|
GITHUB_CLIENT_ID | GitHub OAuth Client ID | 否 | -- |
GITHUB_CLIENT_SECRET | GitHub OAuth Client Secret | 否 | -- |
微信登录
微信提供三种登录方式,按需配置。
PC 网页登录
| 变量名 | 说明 | 必填 | 默认值 |
|---|---|---|---|
WECHAT_WEBSITE_APP_ID | 微信开放平台网站应用 AppID | 否 | -- |
WECHAT_WEBSITE_APP_SECRET | 微信开放平台网站应用 AppSecret | 否 | -- |
公众号登录(移动端)
| 变量名 | 说明 | 必填 | 默认值 |
|---|---|---|---|
WECHAT_SERVICE_ACCOUNT_APP_ID | 微信公众号 AppID | 否 | -- |
WECHAT_SERVICE_ACCOUNT_APP_SECRET | 微信公众号 AppSecret | 否 | -- |
登录 CAPTCHA
| 变量名 | 说明 | 必填 | 默认值 |
|---|---|---|---|
AUTH_CAPTCHA_ENABLED | 是否启用登录 CAPTCHA | 否 | false |
AUTH_CAPTCHA_MODE | off / local-pow / cloudflare-turnstile | 否 | off |
CAPTCHA_LOCAL_POW_DIFFICULTY | Local PoW 难度 | 否 | 10 |
CAPTCHA_LOCAL_POW_SECRET | Local PoW 独立签名密钥 | 否 | 复用认证密钥 |
CAPTCHA_LOCAL_POW_TTL_SECONDS | Local PoW challenge 有效期 | 否 | 120 |
TURNSTILE_SECRET_KEY | Cloudflare Turnstile 服务端密钥 | 否 | -- |
VITE_TURNSTILE_SITE_KEY | Cloudflare Turnstile 前端 site key | 否 | -- |
TURNSTILE_TIMEOUT_MS | Turnstile 校验超时 | 否 | 5000 |
TURNSTILE_ALLOWED_HOSTNAMES | 允许的 Turnstile hostname 列表 | 否 | -- |
TURNSTILE_EXPECTED_ACTION | 期望的 Turnstile action | 否 | login |
支付渠道选择
| 变量名 | 说明 | 必填 | 默认值 |
|---|---|---|---|
PAYMENT_ENABLED_CHANNELS | 逗号分隔的支付渠道 ID,如 stripe:card,zpay:alipay,zpay:wxpay。留空时启用所有密钥完整的渠道。 | 否 | -- |
Stripe
| 变量名 | 说明 | 必填 | 默认值 |
|---|---|---|---|
STRIPE_SECRET_KEY | Stripe API Secret Key | 否 | -- |
STRIPE_WEBHOOK_SECRET | Stripe Webhook 签名密钥 | 否 | -- |
ZPAY
| 变量名 | 说明 | 必填 | 默认值 |
|---|---|---|---|
ZPAY_PID | ZPAY 商户 ID | 否 | -- |
ZPAY_KEY | ZPAY 商户密钥 | 否 | -- |
ZPAY_DEFAULT_TYPE | 默认支付方式:alipay / wxpay | 否 | alipay |
ZPAY_SUBMIT_URL | ZPAY 网关地址 | 否 | -- |
ZPAY_API_URL | ZPAY API 地址 | 否 | -- |
Waffo
| 变量名 | 说明 | 必填 | 默认值 |
|---|---|---|---|
WAFFO_MERCHANT_ID | Waffo 商户 ID | 否 | -- |
WAFFO_PRIVATE_KEY | Waffo 私钥 | 否 | -- |
WAFFO_ENVIRONMENT | Waffo webhook 环境:test / prod | 否 | test |
WAFFO_DEFAULT_CURRENCY | 默认货币 | 否 | USD |
基础模型配置
| 变量名 | 说明 | 必填 | 默认值 |
|---|---|---|---|
OPENAI_API_KEY | OpenAI 兼容服务 API Key | 否 | -- |
OPENAI_BASE_URL | OpenAI 兼容服务基础 URL | 否 | https://api.deepseek.com |
OPENAI_MODEL | 模型名称 | 否 | deepseek-v4-flash |
视频生成
| 变量名 | 说明 | 必填 | 默认值 |
|---|---|---|---|
VOLCENGINE_API_KEY | 火山引擎 API Key(Seedance 视频生成) | 否 | -- |
图片/视频生成
| 变量名 | 说明 | 必填 | 默认值 |
|---|---|---|---|
QWEN_API_KEY | 通义千问 API Key(图片/视频生成) | 否 | -- |
聊天模型统一使用 OPENAI_* 三个变量。这里的 OpenAI 指 API 格式,不要求使用 OpenAI 官方服务。
Drop 功能优先使用 Cloudflare R2。未配置 R2 时,本地开发会回退到本地目录。
| 变量名 | 说明 | 必填 | 默认值 |
|---|---|---|---|
PAGES_BASE_URL | Drop 公开页面基础地址 | 否 | http://localhost:7001/drop/sites |
DROP_R2_BUCKET_NAME | R2 存储桶名称 | 否 | -- |
DROP_R2_ACCOUNT_ID | Cloudflare Account ID | 否 | -- |
DROP_R2_ENDPOINT | R2 S3 兼容 API 地址 | 否 | -- |
DROP_R2_ACCESS_KEY_ID | R2 Access Key | 否 | -- |
DROP_R2_SECRET_ACCESS_KEY | R2 Secret Key | 否 | -- |
DROP_R2_REGION | R2 区域 | 否 | auto |
DROP_LOCAL_STORAGE_DIR | 本地开发存储目录 | 否 | products/01mvp/apps/web/.data/drop-pages |
R2 写入凭证只能放在服务端环境变量里,不要加 VITE_。公开访问域名用 PAGES_BASE_URL 控制。
Cloudflare R2 示例:
PAGES_BASE_URL=https://pages.your-domain.com
DROP_R2_BUCKET_NAME=01mvp-drop-pages
DROP_R2_ACCOUNT_ID=<ACCOUNT_ID>
DROP_R2_ENDPOINT=https://<ACCOUNT_ID>.r2.cloudflarestorage.com
DROP_R2_ACCESS_KEY_ID=<ACCESS_KEY_ID>
DROP_R2_SECRET_ACCESS_KEY=<SECRET_ACCESS_KEY>
DROP_R2_REGION=auto公开上传
头像等公开上传默认写本地目录;配置对象存储后写入 S3 / R2 兼容存储。
| 变量名 | 说明 | 必填 | 默认值 |
|---|---|---|---|
PUBLIC_UPLOAD_BUCKET | 公开上传 bucket | 否 | -- |
PUBLIC_UPLOAD_R2_ACCOUNT_ID | Cloudflare Account ID | 否 | -- |
PUBLIC_UPLOAD_ENDPOINT | S3 / R2 API 地址 | 否 | -- |
PUBLIC_UPLOAD_ACCESS_KEY_ID | 上传 Access Key | 否 | -- |
PUBLIC_UPLOAD_SECRET_ACCESS_KEY | 上传 Secret Key | 否 | -- |
PUBLIC_UPLOAD_REGION | 存储区域 | 否 | auto |
PUBLIC_UPLOAD_PUBLIC_URL | 文件公开访问基础 URL | 否 | 当前站点 /api/uploads/files |
PUBLIC_UPLOAD_LOCAL_DIR | 本地上传目录 | 否 | .data/uploads |
邮件
| 变量名 | 说明 | 必填 | 默认值 |
|---|---|---|---|
ZEABUR_EMAIL_API_KEY | Zeabur 邮件服务 API Key(备选) | 否 | -- |
EMAIL_FROM | 发件人邮箱地址,产品 config 包提供默认值 | 否 | 01MVP <[email protected]> |
FEEDBACK_EMAIL_TO | 反馈表单收件人 | 否 | [email protected] |
FEEDBACK_EMAIL_FROM | 反馈表单发件人 | 否 | -- |
早期通常只配置 FEEDBACK_EMAIL_TO 就够了。需要发送反馈邮件时,再补齐 ZEABUR_EMAIL_API_KEY 和 EMAIL_FROM。
短信
| 变量名 | 说明 | 必填 | 默认值 |
|---|---|---|---|
SMS_PROVIDER | 短信厂商,可选 aliyun、tencent、twilio | 否 | aliyun |
ALIBABA_CLOUD_ACCESS_KEY_ID | 阿里云 AccessKey ID | 否 | -- |
ALIBABA_CLOUD_ACCESS_KEY_SECRET | 阿里云 AccessKey Secret | 否 | -- |
ALIYUN_SMS_REGION | 阿里云 OpenAPI 地域 | 否 | cn-hangzhou |
TENCENT_SMS_REGION | 腾讯云短信区域 | 否 | ap-guangzhou |
TENCENT_SMS_SDK_APP_ID | 腾讯云短信 SDK App ID | 否 | -- |
TENCENT_SMS_SIGN_NAME | 腾讯云短信签名 | 否 | -- |
TENCENT_SMS_TEMPLATE_ID | 腾讯云短信模板 ID | 否 | -- |
TWILIO_ACCOUNT_SID | Twilio Account SID | 否 | -- |
TWILIO_AUTH_TOKEN | Twilio Auth Token | 否 | -- |
TWILIO_FROM_PHONE_NUMBER | Twilio 发送号码 | 否 | -- |
| 变量名 | 说明 | 必填 | 默认值 |
|---|---|---|---|
AUTH_COOKIE_PREFIX | Better Auth cookie 前缀 | 否 | 01mvp-session |
COOKIE_DOMAIN | 跨子域 SSO Cookie 域名 | 否 | -- |
VITE_GOOGLE_ANALYTICS_ID | Google Analytics 4 衡量 ID,留空不加载 GA 脚本 | 否 | -- |
VITE_BAIDU_ANALYTICS_ID | 百度统计 ID | 否 | -- |
VITE_UMAMI_WEBSITE_ID | Umami Website ID | 否 | -- |
VITE_UMAMI_SCRIPT_URL | Umami 脚本地址 | 否 | https://cloud.umami.is/script.js |
TENCENT_CLOUD_SECRET_ID | 腾讯云 Secret ID(内容审核/短信) | 否 | -- |
TENCENT_CLOUD_SECRET_KEY | 腾讯云 Secret Key(内容审核/短信) | 否 | -- |
ENABLE_OPEN_API_DOCS | 是否开放 OpenAPI 文档端点 | 否 | false |
HEALTH_CHECK_DATABASE | 健康检查是否检查数据库 | 否 | true |
HEALTH_CHECK_TIMEOUT_MS | 健康检查超时 | 否 | 1500 |
SOURCE_COMMIT | 构建注入的 Git commit SHA | 否 | unknown |
AI 默认值说明
聊天模型使用 OpenAI-compatible 接口。只要服务商兼容 Chat Completions 格式,就可以通过 OPENAI_BASE_URL 和 OPENAI_MODEL 切换。未配置时默认使用 DeepSeek:https://api.deepseek.com 和 deepseek-v4-flash。
Feature Flags
主要功能开关集中在环境变量 schema 和对应功能包中:
- 认证 --
AUTH_ENABLE_MAGIC_LINKS、AUTH_ENABLE_PHONE、AUTH_ENABLE_PASSKEYS、AUTH_ENABLE_TWO_FACTOR - OpenAPI --
ENABLE_OPEN_API_DOCS - 登录 CAPTCHA --
AUTH_CAPTCHA_ENABLED、AUTH_CAPTCHA_MODE - AI 积分 --
CHAT_CREDITS_ENABLED、AI_MEDIA_CREDITS_ENABLED - 支付渠道 --
PAYMENT_ENABLED_CHANNELS配合 Stripe / ZPAY / Waffo 密钥
修改对应字段后重启开发服务器生效。
按功能查看
以下表格帮助你快速找到启用某个功能所需的变量。
| 功能 | 必需变量 | 可选变量 |
|---|---|---|
| 基础启动 | DATABASE_URL, BETTER_AUTH_SECRET, VITE_WEB_URL, VITE_SERVER_URL | AUTH_COOKIE_PREFIX, COOKIE_DOMAIN |
| Google 登录 | GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET | -- |
| GitHub 登录 | GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET | -- |
| 微信 PC 登录 | AUTH_ENABLE_WECHAT=true, WECHAT_WEBSITE_APP_ID, WECHAT_WEBSITE_APP_SECRET | -- |
| 微信公众号登录 | AUTH_ENABLE_WECHAT=true, WECHAT_SERVICE_ACCOUNT_APP_ID, WECHAT_SERVICE_ACCOUNT_APP_SECRET | -- |
| 登录 CAPTCHA | AUTH_CAPTCHA_ENABLED, AUTH_CAPTCHA_MODE | VITE_TURNSTILE_SITE_KEY, TURNSTILE_SECRET_KEY |
| Stripe 支付 | STRIPE_SECRET_KEY, PAYMENT_ENABLED_CHANNELS=stripe:card | STRIPE_WEBHOOK_SECRET |
| ZPAY 支付 | ZPAY_PID, ZPAY_KEY, PAYMENT_ENABLED_CHANNELS=zpay:alipay | ZPAY_DEFAULT_TYPE, ZPAY_SUBMIT_URL, ZPAY_API_URL |
| Waffo 支付 | WAFFO_MERCHANT_ID, WAFFO_PRIVATE_KEY, PAYMENT_ENABLED_CHANNELS=waffo:default | WAFFO_ENVIRONMENT, WAFFO_DEFAULT_CURRENCY |
| AI 对话 | OPENAI_API_KEY | OPENAI_BASE_URL, OPENAI_MODEL |
| 视频生成 | VOLCENGINE_API_KEY | -- |
| Drop 页面存储 | DROP_R2_BUCKET_NAME, DROP_R2_ENDPOINT, DROP_R2_ACCESS_KEY_ID, DROP_R2_SECRET_ACCESS_KEY | PAGES_BASE_URL, DROP_LOCAL_STORAGE_DIR |
| 公开上传 | PUBLIC_UPLOAD_BUCKET, PUBLIC_UPLOAD_ENDPOINT, PUBLIC_UPLOAD_ACCESS_KEY_ID, PUBLIC_UPLOAD_SECRET_ACCESS_KEY | PUBLIC_UPLOAD_PUBLIC_URL, PUBLIC_UPLOAD_LOCAL_DIR |
| 邮件 | ZEABUR_EMAIL_API_KEY, EMAIL_FROM | FEEDBACK_EMAIL_TO, FEEDBACK_EMAIL_FROM |
| 短信 | SMS_PROVIDER=aliyun, ALIBABA_CLOUD_ACCESS_KEY_ID, ALIBABA_CLOUD_ACCESS_KEY_SECRET | ALIYUN_SMS_REGION |
安全提醒
不要将包含密钥的环境变量文件提交到 Git。 products/01mvp/packages/config/.env 和 packages/config/.env 都应保持未提交。生产环境通过部署平台的环境变量面板管理,例如 Cloudflare Workers Secrets 或 Zeabur Variables。
区分公钥和私钥变量。 以 VITE_ 开头的变量会打包到客户端代码中,任何敏感信息(Secret Key、Private Key)都不应使用此前缀。
这篇文档有问题?