Project Configuration

Storefront Next uses a centralized, type-safe configuration system that gives you:

  • IDE autocomplete: Full TypeScript support with suggestions as you type.
  • Environment overrides: Customize settings per environment without code changes.
  • Validation: Catch configuration errors at startup, not at run time.
  • Security by design: Clear separation between public and server-only values.

All configuration lives in a single file (config.server.ts) with defaults that you can override by using environment variables.

Quick Start 

Storefront Next provides two APIs for accessing configuration.

1// In loaders and actions - pass context
2import { getConfig } from "@/config";
3
4export function loader({ context }: LoaderFunctionArgs) {
5  const config = getConfig(context);
6  return { productsPerPage: config.global.productListing.productsPerPage };
7}
8
9// In React components - use the hook
10import { useConfig } from "@/config";
11
12function ProductGrid() {
13  const config = useConfig();
14  return <div>Showing {config.global.productListing.productsPerPage} products</div>;
15}

Configuration File 

The main configuration file is config.server.ts in your project root.

1// config.server.ts
2import { defineConfig } from "@/config/schema";
3
4export default defineConfig({
5  metadata: {
6    projectName: "My Storefront",
7    projectSlug: "my-storefront",
8  },
9  runtime: {
10    ssrOnly: [],
11    ssrParameters: { ssrFunctionNodeVersion: "22.x" },
12  },
13  app: {
14    commerce: {
15      /* Commerce API settings */
16    },
17    site: {
18      /* Locale, currency, features */
19    },
20    global: {
21      /* Branding, product listing defaults */
22    },
23    pages: {
24      /* Page-specific settings */
25    },
26    performance: {
27      /* Image optimization, caching */
28    },
29    engagement: {
30      /* Analytics adapters */
31    },
32  },
33});

For descriptions of the configuration options, see Configuration Options Reference in the storefront-next-template GitHub repo.

The configuration is organized into three main sections.

SectionPurposeClient Access
metadataProject name and slug for deploymentServer only
runtimeSSR and deployment settingsServer only
appApplication settings (commerce, features, UI)Server and client

The app section is automatically made available to client-side code. The metadata and runtime sections remain server-only.

The runtime.ssrOnly option accepts an array of glob patterns for files that must be available on the server but aren’t publicly accessible from the client. Use this option for server-side resources that aren’t exposed via public URLs.

Don’t import config.server.ts directly in your app code. While the .server.ts suffix prevents the file from being bundled into client-side code (a React Router framework feature), always use getConfig() or useConfig() to access configuration values. These APIs ensure that the configuration is properly loaded and available in the correct context.

Warning

Minimum Required Configuration 

To start the storefront, set B2C Commerce API credentials in a .env file at your project root. All the other settings have a working default in config.server.ts. Declare them only if you want to override their values.

The Storefront Next template includes an .env.default file pre-filled with public demo credentials. Copy it to .env to get started.

1cp .env.default .env

Public Client (Default) 

A public SLAS client needs three variables. These values are safe to expose to the browser, so they use the PUBLIC__ prefix.

1PUBLIC__app__commerce__api__clientId=your-client-id
2PUBLIC__app__commerce__api__organizationId=your-org-id
3PUBLIC__app__commerce__api__shortCode=your-short-code

This table describes each variable.

VariablePurpose
PUBLIC__app__commerce__api__clientIdSLAS client ID provisioned in B2C Commerce
PUBLIC__app__commerce__api__organizationIdB2C Commerce organization or realm ID (for example, f_ecom_zzrf_001)
PUBLIC__app__commerce__api__shortCodeSCAPI short code for your tenant (for example, kv7kzm78)

Private Client 

A private SLAS client uses the same three variables, plus a feature flag that switches authentication into private-client mode and a server-only secret that signs token requests.

1# Client-safe values (PUBLIC__ prefix bundled to the browser)
2PUBLIC__app__commerce__api__clientId=your-client-id
3PUBLIC__app__commerce__api__organizationId=your-org-id
4PUBLIC__app__commerce__api__shortCode=your-short-code
5PUBLIC__app__commerce__api__privateKeyEnabled=true
6
7# Server-only secret — never use the PUBLIC__ prefix
8COMMERCE_API_SLAS_SECRET=your-slas-secret

Don’t add COMMERCE_API_SLAS_SECRET to config.server.ts and don’t give it a PUBLIC__ prefix. Read it directly from process.env in server-side code, such as loaders, actions, and middleware. Anything with the PUBLIC__ prefix is bundled into the browser-visible JavaScript.

Warning

For SLAS private client setup in B2C Commerce, see Authorization for Shopper APIs.

To deploy your storefront to Managed Runtime, also set the deployment variables that the Storefront Next CLI reads. See Storefront Next CLI.

Optional Configuration 

Every other setting has a working default in config.server.ts. To override one, use a PUBLIC__ environment variable with the path syntax described in Environment Variable Overrides.

For feature-specific configuration, see the dedicated guides.

Environment Variable Overrides 

Override any configuration value by using environment variables with the PUBLIC__ prefix. With environment variables, you can customize settings per environment (development, staging, production) without modifying code.

Path Syntax 

Use double underscores (__) to navigate nested configuration paths.

1# Environment variable         →  Config path
2PUBLIC__app__site__locale  config.app.site.locale
3PUBLIC__app__commerce__api__clientId  config.app.commerce.api.clientId

Automatic Type Parsing 

Values are automatically parsed to match the expected type.

1PUBLIC__app__global__productListing__productsPerPage=48    # → number
2PUBLIC__app__site__features__guestCheckout=false           # → boolean
3PUBLIC__app__site__features__socialLogin__providers=["Apple","Google"]  # → array

You can also set entire nested objects using JSON.

1PUBLIC__app__site__features__socialLogin='{"enabled":true,"providers":["Apple","Google"]}'

Case Insensitivity 

Path matching is case-insensitive, so all these variables work.

1PUBLIC__app__site__locale=en-US
2PUBLIC__APP__SITE__LOCALE=en-US
3PUBLIC__App__Site__Locale=en-US

Merge Behavior 

Environment variables are deep merged into the defaults from config.server.ts. Only the values you specify are overridden. Everything else keeps its default.

1// Default in config.server.ts
2pages: {
3    cart: {
4        quantityUpdateDebounce: 750,
5        maxQuantityPerItem: 999,
6        enableRemoveConfirmation: true,
7    }
8}
9
10// With: PUBLIC__app__pages__cart__quantityUpdateDebounce=1000
11// Result:
12pages: {
13    cart: {
14        quantityUpdateDebounce: 1000,  // overridden
15        maxQuantityPerItem: 999,        // preserved
16        enableRemoveConfirmation: true, // preserved
17    }
18}

Security: Public vs. Private Configuration 

The PUBLIC__ prefix indicates values that are safe to expose to the browser. These values are bundled into client-side JavaScript.

Don’t use PUBLIC__ for secrets, API keys, passwords, or authentication tokens. These values are visible to anyone who uses your site.

Important

Use PUBLIC__ ForUse Non-Prefixed For
Client IDsAPI secrets
Site IDsPrivate keys
Locales and currenciesDatabase credentials
Feature flagsAuthentication tokens
Public API endpointsSLAS secrets

For server-only secrets, use environment variables without the PUBLIC__ prefix and read them directly from process.env.

1# .env - Server-only secret (no PUBLIC__ prefix)
2COMMERCE_API_SLAS_SECRET=your-secret-here
1// In server-side code only
2const slasSecret = process.env.COMMERCE_API_SLAS_SECRET;

Accessing Configuration 

In Loaders and Actions 

Use getConfig() with the router context.

1import { getConfig } from "@/config";
2
3export function loader({ context }: LoaderFunctionArgs) {
4  const config = getConfig(context);
5  const { clientId, siteId } = config.commerce.api;
6  return { siteId };
7}
8
9export async function action({ context, request }: ActionFunctionArgs) {
10  const config = getConfig(context);
11  // Use config values...
12}

In React Components 

Use the useConfig() hook:

1import { useConfig } from "@/config";
2
3function Header() {
4  const config = useConfig();
5  return <h1>{config.global.branding.name}</h1>;
6}

In Client Loaders 

Client loaders don’t have access to router context. Call getConfig() without arguments.

1export function clientLoader() {
2  const config = getConfig(); // Uses window.__APP_CONFIG__
3  return { locale: config.site.locale };
4}

Adding New Configuration 

To add a new configuration value, follow these steps.

1. Define the Type 

Add the type definition in src/config/schema.ts:

1export type Config = {
2  app: {
3    // Add your new configuration
4    myFeature: {
5      enabled: boolean;
6      maxItems: number;
7    };
8  };
9};

2. Set the Default Value 

Add the default in config.server.ts:

1export default defineConfig({
2  app: {
3    myFeature: {
4      enabled: false,
5      maxItems: 10,
6    },
7  },
8});

3. Override via Environment Variables 

No code changes needed. Use the PUBLIC__ prefix.

1PUBLIC__app__myFeature__enabled=true
2PUBLIC__app__myFeature__maxItems=25

4. Use in Your Code 

1// In a component
2const config = useConfig();
3if (config.myFeature.enabled) {
4  // Feature is enabled
5}
6
7// In a loader
8const config = getConfig(context);
9const limit = config.myFeature.maxItems;

Deployment 

When deploying to Managed Runtime (MRT), set your environment variables in the Runtime Admin.

  1. Log in to the Runtime Admin.
  2. Navigate to your project → Environment Variables.
  3. Add the required PUBLIC__ variables.
  4. Add any server-only secrets without the PUBLIC__ prefix.
  5. Deploy your app.

MRT has limits: variable names max 512 characters, total PUBLIC__ values max 32 KB. Use JSON to consolidate related settings if needed.

Note

Troubleshooting 

Changed .env but Nothing Happened? 

Restart your dev server. Environment variables are loaded at startup.

Environment Variable Not Working? 

  • Verify the variable name starts with PUBLIC__ (double underscore after PUBLIC)
  • Check the .env file is in the project root
  • Ensure that the path exists in config.server.ts—you can only override existing paths

Type Errors After Adding Configuration? 

Update both src/config/schema.ts (types) and config.server.ts (defaults) to match.

App Won't Start—Missing Credentials? 

Copy .env.default to .env and set the required B2C Commerce credentials. See Minimum Required Configuration.

Path Validation Error? 

The configuration system validates that environment variable paths exist in your config. If you see an error like "local" doesn't exist, check for typos. The system suggests similar valid paths when possible.