vtex-io-app-settings
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseApp Settings & Configuration Boundaries
应用设置与配置边界
When this skill applies
适用场景
Use this skill when deciding or implementing how a VTEX IO app should expose configurable settings.
- Defining
settingsSchema - Adding merchant-configurable app behavior
- Reviewing whether configuration belongs in app settings or custom data
- Reading and validating settings in app code
Do not use this skill for:
- runtime infrastructure settings in
service.json - Master Data entity design
- policy declaration details
- route auth modeling
当你需要决策或实现VTEX IO应用对外暴露可配置设置的方案时,可参考本指南:
- 定义
settingsSchema - 实现商户可配置的应用行为
- 判断配置应该归属于应用设置还是自定义数据
- 在应用代码中读取和验证设置
本指南不适用于以下场景:
- 中的运行时基础设施设置
service.json - Master Data实体设计
- 策略声明细节
- 路由鉴权模型设计
Decision rules
决策规则
- Use app settings for stable configuration that merchants or operators should be able to manage explicitly.
- Use for app-level configuration managed through VTEX Admin, and use
settingsSchemafor Store Framework block configuration that varies by page or block instance.store/contentSchemas.json - If the value is global for the app or account, it usually belongs in . If it varies per page, block, or theme composition, it usually belongs in
settingsSchema.contentSchemas.json - Do not use app settings as a substitute for high-volume operational data storage.
- Use JSON Schema explicitly with ,
properties,required,default,enum, and related constraints instead of a generic rootformatonly.type: object - Use only for non-sensitive values that are intentionally safe to expose to frontend code through
settingsSchema.access: "public".publicSettingsForApp - If is omitted, do not assume frontend GraphQL consumers can read the settings. Public frontend access must be an explicit choice.
access - Use app settings for API keys, tokens, and secrets instead of hardcoding them in the codebase.
- Never expose secrets from app settings directly in HTTP responses, GraphQL responses, HTML, or browser-side props.
- Never expose secrets from app settings in logs either.
- For sensitive fields such as API keys or passwords, keep them as and consider marking them with
type: "string". Some platform consumers, such as Apps GraphQL when usingformat: "password", may use this metadata to mask values in responses. Do not rely on this as the only security layer: secrets must still be treated as backend-only and never exposed in responses or logs.hidePasswords - UI-specific hints such as may be supported by some renderers, but they are not part of the core JSON Schema guarantees. Do not assume the standard VTEX Admin App Settings UI will enforce them.
ui:widget: "password" - Read backend settings through and centralize normalization or validation in a helper instead of spreading ad hoc access patterns through handlers.
ctx.clients.apps.getAppSettings(ctx.vtex.appId ?? process.env.VTEX_APP_ID) - When reading or saving this app's own settings at runtime, use the correct app identifier such as or
process.env.VTEX_APP_IDand rely on the app token plus standard app-settings permissions. Do not declare extra License Manager policies inctx.vtex.appIdor add workspace-wide policies such asmanifest.jsonor undocumented policies such asread-workspace-appsjust to "fix" a 403.write-workspace-apps - Pixel apps that need configuration should also consume settings through on the backend side of the pixel app. If a value must be available to injected JavaScript, expose only non-sensitive fields through
ctx.clients.apps.getAppSettings(...)andaccess: "public", keeping secrets strictly on the server side.publicSettingsForApp - Make code resilient to missing or incomplete settings by validating or applying defaults at the consumption boundary.
- Never assume settings are identical across accounts or workspaces. Each workspace may have different app configuration during development, rollout, or debugging.
Settings vs configuration builder:
- Use when the configuration is specific to this app and the merchant is expected to edit it in Apps > App Settings.
settingsSchema - Consider a separate app using the builder when the configuration contract needs to be shared across multiple apps, managed separately from the runtime app lifecycle, or injected directly into service context through
configuration.ctx.vtex.settings - Prefer a configuration app when the main goal is structured service configuration delivered through VTEX IO runtime context, instead of settings fetched ad hoc by the app itself.
- 应用设置用于存放商户或运营人员需要显式管理的稳定配置项。
- 通过VTEX Admin管理的应用级配置使用定义,随页面或块实例变化的Store Framework块配置使用
settingsSchema定义。store/contentSchemas.json - 如果配置值对应用或账号是全局通用的,通常应该放在中;如果配置值随页面、块或主题组合变化,通常应该放在
settingsSchema中。contentSchemas.json - 不要将应用设置用作高体量运营数据的存储方案。
- 显式使用JSON Schema的、
properties、required、default、enum等约束字段,不要只定义泛型的根级别format。type: object - 仅当非敏感值需要通过安全暴露给前端代码时,才将
publicSettingsForApp设置为settingsSchema.access。"public" - 如果未声明,不要假设前端GraphQL消费者可以读取设置,前端公共访问权限必须显式声明。
access - API密钥、令牌、密钥等敏感信息要存放在应用设置中,不要硬编码在代码库中。
- 绝对不要直接在HTTP响应、GraphQL响应、HTML或浏览器端props中暴露应用设置里的密钥。
- 也绝对不要在日志中暴露应用设置里的密钥。
- 对于API密钥或密码等敏感字段,将其类型设置为,并考虑标记
type: "string"。部分平台消费者(比如开启format: "password"的Apps GraphQL)会使用该元数据在响应中屏蔽敏感值,但不要将其作为唯一的安全层:密钥仍然应该仅在后端使用,永远不要暴露在响应或日志中。hidePasswords - 部分渲染器可能支持这类UI专属提示,但它们不属于JSON Schema的核心保障范围,不要假设标准VTEX Admin应用设置UI会强制执行这些规则。
ui:widget: "password" - 后端通过读取设置,将配置的归一化或验证逻辑集中在工具函数中,不要在处理器中分散使用临时的访问逻辑。
ctx.clients.apps.getAppSettings(ctx.vtex.appId ?? process.env.VTEX_APP_ID) - 运行时读取或保存应用自身的设置时,使用正确的应用标识符(比如或
process.env.VTEX_APP_ID),依赖应用令牌和标准的应用设置权限即可。不要为了“修复”403错误就在ctx.vtex.appId中声明额外的License Manager策略,也不要添加manifest.json这类工作区级别的策略,或者read-workspace-apps这类非公开策略。write-workspace-apps - 需要配置的Pixel应用也应该在后端通过读取设置。如果某个值需要提供给注入的JavaScript使用,仅通过
ctx.clients.apps.getAppSettings(...)和access: "public"暴露非敏感字段,密钥必须严格保留在服务端。publicSettingsForApp - 在配置使用边界对设置进行验证或应用默认值,让代码能够适配缺失或不完整的配置。
- 永远不要假设配置在不同账号或工作空间中是一致的,开发、灰度或调试阶段,每个工作空间可能有不同的应用配置。
Hard constraints
应用设置 vs 配置构建器:
Constraint: Configurable app behavior must have a schema
—
Merchant-configurable settings MUST be modeled through an explicit schema instead of ad hoc unvalidated objects.
Why this matters
Without a schema, configuration becomes ambiguous, harder to validate, and easier to break across environments.
Detection
If code depends on app-level configuration but no schema or validation contract exists, STOP and define it first.
Correct
json
{
"settingsSchema": {
"title": "My App Settings",
"type": "object",
"properties": {
"enableModeration": {
"title": "Enable moderation",
"type": "boolean",
"default": false,
"description": "If true, new content will require approval before going live."
},
"apiKey": {
"title": "External API key",
"type": "string",
"minLength": 1,
"description": "API key for the external moderation service.",
"format": "password"
},
"mode": {
"title": "Mode",
"type": "string",
"enum": ["sandbox", "production"],
"default": "sandbox"
}
},
"required": ["apiKey"]
}
}Wrong
typescript
const settings = ctx.state.anything- 当配置是当前应用专属,且商户需要在「应用 > 应用设置」中编辑时,使用。
settingsSchema - 当配置协议需要在多个应用间共享、需要与运行时应用生命周期分开管理,或者需要通过直接注入到服务上下文时,可以开发单独的应用使用
ctx.vtex.settings构建器实现。configuration - 如果核心需求是通过VTEX IO运行时上下文提供结构化的服务配置,而非应用自行拉取配置,优先使用配置应用。
Constraint: Sensitive settings must stay backend-only and must not be exposed to the frontend
硬性约束
—
约束:可配置的应用行为必须有对应的Schema
Secrets stored in app settings such as API keys, tokens, or passwords MUST be treated as backend-only configuration.
Why this matters
App settings are a natural place for secrets, but exposing them in HTTP responses, GraphQL payloads, HTML, or frontend props turns configuration into a security leak.
Detection
If a route, resolver, or frontend-facing response returns raw settings or includes sensitive fields from settings, STOP and move the external call or secret usage fully to the backend boundary.
Correct
typescript
const { apiKey } = await ctx.clients.apps.getAppSettings(
ctx.vtex.appId ?? process.env.VTEX_APP_ID
)
const result = await externalClient.fetchData({ apiKey })
ctx.body = resultWrong
typescript
const settings = await ctx.clients.apps.getAppSettings(
ctx.vtex.appId ?? process.env.VTEX_APP_ID
)
ctx.body = settings商户可配置的设置必须通过显式Schema定义,不能使用未验证的临时对象。
重要性
没有Schema的配置会变得模棱两可、更难验证,也更容易在不同环境中出现问题。
检查方式
如果代码依赖应用级配置,但没有对应的Schema或验证协议,立即停止开发,先定义好配置Schema。
正确示例
json
{
"settingsSchema": {
"title": "My App Settings",
"type": "object",
"properties": {
"enableModeration": {
"title": "Enable moderation",
"type": "boolean",
"default": false,
"description": "If true, new content will require approval before going live."
},
"apiKey": {
"title": "External API key",
"type": "string",
"minLength": 1,
"description": "API key for the external moderation service.",
"format": "password"
},
"mode": {
"title": "Mode",
"type": "string",
"enum": ["sandbox", "production"],
"default": "sandbox"
}
},
"required": ["apiKey"]
}
}错误示例
typescript
const settings = ctx.state.anythingConstraint: Public app settings access must never expose sensitive configuration
约束:敏感设置必须仅在后端使用,不得暴露给前端
If is set to , the exposed settings MUST contain only values that are safe to ship to frontend code through .
settingsSchema.accesspublicpublicSettingsForAppWhy this matters
access: "public"Detection
If a settings schema marks access as public and includes API keys, tokens, passwords, or any value intended only for backend integrations, STOP and keep those settings private.
Correct
json
{
"settingsSchema": {
"title": "Public Storefront Settings",
"type": "object",
"access": "public",
"properties": {
"bannerText": {
"title": "Banner text",
"type": "string"
}
}
}
}Wrong
json
{
"settingsSchema": {
"title": "My App Settings",
"type": "object",
"access": "public",
"properties": {
"apiKey": {
"title": "External API key",
"type": "string",
"format": "password"
}
}
}
}应用设置中存储的API密钥、令牌、密码等密钥必须作为后端专属配置处理。
重要性
应用设置是存储密钥的合理位置,但如果将其暴露在HTTP响应、GraphQL payload、HTML或前端props中,会导致配置信息泄露,产生安全风险。
检查方式
如果路由、解析器或面向前端的响应返回了原始设置,或者包含设置中的敏感字段,立即停止开发,将外部调用或密钥的使用逻辑完全移到后端边界内。
正确示例
typescript
const { apiKey } = await ctx.clients.apps.getAppSettings(
ctx.vtex.appId ?? process.env.VTEX_APP_ID
)
const result = await externalClient.fetchData({ apiKey })
ctx.body = result错误示例
typescript
const settings = await ctx.clients.apps.getAppSettings(
ctx.vtex.appId ?? process.env.VTEX_APP_ID
)
ctx.body = settingsConstraint: Settings must not be used as operational data storage
约束:公共应用设置访问绝对不能暴露敏感配置
App settings MUST represent configuration, not high-volume mutable records.
Why this matters
Settings are for configuration boundaries, not for transactional or large-scale operational data.
Detection
If a proposed setting stores records that behave like orders, reviews, logs, or queue items, STOP and move that concern to a more appropriate data mechanism.
Correct
json
{
"enableModeration": true
}Wrong
json
{
"allReviews": []
}如果设置为,暴露的设置只能包含可以安全通过发送给前端代码的值。
settingsSchema.accesspublicpublicSettingsForApp重要性
是一种分发配置的选择,而非安全控制手段。一旦设置被公开暴露,门店前端或前端代码都可以读取,因此密钥和后端专属配置绝对不能包含在公共设置中。
access: "public"检查方式
如果设置Schema标记了公开访问,但包含API密钥、令牌、密码或任何仅用于后端集成的值,立即停止开发,将这些设置改为私有。
正确示例
json
{
"settingsSchema": {
"title": "Public Storefront Settings",
"type": "object",
"access": "public",
"properties": {
"bannerText": {
"title": "Banner text",
"type": "string"
}
}
}
}错误示例
json
{
"settingsSchema": {
"title": "My App Settings",
"type": "object",
"access": "public",
"properties": {
"apiKey": {
"title": "External API key",
"type": "string",
"format": "password"
}
}
}
}Constraint: Code must validate or default settings at the consumption boundary
约束:不得将设置用作运营数据存储
Settings-dependent code MUST tolerate missing or incomplete values safely.
Why this matters
Configuration can drift across workspaces and accounts. Code that assumes every setting is present becomes fragile.
Detection
If code reads settings and assumes required fields always exist with no validation or defaults, STOP and make the dependency explicit.
Correct
typescript
const rawSettings = await ctx.clients.apps.getAppSettings(
ctx.vtex.appId ?? process.env.VTEX_APP_ID
)
const settings = normalizeSettings(rawSettings)
const enabled = settings.enableModeration ?? falseWrong
typescript
const enabled = settings.enableModeration.value应用设置必须用于存储配置,而非高体量的可变记录。
重要性
设置是用于配置边界的,不适用于事务性或大规模运营数据的存储。
检查方式
如果拟新增的设置用于存储订单、评论、日志、队列项这类记录,立即停止开发,将这类数据迁移到更合适的数据存储机制中。
正确示例
json
{
"enableModeration": true
}错误示例
json
{
"allReviews": []
}Preferred pattern
约束:代码必须在使用边界对设置进行验证或设置默认值
Use settings for stable, merchant-managed configuration, define them with explicit JSON Schema properties, and validate or normalize them where they are consumed.
For secrets, keep the read and the external call on the backend and return only the business result to the frontend.
Use frontend GraphQL access only for intentionally public settings, and keep backend-only settings behind .
getAppSettings(...)依赖设置的代码必须能够安全地处理缺失或不完整的配置值。
重要性
配置在不同工作空间和账号中可能存在差异,假设所有设置都一定存在的代码稳定性会很差。
检查方式
如果代码读取设置后,假设必填字段一定存在,没有做验证或者设置默认值,立即停止开发,显式声明配置依赖规则。
正确示例
typescript
const rawSettings = await ctx.clients.apps.getAppSettings(
ctx.vtex.appId ?? process.env.VTEX_APP_ID
)
const settings = normalizeSettings(rawSettings)
const enabled = settings.enableModeration ?? false错误示例
typescript
const enabled = settings.enableModeration.valueCommon failure modes
推荐模式
- Using settings as operational storage.
- Using only without explicit
type: objectand validation details.properties - Reading settings without defaults or validation.
- Exposing raw settings or secrets to the frontend.
- Marking settings as when they contain backend-only or sensitive values.
access: "public" - Logging settings or secrets in plain text.
- Hardcoding API keys or tokens instead of storing them in app settings.
- Adding workspace-level policies such as or invalid policies such as
read-workspace-appsas a generic workaround for app settings permission errors, instead of validating the correct appId and standard app-settings permissions.write-workspace-apps - Using when the requirement is really block-level Store Framework configuration.
settingsSchema - Creating schemas that are too broad or vague.
将应用设置用于稳定的、由商户管理的配置,通过显式的JSON Schema属性定义配置,在使用配置的位置对其进行验证或归一化处理。
对于密钥,将读取逻辑和外部调用都放在后端,仅将业务结果返回给前端。
仅对故意公开的设置开放前端GraphQL访问权限,后端专属设置通过读取。
getAppSettings(...)Review checklist
常见错误模式
- Does this data really belong in app settings?
- Does the declare explicit
settingsSchemawith clear types andpropertiesonly where necessary?required - Are sensitive fields represented safely, for example as fields with
string, knowing that some consumers such as Apps GraphQL withformat: "password"may use that metadata to mask the output?hidePasswords - Does the consuming code validate or default missing values?
- Are secrets kept backend-only and never exposed to the frontend?
- If is used, are all exposed settings intentionally safe for frontend consumption?
access: "public" - Is the settings surface small and intentional?
- 将设置用作运营存储。
- 仅定义,没有显式声明
type: object和验证细节。properties - 读取设置时没有设置默认值或做验证。
- 将原始设置或密钥暴露给前端。
- 当设置包含后端专属或敏感值时,仍然标记。
access: "public" - 以明文形式记录设置或密钥日志。
- 硬编码API密钥或令牌,而非存储在应用设置中。
- 为了临时解决应用设置权限错误,添加这类工作区级别的策略,或者
read-workspace-apps这类无效策略,而不是校验正确的appId和标准应用设置权限。write-workspace-apps - 当需求实际上是块级别的Store Framework配置时,错误使用。
settingsSchema - 定义的Schema过于宽泛或模糊。
Reference
审核Checklist
- Manifest - App configuration contract
- Creating an interface for your app settings - ,
settingsSchema, frontend queries, and backend settings consumptionaccess - Configuring your app settings - Pixel app example for consuming app settings in VTEX IO
- 该数据确实适合存放在应用设置中吗?
- 是否声明了显式的
settingsSchema,带有清晰的类型,仅在必要时标记properties?required - 敏感字段是否做了安全处理?比如设置为类型并标记
string,同时知晓开启format: "password"的Apps GraphQL这类消费者可能会使用该元数据屏蔽输出?hidePasswords - 配置使用代码是否对缺失的值做了验证或设置了默认值?
- 密钥是否仅在后端使用,永远不会暴露给前端?
- 如果使用了,所有暴露的设置是否确实可以安全地提供给前端使用?
access: "public" - 设置的暴露范围是否足够小且符合预期?
—
参考资料
—
- Manifest - 应用配置协议
- 为应用设置创建交互界面 - 、
settingsSchema、前端查询和后端设置使用指南access - 配置应用设置 - 在VTEX IO中使用应用设置的Pixel应用示例