[API reference](https://evolu.dev/docs/api-reference) › [@evolu/common](https://evolu.dev/docs/api-reference/common) › [Config](https://evolu.dev/docs/api-reference/common/Config) › env

```ts
function env<Props>(
  props: Props,
  ..._validation: [EnvValidation<Props>] extends [never]
    ? []
    : [EnvValidation<Props>]
): EnvType<Props>;
```

Defined in: [packages/common/src/Config.ts:170](https://github.com/evoluhq/evolu/blob/dd96d79f1dbe9a49fa12ce8e0aa7d3d0177795ca/packages/common/src/Config.ts#L170)

Creates a reversible environment-variable codec with a flat decoded output.

Declare camelCase fields directly, or put them in one-level CONSTANT_CASE
namespace groups. A direct `port` field reads `PORT`; a `maxOwnerBytes` field
in an `EVOLU_RELAY` group reads `EVOLU_RELAY_MAX_OWNER_BYTES`. Groups affect
external names only. Duplicate decoded fields or encoded names are rejected
during construction, even when their Types are identical.

Selects exact declared unprefixed names and all keys within declared
namespaces. Namespace selection ignores casing so incorrectly cased names
fail validation instead of being ignored. Selected names must match their
exact declared spelling. Unrelated variables are ignored; misspelled
unprefixed names or namespace prefixes can therefore still look absent.

Field Types must encode to strings. Optional fields may be absent, but
explicit `undefined` values are rejected. Empty strings remain present and
must satisfy the field Type. Compose [withDefault](https://evolu.dev/docs/api-reference/common/Type/functions/withDefault) to supply defaults.
Encoding emits canonical external names and string values, preserving absence
when the field codec does. Errors retain external names and nested paths.

Reads own string properties from any non-null object, including
`process.env`. Selected properties must be enumerable data properties;
getters are never read. Prototypes and internal contents such as Map entries
are ignored. Non-object inputs fail with standard object errors. Schema names
must satisfy [EnvName](https://evolu.dev/docs/api-reference/common/Config/variables/EnvName); groups cannot be nested. Loading and source
precedence remain explicit application code.

### Example

```ts
import {
  assertEqual,
  assertErr,
  assertOk,
  assertType,
  ByteSizeLiteral,
  env,
  optional,
  Port,
  PortFromString,
  withDefault,
} from "@evolu/common";

const RelayEnv = env({
  port: withDefault(optional(PortFromString), Port.orThrow(4000)),
  EVOLU_RELAY: {
    maxOwnerBytes: optional(ByteSizeLiteral),
  },
});

const result = RelayEnv.fromUnknown({
  PORT: "04000",
  EVOLU_RELAY_MAX_OWNER_BYTES: "512KiB",
  HOME: "/home/evolu",
});

assertOk(result, { port: 4000, maxOwnerBytes: "512KiB" });
assertType<typeof result.value.port, Port>();
assertEqual(RelayEnv.to(result.value), {
  PORT: "4000",
  EVOLU_RELAY_MAX_OWNER_BYTES: "512KiB",
});

assertOk(RelayEnv.fromUnknown({}), { port: 4000 });
assertErr(RelayEnv.fromUnknown({ PORT: "" }));
assertErr(RelayEnv.fromUnknown({ EVOLU_RELAY_MAX_OWENR_BYTES: "1MiB" }));
assertErr(RelayEnv.fromUnknown({ evolu_relay_max_owner_bytes: "1MiB" }));
```