alepha@docs:~/docs/guides/core$
cat 2-configurations.md
2 min read
Last commit:

#Configurations

Alepha provides two primitives for configuration: $env for environment variables and $atom for runtime state.

#Environment Variables with $env

$env reads environment variables with schema validation, type coercion, and defaults. Import it from "alepha".

typescript
 1import { $env, t } from "alepha"; 2  3class App { 4  env = $env(t.object({ 5    DATABASE_URL: t.text(), 6    PORT: t.integer({ default: 3000 }), 7    DEBUG: t.optional(t.boolean()), 8  })); 9 10  connect() {11    console.log(this.env.DATABASE_URL); // string, guaranteed to exist12    console.log(this.env.PORT);         // number, defaults to 300013    console.log(this.env.DEBUG);        // boolean | undefined14  }15}

The schema must be a t.object(...). Each property maps to an environment variable name. Alepha validates values at instantiation time and throws if required variables are missing.

#How env values are resolved

Alepha.create() merges process.env with any values passed in the state.env option:

typescript
1const alepha = Alepha.create({2  env: {3    DATABASE_URL: "postgres://localhost/mydb",4    PORT: "8080",5  },6});

Values from process.env take precedence. This means .env files loaded before the process starts (e.g. via alepha dev) are available automatically.

#Variable interpolation

String values support $VAR interpolation using other variables from the same schema:

typescript
1class Config {2  env = $env(t.object({3    HOST: t.text({ default: "localhost" }),4    PORT: t.integer({ default: 5432 }),5    DB_NAME: t.text({ default: "mydb" }),6    DATABASE_URL: t.text({ default: "postgres://$HOST:$PORT/$DB_NAME" }),7  }));8}

#Environment caching

Alepha caches parsed env results per schema. Multiple services using the same t.object(...) reference will share the same parsed output.

#State Management with $atom

$atom defines a named, typed, validated piece of global state. Use it for application-level configuration and shared data.

#Defining an atom

typescript
 1import { $atom, t } from "alepha"; 2  3const appConfig = $atom({ 4  name: "app.config", 5  schema: t.object({ 6    theme: t.enum(["light", "dark"]), 7    language: t.text({ default: "en" }), 8  }), 9  default: { theme: "light", language: "en" },10});

The name uniquely identifies the atom in the state store. The schema defines the shape and validation. The default provides the initial value.

Recommended naming convention for name is dot-separated, e.g. "app.config", "user.settings", etc.

If the schema has all optional fields (via t.optional), the default is optional too. Otherwise, default is required.

#Reading and writing atoms

Use alepha.store.get() and alepha.store.set() (or alepha.set() as shorthand):

typescript
 1const alepha = Alepha.create(); 2  3// Read 4const config = alepha.store.get(appConfig); 5console.log(config.theme); // "light" 6  7// Write 8alepha.store.set(appConfig, { theme: "dark", language: "fr" }); 9 10// Shorthand write on the container11alepha.set(appConfig, { theme: "dark", language: "fr" });

#Injecting atoms with $use

$use creates a reactive getter that always returns the current atom value:

typescript
 1import { $atom, $use, t } from "alepha"; 2  3const count = $atom({ 4  name: "count", 5  schema: t.object({ value: t.number() }), 6  default: { value: 0 }, 7}); 8  9class Counter {10  count = $use(count);11 12  current() {13    return this.count.value; // always reads current state14  }15}

Under the hood, $use registers the atom and replaces the property with a getter that reads from the state store. When the state changes, the next property access returns the updated value:

typescript
1const alepha = Alepha.create();2const counter = alepha.inject(Counter);3 4console.log(counter.count.value); // 05 6alepha.store.set(count, { value: 42 });7console.log(counter.count.value); // 42

#State mutation events

Every store.set() call emits a "state:mutate" event:

typescript
1alepha.events.on("state:mutate", ({ key, value, prevValue }) => {2  console.log(`State "${key}" changed from`, prevValue, "to", value);3});

Atoms is not only about configuration ! This powers SSR hydration, React integration, and devtools.