00 / 00

配置体系

环境变量、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 32

VITE_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/.envpackages/config/.env 都不要提交到 Git。生产环境通过部署平台的环境变量面板管理。

修改环境变量后需要重启 vpr @01mvp/product#dev 才会生效,TanStack Start 不会热加载环境变量的变化。另外,只有以 VITE_ 开头的变量才会暴露给浏览器端代码。

配置系统说明

共享环境变量 schema 位于 packages/config/src/server/env.tspackages/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.example01MVP 产品默认值和产品级变量示例
products/01mvp/packages/config/.env01MVP 本机开发真实值,优先级最高
packages/config/.env多产品共享的本机兜底值
products/01mvp/packages/config01MVP 产品默认值和产品级 env 包
products/onesay/packages/configOneSay 产品默认值和产品级 env 包
部署平台 Variables / Secrets生产、预发等环境真实值平台托管

以后 monorepo 增加新的产品时,先判断变量属于共享平台能力还是产品能力。共享变量定义放在 packages/config,产品默认值和产品级 .env.example 放在 products/<product>/packages/config

本地脚本按下面顺序加载 env:产品 env 优先,shared env 作为兜底。这样 VITE_WEB_URLVITE_SERVER_URLEMAIL_FROMAUTH_COOKIE_PREFIX 这类同名变量可以按产品覆盖。

products/<product>/packages/config/.env
packages/config/.env

01MVP 项目初始化时,优先复制对应产品的示例文件:

cp products/01mvp/packages/config/.env.example products/01mvp/packages/config/.env

如果一个变量只属于某个产品,优先把默认值放进该产品的 config 包,不要让其他产品代码直接读取它。

从旧项目迁移 env

从 Next.js 或旧项目迁过来时,不要直接复制整个 .env.local。先按新变量名映射,再确认哪些密钥会写生产资源。

旧变量新变量
NEXT_PUBLIC_SITE_URL / BETTER_AUTH_URLVITE_WEB_URL
NEXT_PUBLIC_SITE_URL + /apiVITE_SERVER_URL
NEXT_PUBLIC_GOOGLE_ANALYTICS_IDVITE_GOOGLE_ANALYTICS_ID
NEXT_PUBLIC_BAIDU_ANALYTICS_IDVITE_BAIDU_ANALYTICS_ID
NEXT_PUBLIC_UMAMI_WEBSITE_IDVITE_UMAMI_WEBSITE_ID
NEXT_PUBLIC_UMAMI_SCRIPT_URLVITE_UMAMI_SCRIPT_URL
NEXT_PUBLIC_TURNSTILE_SITE_KEYVITE_TURNSTILE_SITE_KEY
CAPTCHA_ENABLEDAUTH_CAPTCHA_ENABLED
CAPTCHA_PROVIDER=turnstileAUTH_CAPTCHA_MODE=cloudflare-turnstile
S3_* / R2_* 用于 Drop 页面DROP_R2_*

R2、S3、支付、数据库、认证密钥都可能连接真实外部服务。迁移前先确认本地命令是否允许写入这些资源。

完整环境变量列表

以下变量为项目启动所必需。

变量名说明必填默认值
DATABASE_URLPostgreSQL 连接字符串--
BETTER_AUTH_SECRET认证签名密钥(至少 32 位)--
VITE_WEB_URL站点公开地址--
VITE_SERVER_URLAPI 公开地址,通常是 VITE_WEB_URL/api--

认证基础

变量名说明必填默认值
BETTER_AUTH_SECRET认证签名密钥(至少 32 位)--
AUTH_COOKIE_PREFIXBetter 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是否启用 Passkeytrue
AUTH_ENABLE_TWO_FACTOR是否启用双因素认证true
AUTH_ENABLE_WECHAT是否启用微信登录;仍需配置微信 OAuth 凭据false

Google OAuth

变量名说明必填默认值
GOOGLE_CLIENT_IDGoogle OAuth Client ID--
GOOGLE_CLIENT_SECRETGoogle OAuth Client Secret--

GitHub OAuth

变量名说明必填默认值
GITHUB_CLIENT_IDGitHub OAuth Client ID--
GITHUB_CLIENT_SECRETGitHub 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是否启用登录 CAPTCHAfalse
AUTH_CAPTCHA_MODEoff / local-pow / cloudflare-turnstileoff
CAPTCHA_LOCAL_POW_DIFFICULTYLocal PoW 难度10
CAPTCHA_LOCAL_POW_SECRETLocal PoW 独立签名密钥复用认证密钥
CAPTCHA_LOCAL_POW_TTL_SECONDSLocal PoW challenge 有效期120
TURNSTILE_SECRET_KEYCloudflare Turnstile 服务端密钥--
VITE_TURNSTILE_SITE_KEYCloudflare Turnstile 前端 site key--
TURNSTILE_TIMEOUT_MSTurnstile 校验超时5000
TURNSTILE_ALLOWED_HOSTNAMES允许的 Turnstile hostname 列表--
TURNSTILE_EXPECTED_ACTION期望的 Turnstile actionlogin

支付渠道选择

变量名说明必填默认值
PAYMENT_ENABLED_CHANNELS逗号分隔的支付渠道 ID,如 stripe:card,zpay:alipay,zpay:wxpay。留空时启用所有密钥完整的渠道。--

Stripe

变量名说明必填默认值
STRIPE_SECRET_KEYStripe API Secret Key--
STRIPE_WEBHOOK_SECRETStripe Webhook 签名密钥--

ZPAY

变量名说明必填默认值
ZPAY_PIDZPAY 商户 ID--
ZPAY_KEYZPAY 商户密钥--
ZPAY_DEFAULT_TYPE默认支付方式:alipay / wxpayalipay
ZPAY_SUBMIT_URLZPAY 网关地址--
ZPAY_API_URLZPAY API 地址--

Waffo

变量名说明必填默认值
WAFFO_MERCHANT_IDWaffo 商户 ID--
WAFFO_PRIVATE_KEYWaffo 私钥--
WAFFO_ENVIRONMENTWaffo webhook 环境:test / prodtest
WAFFO_DEFAULT_CURRENCY默认货币USD

基础模型配置

变量名说明必填默认值
OPENAI_API_KEYOpenAI 兼容服务 API Key--
OPENAI_BASE_URLOpenAI 兼容服务基础 URLhttps://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_URLDrop 公开页面基础地址http://localhost:7001/drop/sites
DROP_R2_BUCKET_NAMER2 存储桶名称--
DROP_R2_ACCOUNT_IDCloudflare Account ID--
DROP_R2_ENDPOINTR2 S3 兼容 API 地址--
DROP_R2_ACCESS_KEY_IDR2 Access Key--
DROP_R2_SECRET_ACCESS_KEYR2 Secret Key--
DROP_R2_REGIONR2 区域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_IDCloudflare Account ID--
PUBLIC_UPLOAD_ENDPOINTS3 / 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_KEYZeabur 邮件服务 API Key(备选)--
EMAIL_FROM发件人邮箱地址,产品 config 包提供默认值01MVP <[email protected]>
FEEDBACK_EMAIL_TO反馈表单收件人[email protected]
FEEDBACK_EMAIL_FROM反馈表单发件人--

早期通常只配置 FEEDBACK_EMAIL_TO 就够了。需要发送反馈邮件时,再补齐 ZEABUR_EMAIL_API_KEYEMAIL_FROM

短信

变量名说明必填默认值
SMS_PROVIDER短信厂商,可选 aliyuntencenttwilioaliyun
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_SIDTwilio Account SID--
TWILIO_AUTH_TOKENTwilio Auth Token--
TWILIO_FROM_PHONE_NUMBERTwilio 发送号码--
变量名说明必填默认值
AUTH_COOKIE_PREFIXBetter Auth cookie 前缀01mvp-session
COOKIE_DOMAIN跨子域 SSO Cookie 域名--
VITE_GOOGLE_ANALYTICS_IDGoogle Analytics 4 衡量 ID,留空不加载 GA 脚本--
VITE_BAIDU_ANALYTICS_ID百度统计 ID--
VITE_UMAMI_WEBSITE_IDUmami Website ID--
VITE_UMAMI_SCRIPT_URLUmami 脚本地址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 SHAunknown

AI 默认值说明

聊天模型使用 OpenAI-compatible 接口。只要服务商兼容 Chat Completions 格式,就可以通过 OPENAI_BASE_URLOPENAI_MODEL 切换。未配置时默认使用 DeepSeek:https://api.deepseek.comdeepseek-v4-flash

Feature Flags

主要功能开关集中在环境变量 schema 和对应功能包中:

  • 认证 -- AUTH_ENABLE_MAGIC_LINKSAUTH_ENABLE_PHONEAUTH_ENABLE_PASSKEYSAUTH_ENABLE_TWO_FACTOR
  • OpenAPI -- ENABLE_OPEN_API_DOCS
  • 登录 CAPTCHA -- AUTH_CAPTCHA_ENABLEDAUTH_CAPTCHA_MODE
  • AI 积分 -- CHAT_CREDITS_ENABLEDAI_MEDIA_CREDITS_ENABLED
  • 支付渠道 -- PAYMENT_ENABLED_CHANNELS 配合 Stripe / ZPAY / Waffo 密钥

修改对应字段后重启开发服务器生效。

按功能查看

以下表格帮助你快速找到启用某个功能所需的变量。

功能必需变量可选变量
基础启动DATABASE_URL, BETTER_AUTH_SECRET, VITE_WEB_URL, VITE_SERVER_URLAUTH_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--
登录 CAPTCHAAUTH_CAPTCHA_ENABLED, AUTH_CAPTCHA_MODEVITE_TURNSTILE_SITE_KEY, TURNSTILE_SECRET_KEY
Stripe 支付STRIPE_SECRET_KEY, PAYMENT_ENABLED_CHANNELS=stripe:cardSTRIPE_WEBHOOK_SECRET
ZPAY 支付ZPAY_PID, ZPAY_KEY, PAYMENT_ENABLED_CHANNELS=zpay:alipayZPAY_DEFAULT_TYPE, ZPAY_SUBMIT_URL, ZPAY_API_URL
Waffo 支付WAFFO_MERCHANT_ID, WAFFO_PRIVATE_KEY, PAYMENT_ENABLED_CHANNELS=waffo:defaultWAFFO_ENVIRONMENT, WAFFO_DEFAULT_CURRENCY
AI 对话OPENAI_API_KEYOPENAI_BASE_URL, OPENAI_MODEL
视频生成VOLCENGINE_API_KEY--
Drop 页面存储DROP_R2_BUCKET_NAME, DROP_R2_ENDPOINT, DROP_R2_ACCESS_KEY_ID, DROP_R2_SECRET_ACCESS_KEYPAGES_BASE_URL, DROP_LOCAL_STORAGE_DIR
公开上传PUBLIC_UPLOAD_BUCKET, PUBLIC_UPLOAD_ENDPOINT, PUBLIC_UPLOAD_ACCESS_KEY_ID, PUBLIC_UPLOAD_SECRET_ACCESS_KEYPUBLIC_UPLOAD_PUBLIC_URL, PUBLIC_UPLOAD_LOCAL_DIR
邮件ZEABUR_EMAIL_API_KEY, EMAIL_FROMFEEDBACK_EMAIL_TO, FEEDBACK_EMAIL_FROM
短信SMS_PROVIDER=aliyun, ALIBABA_CLOUD_ACCESS_KEY_ID, ALIBABA_CLOUD_ACCESS_KEY_SECRETALIYUN_SMS_REGION

安全提醒

不要将包含密钥的环境变量文件提交到 Git。 products/01mvp/packages/config/.envpackages/config/.env 都应保持未提交。生产环境通过部署平台的环境变量面板管理,例如 Cloudflare Workers Secrets 或 Zeabur Variables。

区分公钥和私钥变量。VITE_ 开头的变量会打包到客户端代码中,任何敏感信息(Secret Key、Private Key)都不应使用此前缀。

这篇文档有问题?