Skip to content
Africa OS Knowledgebase
Esc
navigateopen⌘Jpreview
On this page

Configuration

Central configuration - validated environment variables, product constants, feature flags, and the ApplicationConfig contract.

@africaos/config is the single source of truth for configuration. Environment variables are validated once at startup, product constants and feature flags live here, and the application-config contract that every app.config.ts satisfies is defined here too.

Environment variables

packages/config/env.config.ts uses defineEnv from the envin package with Zod schemas. It splits variables into shared, server, and client (VITE_-prefixed):

Scope Variable Rule
Shared NODE_ENV `development
Server DATABASE_URL Required, must be a valid URL.
Server BETTER_AUTH_SECRET Required, at least 32 characters.
Server BETTER_AUTH_URL Optional URL; blank values treated as absent.
Server GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET Optional; enables Google login when present.
Server WORKOS_API_KEY / WORKOS_CLIENT_ID / WORKOS_REDIRECT_URI Optional; enables WorkOS SSO when present.
Client VITE_APP_NAME Default "Africa OS".
Client VITE_APP_VERSION Default "0.0.0".
Client VITE_PLATFORM_URL Optional URL.

Key behaviors:

  • Required vs optional is encoded in the schema. DATABASE_URL and BETTER_AUTH_SECRET are required; everything else is optional so apps that do not need a capability (the landing page has no auth) still boot.
  • Blank values are treated as absent. optionalUrl() preprocesses empty strings to undefined, so copying .env.example (which leaves optional entries blank) does not break startup.
  • Validation is at boot time. A missing or malformed variable fails fast with a clear error rather than failing later in an obscure place.

The env object is the default export; code reads it as env.DATABASE_URL etc.

Product constants

packages/config/src/constants.ts:

export const AFRICA_OS = {
  name: "Africa OS",
  version: "0.0.0",
  namespace: "@africaos",
} as const;

Feature flags

packages/config/src/features.ts declares the platform’s capability flags:

export const features = {
  offline: true,
  desktop: true,
  multiTenant: true,
  realtime: false,
} as const;

The ApplicationConfig contract

packages/config/src/types.ts defines the types every application’s app.config.ts uses:

export interface ApplicationFeature {
  slug: string;
  label: string;
  icon?: string;
  path?: string; // application-relative route when implemented
}

export interface ApplicationConfig {
  id: string;
  name: string;
  icon?: string;
  color?: string;
  description?: string;
  route?: string;
  capabilities: {
    offline: boolean;
    desktop: boolean;
    mobile: boolean;
  };
  features: ReadonlyArray<ApplicationFeature>;
}

export const defineAppConfig = (config: ApplicationConfig): ApplicationConfig => config;

defineAppConfig gives applications full type checking on their self-description, so the registry contract is enforced at build time. A feature with a path is implemented and becomes navigation; one without a path is declared surface (for example a planned module).

Where config is used

  • The database pool reads env.DATABASE_URL.
  • The auth provider reads env.BETTER_AUTH_SECRET, BETTER_AUTH_URL, and the OAuth/WorkOS credentials.
  • Apps read VITE_APP_NAME/VITE_APP_VERSION for the header chrome.
  • Application packages call defineAppConfig in their app.config.ts.

Next steps

Last updated on August 18, 2026