<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Chris Maillefaud</title>
    <description>The latest articles on DEV Community by Chris Maillefaud (@megalus).</description>
    <link>https://dev.to/megalus</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F330854%2F0496c0ad-8f56-4ec4-a54a-8ce5996be13b.png</url>
      <title>DEV Community: Chris Maillefaud</title>
      <link>https://dev.to/megalus</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/megalus"/>
    <language>en</language>
    <item>
      <title>Manage Your Python Environment Variables Like a Pro with Stela</title>
      <dc:creator>Chris Maillefaud</dc:creator>
      <pubDate>Tue, 02 Sep 2025 23:38:38 +0000</pubDate>
      <link>https://dev.to/megalus/manage-your-python-environment-variables-like-a-pro-with-stela-3kkl</link>
      <guid>https://dev.to/megalus/manage-your-python-environment-variables-like-a-pro-with-stela-3kkl</guid>
      <description>&lt;p&gt;Getting started with environment variables in Python can feel overwhelming. You may juggle multiple .env files, try to keep secrets out of version control, and write repetitive code to parse types. Stela turns that chaos into a smooth, predictable workflow by offering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatic type inference&lt;/li&gt;
&lt;li&gt;A clear separation between settings and secrets&lt;/li&gt;
&lt;li&gt;Environment-specific .env files&lt;/li&gt;
&lt;li&gt;A simple, consistent API&lt;/li&gt;
&lt;li&gt;Extensible support for custom loaders&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whether you’re building a small script or a large web service, Stela makes configuration clean, safe, and maintainable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why environment variables matter
&lt;/h3&gt;

&lt;p&gt;Environment variables let you keep configuration out of your codebase. Instead of hard-coding API URLs, database credentials, or feature flags, you store them externally and load them at runtime. This approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keeps secrets out of your Git history&lt;/li&gt;
&lt;li&gt;Makes it easy to switch configs for development, testing, and production&lt;/li&gt;
&lt;li&gt;Simplifies deployment to containers, CI pipelines, and cloud services&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yet most libraries leave you you to write the same boilerplate: read files, parse strings into ints or booleans, and override defaults. Stela automates all of that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Introducing Stela
&lt;/h3&gt;

&lt;p&gt;Stela divides configuration into two concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Settings&lt;/strong&gt;: Non-sensitive values you can commit (API endpoints, timeouts, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secrets&lt;/strong&gt;: Sensitive values you must keep out of your repo (passwords, tokens, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It loads files in a well-defined order, casts strings to Python types automatically, and lets you add an optional final loader to pull values from other sources (AWS Parameter Store, HashiCorp Vault, etc.).&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing Stela
&lt;/h3&gt;

&lt;p&gt;Install via pip:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;stela
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Quick start: initialize your project
&lt;/h3&gt;

&lt;p&gt;Run the built-in init command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;stela init &lt;span class="nt"&gt;--default&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a set of configuration files and updates your &lt;code&gt;.gitignore&lt;/code&gt;. Typical files are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.env&lt;/code&gt; — default settings (committed)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.env.local&lt;/code&gt; — secrets (ignored)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.stela&lt;/code&gt; — Stela configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Try this quick test to observe precedence:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add or uncomment a &lt;code&gt;MY_SECRET&lt;/code&gt; line in &lt;code&gt;.env&lt;/code&gt;, then open a Python REPL and run:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;   &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;stela&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;
   &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MY_SECRET&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Stop the REPL. Add or uncomment &lt;code&gt;MY_SECRET&lt;/code&gt; in &lt;code&gt;.env.local&lt;/code&gt;, restart the REPL and run the same code — the value from &lt;code&gt;.env.local&lt;/code&gt; should take precedence over &lt;code&gt;.env&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;MY_SECRET&lt;/code&gt; in your process environment and run the REPL again. On macOS/Linux:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;MY_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"value_from_memory"&lt;/span&gt;
   python &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"from stela import env; print(env.MY_SECRET)"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Windows PowerShell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;MY_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"value_from_memory"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"from stela import env; print(env.MY_SECRET)"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Understanding your dotenv files and precedence
&lt;/h3&gt;

&lt;p&gt;By default Stela reads dotenv files in this order:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.env&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.env.local&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you set STELA_ENV (for example &lt;code&gt;STELA_ENV=development&lt;/code&gt;), Stela will also look for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.env.development&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.env.development.local&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the same key exists in multiple places, precedence (what wins) is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;System environment variable already set in memory (&lt;code&gt;os.environ&lt;/code&gt;) — always wins.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.env.{environment}.local&lt;/code&gt; (if STELA_ENV is set)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.env.{environment}&lt;/code&gt; (if STELA_ENV is set)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.env.local&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.env&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;If a value is not found anywhere, Stela raises a &lt;code&gt;StelaValueError&lt;/code&gt; by default (this is configurable).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This lets you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep safe defaults in &lt;code&gt;.env&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Override with real secrets in &lt;code&gt;.env.local&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Customize per-environment values without changing defaults&lt;/li&gt;
&lt;li&gt;Still override anything at runtime via process envs (Docker, CI, shell) without editing files&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Accessing settings and secrets
&lt;/h3&gt;

&lt;p&gt;In your Python code, just import and use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;stela&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;

&lt;span class="n"&gt;API_URL&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;API_URL&lt;/span&gt;        &lt;span class="c1"&gt;# str
&lt;/span&gt;&lt;span class="n"&gt;TIMEOUT&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TIMEOUT&lt;/span&gt;        &lt;span class="c1"&gt;# int
&lt;/span&gt;&lt;span class="n"&gt;FEATURE_FLAG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FEATURE_FLAG&lt;/span&gt;   &lt;span class="c1"&gt;# bool
&lt;/span&gt;&lt;span class="n"&gt;DB_URL&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB_URL&lt;/span&gt;         &lt;span class="c1"&gt;# str (may come from secrets if overridden)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stela reads your &lt;code&gt;.env&lt;/code&gt; files under the hood and exposes a single &lt;code&gt;env&lt;/code&gt; object.&lt;/p&gt;

&lt;h3&gt;
  
  
  Type inference out of the box
&lt;/h3&gt;

&lt;p&gt;Stela parses values into native Python types automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="c"&gt;# .env
&lt;/span&gt;&lt;span class="py"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;8000&lt;/span&gt;
&lt;span class="py"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;RETRY_TIMES&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;3&lt;/span&gt;
&lt;span class="py"&gt;PI&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;3.14159&lt;/span&gt;
&lt;span class="py"&gt;FEATURES&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;["search","login","signup"]&lt;/span&gt;
&lt;span class="py"&gt;EXTRA_SETTINGS&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;{"cache":true,"timeout":30}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;stela&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FEATURES&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EXTRA_SETTINGS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stela handles &lt;em&gt;JSON&lt;/em&gt;, &lt;em&gt;booleans&lt;/em&gt;, &lt;em&gt;numbers&lt;/em&gt;, &lt;em&gt;lists&lt;/em&gt;, and &lt;em&gt;dictionaries&lt;/em&gt; — no manual casting required.&lt;/p&gt;

&lt;h3&gt;
  
  
  Managing multiple environments
&lt;/h3&gt;

&lt;p&gt;Create files like &lt;code&gt;.env.testing&lt;/code&gt; or &lt;code&gt;.env.production&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="c"&gt;# .env.production
&lt;/span&gt;&lt;span class="py"&gt;API_URL&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://api.example.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Switch environments by setting STELA_ENV:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;STELA_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your code stays the same — Stela picks values based on &lt;code&gt;STELA_ENV&lt;/code&gt; automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Separating settings from secrets
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;stela init&lt;/code&gt; command updates your .gitignore so:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.env&lt;/code&gt; is committed&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.env.local&lt;/code&gt; and &lt;code&gt;.env.*.local&lt;/code&gt; are ignored&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use &lt;code&gt;.env&lt;/code&gt; for harmless defaults and &lt;code&gt;.env.local&lt;/code&gt; for real credentials. This keeps secrets out of your repo while making it easy for teammates to get started.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advanced: custom final loader
&lt;/h3&gt;

&lt;p&gt;Stela doesn’t only read dotenv files. You can register an optional final loader in your .stela config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[stela]&lt;/span&gt;
&lt;span class="py"&gt;final_loader&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"myproject.loaders.custom_loader"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then implement &lt;code&gt;myproject/loaders.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# myproject/loaders.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;stela.config&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StelaOptions&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;custom_loader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;StelaOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;env_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Load settings from a custom source and merge into env_data.

    Args:
        options: Stela configuration options (includes current_environment).
        env_data: Data already loaded from dotenv files.

    Returns:
        Updated data dictionary.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# Example: pretend we fetched data from an external source
&lt;/span&gt;    &lt;span class="n"&gt;external&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;API_TIMEOUT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FEATURE_FLAG&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# Merge/override values from the external source into env_data
&lt;/span&gt;    &lt;span class="n"&gt;env_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;external&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;env_data&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use Stela in your app as usual:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;stela&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;

&lt;span class="c1"&gt;# Values can come from dotenv files or your custom source.
# If a key is already set in os.environ at runtime, that in-memory value wins.
&lt;/span&gt;&lt;span class="n"&gt;API_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;API_URL&lt;/span&gt;
&lt;span class="n"&gt;DB_PASSWORD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB_PASSWORD&lt;/span&gt;
&lt;span class="n"&gt;API_TIMEOUT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;API_TIMEOUT&lt;/span&gt;  &lt;span class="c1"&gt;# From custom loader
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On startup, Stela loads your dotenv files, then calls the custom loader and merges its returned values into the loaded data. Values already present in &lt;code&gt;os.environ&lt;/code&gt; are never overwritten.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extensibility
&lt;/h3&gt;

&lt;p&gt;Don't want automatic type inference? Prefer a different file format? Define a default environment? Disable logs? Stela is flexible — check &lt;a href="https://megalus.github.io/stela/" rel="noopener noreferrer"&gt;https://megalus.github.io/stela/&lt;/a&gt; for all customization options.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion &amp;amp; next steps
&lt;/h3&gt;

&lt;p&gt;Stela brings structure, safety, and simplicity to environment variable management in Python. You get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zero-boilerplate type inference&lt;/li&gt;
&lt;li&gt;Clear separation of settings and secrets&lt;/li&gt;
&lt;li&gt;Straightforward multi-environment support&lt;/li&gt;
&lt;li&gt;Extensible custom loaders&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ready to try it? Visit the docs at &lt;a href="https://megalus.github.io/stela/" rel="noopener noreferrer"&gt;https://megalus.github.io/stela/&lt;/a&gt; and start cleaning up your configuration today.&lt;/p&gt;

&lt;p&gt;If this helped or you have questions, please leave a comment below — I'm happy to answer.&lt;/p&gt;

&lt;p&gt;Happy coding! 🚀&lt;/p&gt;

</description>
      <category>programming</category>
      <category>python</category>
      <category>dotenv</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
