원클릭으로
add-env-var
Step-by-step checklist for adding a new NEXT_PUBLIC_* environment variable. Use when introducing any new runtime env var.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Step-by-step checklist for adding a new NEXT_PUBLIC_* environment variable. Use when introducing any new runtime env var.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Create or finalize a pull request — three modes: placeholder draft PR at spec time, finalize a draft into ready-for-review, or a regular PR right away for work done outside the task workflow.
Grill a product task (GitHub issue) into an implementable spec — research first, then a one-question-at-a-time interview; also elaborates sub-specs for deferred subtasks of large tasks.
Execute a product-task spec one leaf subtask per run — [agent] subtasks via the project skills, [human] subtasks handed off to the developer.
Convert the current conversation into a product-task spec in .agents/tasks/, or update an existing spec — folding in new decisions, harvesting colleague replies from Slack threads, and sending open questions to their owners. Use at the end of a grilling session, when the user wants to capture any conversation as a spec, or to sync a spec's open questions with Slack.
Declare new API resource(s) in an existing API service. Use whenever the app needs to call an endpoint that has no `service:name` resource yet.
Scaffold a new page (index / detail / general) and optionally wire it to API data. Use when adding any new route to the app, or when wiring API data into an already-scaffolded page (one with `TODO (api-data):` markers).
| name | add-env-var |
| description | Step-by-step checklist for adding a new NEXT_PUBLIC_* environment variable. Use when introducing any new runtime env var. |
Read .agents/rules/env-vars.mdc first for background: how runtime delivery
works, how the config object is structured, the three value types
(primitive / JSON-encoded / JSON config URL), and where validation lives. This
skill is the checklist; the rule is the concept doc.
Three answers drive every step below. Settle them first.
Value type (see env-vars.mdc § "Value types"):
_URL.External URL? Does the value point to a third-party host (image, JSON payload, HTTP endpoint)? If yes → CSP and download-script considerations apply (see Step 4).
Mode — Does the variable apply in the default mode, multichain mode, or both? This decides which validator schema(s) you touch.
docs/ENVS.mdAdd a row in the section that mirrors where the variable's config lives:
App configuration / APIs configuration / App shell / Slices / Features /
External services / Misc. The doc sections mirror src/config/index.ts.
Fill in: name, type, description, required/optional, default, example.
Set the Version column to upcoming. The release process replaces this
with the actual version number when the change ships.
Why this is mandatory: collect_envs.sh scans docs/ENVS.md for
NEXT_PUBLIC_* names to emit .env.registry, which gates what
make_envs_script.sh writes into window.__envs. An undocumented variable
never reaches the browser.
Find the matching sub-config:
src/<area>/<name>/config.ts.app, apis, chain, misc, metadata): src/config/<area>.ts.Read the value with the helper that matches its type:
getEnvValue('NEXT_PUBLIC_…'); cast at the call site
(=== 'true', Number(…), …).parseEnvJson<T>(getEnvValue('NEXT_PUBLIC_…')) with a
fallback (returns null on parse failure).getExternalAssetFilePath('NEXT_PUBLIC_…_URL').Never read process.env.NEXT_PUBLIC_* in client code.
If the variable belongs to a brand-new feature, also:
src/features/<feature-name>/.src/features/<feature-name>/config.ts following the template below.src/config/features.ts:
export { default as <featureName> } from 'src/features/<feature-name>/config';
Keep the export list alphabetised by export name.config.ts template// SPDX-License-Identifier: LicenseRef-Blockscout
import { getEnvValue } from 'src/config/utils/envs';
import type { Feature } from 'src/config/utils/features';
const title = 'Human-readable feature name';
const config: Feature<{ /* payload fields available when enabled */ }> = (() => {
if (getEnvValue('NEXT_PUBLIC_<FEATURE>_ENABLED') === 'true') {
return Object.freeze({
title,
isEnabled: true,
// payload fields here
});
}
return Object.freeze({
title,
isEnabled: false,
});
})();
export default config;
Feature<Payload> is a discriminated union on isEnabled. Consumers narrow
to the enabled branch (if (config.isEnabled) { … config.payloadField … })
to get typed access to the payload. Real examples:
src/features/web3-wallet/config.ts, src/features/chain-stats/config.ts.
Anything that integrates with a 3rd-party able to collect user info
(analytics, error tracking, A/B testing, captcha, …) must respect the
app.isPrivateMode flag. The flag lives in src/config/app.
Feature config — gate the entire enabled branch on
!app.isPrivateMode so consumers see isEnabled: false in private mode.
Example: src/features/web3-wallet/config.ts.
if (!app.isPrivateMode && /* other conditions */) {
return Object.freeze({ title, isEnabled: true, /* payload */ });
}
return Object.freeze({ title, isEnabled: false });
Service config — never store the service's client key (or any
identifier the SDK would use to attach the user's session to a remote
account) in the config when private mode is on. Set the field to
undefined and let consumers no-op when they see it missing. Other
non-identifying fields (config overrides, etc.) can remain populated.
Examples: src/services/mixpanel/config.ts,
src/services/google-analytics/config.ts.
const projectToken = !app.isPrivateMode
? getEnvValue('NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN')
: undefined;
If the new variable doesn't touch user data (purely cosmetic, chain config, URL of a same-origin asset, etc.), this section doesn't apply.
Add the rule and a test preset entry. The full procedure (which schema file,
where in the schema, JSON shape conventions, JSON-URL example assets,
companion-variable rules, running the tests, verifying the negative path)
lives in deploy/tools/envs-validator/CONTEXT.md — follow the "Adding a new
variable" section there.
Most URL variables need a CSP allowance under src/server/csp/policies/.
Gate the addition on the relevant config option being enabled — don't widen
the CSP unconditionally.
Exceptions — these are already auto-included by policies/app.ts and
need no manual CSP work:
endpoint and socketEndpoint values that flow into config.apis.*.If the new variable lands inside one of those config paths, skip this step. For any other external host (analytics, third-party services, custom integrations, etc.), add the domain to the matching policy and gate it on the feature/option being enabled.
Append the variable name to the ASSETS_ENVS array in
deploy/scripts/download_assets.sh. The container entrypoint downloads the
asset into the image at startup so the browser serves it same-origin.