Skip to content

Environments

SkyState config is stored per environment. Each project has three environments:

Environment slugTypical use
developmentLocal development. Auto-registration is active when a devKey is present.
stagingPre-production testing. Read-only from the SDK.
productionLive user-facing config. Read-only from the SDK.

These three slugs are the only valid values. The SDK rejects any other string at startup.


How Environment Resolution Works

The SDK does not read an environment slug from a prop or a runtime argument. Instead, it calls a resolveEnvironment function that you provide, which reads from your build tooling's environment variables. This keeps the SDK decoupled from any specific bundler.

resolveEnvironment is called once when the store is created. The returned value must be one of 'development', 'staging', or 'production'. If it is not, getOrCreateStore throws a SkyStateError synchronously before making any HTTP request.


Providing a Resolver

Vite

In a Vite project, use import.meta.env.MODE. Vite sets MODE to 'development' in dev mode and 'production' in production builds by default. If you have a staging environment, configure it in your Vite config.

typescript
import { getOrCreateStore } from '@skystate/core';

const store = getOrCreateStore({
  apiUrl: 'https://api.skystate.io',
  accountSlug: 'my-account',
  projectSlug: 'my-project',
  resolveEnvironment: () => import.meta.env.MODE,
});

Vite mode values map directly to SkyState environment slugs:

Vite mode (import.meta.env.MODE)SkyState environment
developmentdevelopment
staging (custom mode)staging
productionproduction

Node.js / webpack / CRA

In Node.js or webpack-based projects, use process.env.NODE_ENV:

typescript
const store = getOrCreateStore({
  apiUrl: 'https://api.skystate.io',
  accountSlug: 'my-account',
  projectSlug: 'my-project',
  resolveEnvironment: () => process.env.NODE_ENV ?? 'development',
});

Custom resolver

If your environment value uses different names (for example 'dev' instead of 'development'), map them in your resolver:

typescript
const envMap: Record<string, string> = {
  dev: 'development',
  staging: 'staging',
  prod: 'production',
};

const store = getOrCreateStore({
  // ...
  resolveEnvironment: () => envMap[process.env.APP_ENV ?? 'dev'] ?? 'development',
});

The defaultReactResolver

The @skystate/react package exports a defaultReactResolver function that the SkyStateProvider uses when no resolveEnvironment prop is passed. It tries the following in order:

  1. import.meta.env.MODE (Vite / Rollup / esbuild)
  2. process.env.NODE_ENV (Node.js / webpack / CRA)

If neither is available, it returns undefined, which causes getOrCreateStore to throw SkyStateError('invalid_environment', ...).

You can import defaultReactResolver directly if you want to use it in your own @skystate/core setup:

typescript
import { defaultReactResolver } from '@skystate/react';
import { getOrCreateStore } from '@skystate/core';

const store = getOrCreateStore({
  apiUrl: 'https://api.skystate.io',
  accountSlug: 'my-account',
  projectSlug: 'my-project',
  resolveEnvironment: defaultReactResolver,
});

Validation

The SDK validates the resolved environment slug against the constant:

typescript
export const VALID_ENVIRONMENTS = ['development', 'staging', 'production'] as const;

If resolveEnvironment() throws, the SDK throws SkyStateError('environment_resolution_failed', ...).

If resolveEnvironment() returns a value not in VALID_ENVIRONMENTS, the SDK throws SkyStateError('invalid_environment', ...).

Both errors are thrown synchronously from getOrCreateStore before any HTTP request is made. In a React application, this will surface as an error boundary failure unless caught in the resolver itself.


Build-time vs. Runtime

Environment resolution is intentionally build-time. import.meta.env.MODE and process.env.NODE_ENV are injected by the bundler at build time, not read at runtime. This means:

  • A production build always connects to the production environment, regardless of where it is deployed.
  • A development build always connects to development.
  • There is no runtime mechanism to switch environments. If you need to point a production build at a staging environment for testing, build with the staging mode flag (vite build --mode staging).

This design prevents accidentally reading production config during local development and makes the environment coupling explicit and traceable.

Built with VitePress