Environments
SkyState config is stored per environment. Each project has three environments:
| Environment slug | Typical use |
|---|---|
development | Local development. Auto-registration is active when a devKey is present. |
staging | Pre-production testing. Read-only from the SDK. |
production | Live 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.
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 |
|---|---|
development | development |
staging (custom mode) | staging |
production | production |
Node.js / webpack / CRA
In Node.js or webpack-based projects, use process.env.NODE_ENV:
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:
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:
import.meta.env.MODE(Vite / Rollup / esbuild)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:
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:
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
productionenvironment, 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.