# Sfnext Configuration

> Manage Storefront Next application configuration using config.server.ts, schema types, environment variables, and multi-site setup. Use when editing config.server.ts, adding PUBLIC__ environment variables, using useConfig or getConfig, or configuring multiple sites. NOT for initial project creation — see sfnext-project-setup.

- Skill: `salesforcecommercecloud/sfnext-configuration` (Agent Skill)
- Install (CLI): `npx skillmds@latest add salesforcecommercecloud/sfnext-configuration`
- Raw SKILL.md: https://api.skillmd.com/api/skills/salesforcecommercecloud/sfnext-configuration/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: salesforcecommercecloud (https://skillmd.com/u/salesforcecommercecloud)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/salesforcecommercecloud/sfnext-configuration

---


# Configuration Skill

This skill covers the Storefront Next configuration system — centralized in `config.server.ts` with environment variable overrides.

## Overview

All configuration is centralized in `config.server.ts` with typed defaults. Environment variables (via `.env` files or MRT settings) override these defaults. The system provides type-safe access with automatic parsing and validation.

## Adding Configuration

### 1. Define the type in `src/types/config.ts`

```typescript
export type Config = {
  app: {
    myFeature: {
      enabled: boolean;
      maxItems: number;
    };
  };
};
```

### 2. Set defaults in `config.server.ts`

```typescript
export default defineConfig({
  app: {
    myFeature: {
      enabled: false,
      maxItems: 10,
    },
  },
});
```

### 3. Override via environment variables

```bash
PUBLIC__app__myFeature__enabled=true
PUBLIC__app__myFeature__maxItems=20
```

## Accessing Configuration

### In React Components

```typescript
import { useConfig } from '@salesforce/storefront-next-runtime/config';

export function MyComponent() {
  const config = useConfig();

  if (config.myFeature.enabled) {
    const maxItems = config.myFeature.maxItems;
    // Feature code
  }
}
```

### In Server Loaders/Actions

```typescript
import { getConfig } from '@salesforce/storefront-next-runtime/config';

export function loader({context}: LoaderFunctionArgs) {
  const config = getConfig(context); // context is required on server

  if (config.myFeature.enabled) {
    // Loader code
  }
}
```

### In Browser Code (Non-Route Modules)

```typescript
import { getConfig } from '@salesforce/storefront-next-runtime/config';

export function getFeatureFlag() {
  const config = getConfig(); // No context needed in browser (uses window.__APP_CONFIG__)
  return config.myFeature.enabled;
}
```

**Note:** `getConfig()` and `useConfig()` return `AppConfig` — the `app` section of the full config. Access properties directly (e.g., `config.myFeature.enabled`) without the `app` prefix.

## Environment Variable Rules

```bash
# Pattern: PUBLIC__app__{path}__{to}__{property}=value
PUBLIC__app__commerce__api__clientId=abc123
# Maps to config.app.commerce.api.clientId
# Accessed as config.commerce.api.clientId
```

| Rule              | Detail                                         |
| ----------------- | ---------------------------------------------- |
| `PUBLIC__` prefix | Exposed to browser (client-safe)               |
| No prefix         | Server-only (secrets)                          |
| `__` separator    | Navigate nested paths                          |
| Auto-parsing      | Numbers, booleans, JSON parsed automatically   |
| Validation        | Paths must exist in `config.server.ts`         |
| Depth limit       | Maximum 10 levels                              |
| MRT limits        | Names max 512 chars; total `PUBLIC__` max 32KB |

## Multi-Site Configuration

```bash
PUBLIC__app__commerce__sites='[
  {
    "id": "RefArchGlobal",
    "defaultLocale": "en-US",
    "defaultCurrency": "USD",
    "supportedLocales": [
      {"id": "en-US", "preferredCurrency": "USD"},
      {"id": "de-DE", "preferredCurrency": "EUR"}
    ],
    "supportedCurrencies": ["USD", "EUR"]
  }
]'
```

```typescript
const config = getConfig(context);
const currentSite = config.commerce.sites[0];
const locale = currentSite.defaultLocale; // "en-US"
const currency = currentSite.defaultCurrency; // "USD"
```

## Security

```bash
# Client-safe (PUBLIC__ prefix)
PUBLIC__app__commerce__api__clientId=abc123

# Server-only (no prefix — never sent to client)
COMMERCE_API_SLAS_SECRET=your-secret
```

Read server-only secrets directly from `process.env` — never add them to the config system.

## Common Pitfalls

| Pitfall           | Problem                                    | Solution                                           |
| ----------------- | ------------------------------------------ | -------------------------------------------------- |
| Missing `context` | `getConfig()` returns undefined in loaders | Use `getConfig(context)` on server                 |
| Typo in env var   | Variable silently ignored                  | Validation catches paths not in `config.server.ts` |
| Exposing secrets  | Sensitive data in browser                  | Use no-prefix variables; access via `process.env`  |

## Related Skills

- `storefront-next:sfnext-project-setup` - Initial environment setup and `.env` configuration
- `storefront-next:sfnext-data-fetching` - Using config in loader functions
- `storefront-next:sfnext-deployment` - MRT environment variable configuration

