Skip to content

Environment Variables

Orionis provides a comprehensive environment variable management system that goes far beyond simple string reading. While most frameworks are limited to reading .env values as raw strings, Orionis incorporates type hints, dynamic casting, bidirectional serialization, and strict key validation, turning environment variables into first-class citizens of the Python type system.


The environment module is composed of several collaborating layers:

ComponentResponsibility
EnvHigh-level static facade — main entry point
DotEnvSingleton engine that reads, writes, and manages the .env file
EnvironmentCasterDynamic casting engine with 10 supported types
ValidateKeyNameKey name validator (^[A-Z][A-Z0-9_]*$)
ValidateTypesType hint validator and inferrer
EnvironmentValueTypeEnum with the 10 supported types
SecureKeyGeneratorCryptographic key generator compatible with APP_KEY
env()Global helper function for quick access

The Env class is the main entry point for interacting with environment variables. All its methods are @classmethod, so no instantiation is required.

from orionis.services.environment.env import Env

Internally, Env delegates all operations to a singleton instance of DotEnv, created automatically on the first call.

Env implements the abstract contract IEnv, which defines the public interface:

from orionis.services.environment.contracts.env import IEnv
MethodSignatureReturn
get(key, default=None)object
set(key, value, type_hint=None, *, only_os=False)bool
unset(key, *, only_os=False)bool
all()dict[str, Any]
reload()bool

Retrieves the value of an environment variable. If the key exists, the value is automatically parsed to the corresponding Python type. If not, it returns the default value.

# simple read
db_host = Env.get("DB_HOST")
# with default value
db_port = Env.get("DB_PORT", 5432)

Unlike other frameworks where get() always returns a str, Orionis detects and converts stored values automatically:

Value in .envPython Type Returned
true / falsebool
null, none, nan, nilNone
42int
3.14float
[1, 2, 3]list
{'key': 'val'}dict
(1, 2)tuple
{1, 2, 3}set
int:42int (via type hint)
base64:SGVsbG8=str (decoded)
path:/usr/localstr (POSIX path)
Hello Worldstr

The parsing engine follows this resolution sequence:

  1. If the value is None, returns None
  2. If it is already a basic Python type (bool, int, float, etc.), returns it directly
  3. If it is an empty string or matches null, none, nan, or nil, returns None
  4. If it is true or false (case-insensitive), returns bool
  5. If it starts with a supported type prefix (e.g., int:, list:), delegates to EnvironmentCaster
  6. Attempts evaluation with ast.literal_eval for Python literals
  7. If all else fails, returns the original string

Sets or updates an environment variable. By default, it writes to both the .env file and os.environ.

# simple write
Env.set("APP_NAME", "Orionis")
# with explicit type hint
Env.set("APP_PORT", "8000", type_hint="int")
# process memory only (not persisted to .env)
Env.set("TEMP_TOKEN", "abc123", only_os=True)
ParameterTypeDescription
keystrVariable name (must match ^[A-Z][A-Z0-9_]*$)
valuestr | float | bool | list | dict | tuple | setValue to assign
type_hintstr | EnvironmentValueType | NoneExplicit type for serialization
only_osboolIf True, only sets in os.environ

When writing a value, the engine serializes it automatically:

Python TypeRepresentation in .env
Nonenull
booltrue / false
int / floatString representation ("42", "3.14")
list / dict / tuple / setrepr() representation
strText with whitespace trimmed

When a type_hint is provided, the value is stored with a type prefix:

Env.set("PORT", 8080, type_hint="int")
# In .env: PORT="int:8080"
Env.set("HOSTS", ["a", "b"], type_hint="list")
# In .env: HOSTS="list:['a', 'b']"

Removes an environment variable from the .env file and from os.environ.

# complete removal
Env.unset("OLD_KEY")
# only remove from os.environ (keep in .env)
Env.unset("CACHED_KEY", only_os=True)

The operation always returns True, even if the key did not exist.


Returns all variables from the .env file as a dictionary with parsed values:

config = Env.all()
# {'DB_HOST': 'localhost', 'DB_PORT': 5432, 'DEBUG': True}

Reloads variables from the .env file. Useful when the file has been modified externally:

Env.reload()

Internally, it destroys the DotEnv singleton instance and creates a new one, ensuring a completely clean state.


One of the most distinctive features of Orionis is the type hints system for environment variables. It allows storing and retrieving values with explicit types using the type:value format directly in the .env file.

The EnvironmentValueType enum defines the 10 available types:

from orionis.services.environment.enums.value_type import EnvironmentValueType
MemberValueExample in .envPython Type
STRstrstr:hellostr
INTintint:42int
FLOATfloatfloat:3.14float
BOOLboolbool:truebool
LISTlistlist:[1, 2, 3]list
DICTdictdict:{'a': 1}dict
TUPLEtupletuple:(1, 2)tuple
SETsetset:{1, 2, 3}set
BASE64base64base64:SGVsbG8=str
PATHpathpath:/usr/local/binstr
from orionis.services.environment.enums.value_type import EnvironmentValueType
# using string
Env.set("API_PORT", 3000, type_hint="int")
# using enum
Env.set("API_PORT", 3000, type_hint=EnvironmentValueType.INT)

When reading a variable that has a type prefix, the EnvironmentCaster converts it automatically:

# If in .env: API_PORT="int:3000"
port = Env.get("API_PORT")
print(type(port)) # <class 'int'>
print(port) # 3000

The boolean caster recognizes multiple representations:

TruthyFalsy
truefalse
10
yesno
onoff
enableddisabled

Paths are normalized to POSIX format and resolved as absolute:

Env.set("UPLOAD_DIR", "./uploads", type_hint="path")
# Stores: path:/absolute/path/to/uploads

If the value is already valid Base64, it is preserved. Otherwise, it is encoded automatically:

Env.set("SECRET", "my-secret", type_hint="base64")
# Stores: base64:bXktc2VjcmV0

All environment variable keys are validated against the strict pattern ^[A-Z][A-Z0-9_]*$:

KeyValidReason
DB_HOSTUppercase, underscores, correct
VAR123Digits after first letter
A__BMultiple underscores allowed
myVarContains lowercase
1VARStarts with digit
_VARStarts with underscore
MY-VARContains hyphen
# TypeError if not a string
Env.set(123, "value") # raises TypeError
# ValueError if pattern not matched
Env.set("my_var", "value") # raises ValueError

DotEnv is the internal layer that directly manages the .env file. It implements the Singleton pattern and is thread-safe via threading.RLock.

from orionis.services.environment.core.dot_env import DotEnv
  • Singleton: A single shared instance across the entire application
  • Thread-safe: All operations use threading.RLock
  • Auto-creation: If the .env file does not exist, it is created automatically
  • Configurable path: Accepts a custom path in the constructor
  • Dual persistence: Writes to both the .env file and os.environ simultaneously
# uses .env in the current directory (default behavior)
dotenv = DotEnv()
# custom path
dotenv = DotEnv(path="/config/.env.production")

The module includes SecureKeyGenerator for generating cryptographic keys compatible with the APP_KEY format (base64:<payload>):

from orionis.services.environment.key.key_generator import SecureKeyGenerator
CipherKey Size
AES-128-CBC16 bytes
AES-256-CBC32 bytes
AES-128-GCM16 bytes
AES-256-GCM32 bytes
# default cipher: AES-256-CBC
key = SecureKeyGenerator.generate()
# "base64:xK9m2..."
# specific cipher with string
key = SecureKeyGenerator.generate("AES-128-GCM")
# specific cipher with enum
from orionis.foundation.config.app.enums.ciphers import Cipher
key = SecureKeyGenerator.generate(Cipher.AES_256_GCM)

Each call produces a cryptographically unique key generated with os.urandom().


For quick access from anywhere in the application, Orionis provides the global env() function:

from orionis.services.environment.helpers.functions import env
# equivalent to Env.get("DB_HOST")
host = env("DB_HOST")
# with default value
port = env("DB_PORT", 3306)

The function simply delegates to Env.get(), accepting the same key and default parameters.


from orionis.services.environment.env import Env
from orionis.services.environment.helpers.functions import env
from orionis.services.environment.key.key_generator import SecureKeyGenerator
# Generate and set an application key
app_key = SecureKeyGenerator.generate()
Env.set("APP_KEY", app_key, type_hint="base64")
# Configure variables with explicit types
Env.set("APP_DEBUG", True, type_hint="bool")
Env.set("APP_PORT", 8080, type_hint="int")
Env.set("ALLOWED_HOSTS", ["localhost", "127.0.0.1"], type_hint="list")
Env.set("DB_CONFIG", {"host": "localhost", "port": 5432}, type_hint="dict")
# Reads with automatic casting
debug = Env.get("APP_DEBUG") # bool: True
port = Env.get("APP_PORT") # int: 8080
hosts = env("ALLOWED_HOSTS") # list: ['localhost', '127.0.0.1']
db = env("DB_CONFIG") # dict: {'host': 'localhost', 'port': 5432}
# Query all configuration
all_vars = Env.all()
# Temporary variable in memory only
Env.set("REQUEST_ID", "abc-123", only_os=True)
# Reload after external change
Env.reload()