<?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: Marçal Albert Castellví</title>
    <description>The latest articles on DEV Community by Marçal Albert Castellví (@macalbert).</description>
    <link>https://dev.to/macalbert</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%2F1290970%2Fdf8026b9-d325-4e43-b614-e1b57b3038c4.png</url>
      <title>DEV Community: Marçal Albert Castellví</title>
      <link>https://dev.to/macalbert</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/macalbert"/>
    <language>en</language>
    <item>
      <title>How I run LocalStack without committing LOCALSTACK_AUTH_TOKEN</title>
      <dc:creator>Marçal Albert Castellví</dc:creator>
      <pubDate>Mon, 08 Jun 2026 23:13:33 +0000</pubDate>
      <link>https://dev.to/macalbert/how-i-run-localstack-without-committing-localstackauthtoken-34gk</link>
      <guid>https://dev.to/macalbert/how-i-run-localstack-without-committing-localstackauthtoken-34gk</guid>
      <description>&lt;h2&gt;
  
  
  &lt;em&gt;Using &lt;a href="https://envilder.com/" rel="noopener noreferrer"&gt;Envilder&lt;/a&gt; to keep the LocalStack auth token out of Git while preserving a reproducible local Docker Compose setup.&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;I wanted a reproducible LocalStack setup without committing &lt;code&gt;LOCALSTACK_AUTH_TOKEN&lt;/code&gt; to the repository.&lt;/p&gt;

&lt;p&gt;That sounds simple, but it touches a common local development problem:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;How do you make a project easy to run without putting real secrets in Git?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;LocalStack &lt;a href="https://docs.localstack.cloud/aws/getting-started/auth-token/" rel="noopener noreferrer"&gt;expects the auth token&lt;/a&gt; to be available through the &lt;code&gt;LOCALSTACK_AUTH_TOKEN&lt;/code&gt; environment variable when starting it with Docker, Docker Compose, the LocalStack CLI, or CI workflows.&lt;/p&gt;

&lt;p&gt;Since &lt;a href="https://blog.localstack.cloud/localstack-for-aws-release-2026-03-0/" rel="noopener noreferrer"&gt;LocalStack for AWS 2026.03.0&lt;/a&gt;, it ships as a consolidated Docker image and requires an auth token to start, so managing &lt;code&gt;LOCALSTACK_AUTH_TOKEN&lt;/code&gt; cleanly is now part of the normal setup path, not just a Pro-only edge case.&lt;/p&gt;

&lt;p&gt;That token is a secret, so I did not want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;commit it to the repository&lt;/li&gt;
&lt;li&gt;paste it into &lt;code&gt;docker-compose.yml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;duplicate it across helper scripts&lt;/li&gt;
&lt;li&gt;rely on a manual &lt;code&gt;export LOCALSTACK_AUTH_TOKEN=...&lt;/code&gt; step every time&lt;/li&gt;
&lt;li&gt;make the setup work only on my machine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What I wanted instead was a small, repeatable contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;this project needs LOCALSTACK_AUTH_TOKEN
resolve it from the secret store
inject it locally when needed
do not commit the value
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the pattern I ended up using with &lt;a href="https://github.com/macalbert/envilder" rel="noopener noreferrer"&gt;Envilder&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pattern
&lt;/h2&gt;

&lt;p&gt;The idea is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;secret values stay in a real secret store&lt;/li&gt;
&lt;li&gt;the repository contains only the mapping&lt;/li&gt;
&lt;li&gt;local development generates a &lt;code&gt;.env&lt;/code&gt; file from that mapping&lt;/li&gt;
&lt;li&gt;Docker Compose reads the generated &lt;code&gt;.env&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;the token never gets committed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this case, the secret is &lt;code&gt;LOCALSTACK_AUTH_TOKEN&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In another project, it could be a database password, webhook secret, API key, or service credential.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining the Secret Mapping
&lt;/h2&gt;

&lt;p&gt;Here is a minimal &lt;code&gt;envilder.json&lt;/code&gt; example using AWS SSM Parameter Store:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"$schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://envilder.com/schema/map-file.v1.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"$config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"aws"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"profile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"default"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"LOCALSTACK_AUTH_TOKEN"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/envilder/localstack/auth-token"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This file is safe to commit because it does not contain the token.&lt;/p&gt;

&lt;p&gt;It only says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;To produce &lt;code&gt;LOCALSTACK_AUTH_TOKEN&lt;/code&gt;, resolve this value from the secret store.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The actual token remains outside the repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating the Local &lt;code&gt;.env&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Before starting LocalStack, generate the local environment file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx envilder &lt;span class="nt"&gt;--map&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;envilder.json &lt;span class="nt"&gt;--envfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That produces a local &lt;code&gt;.env&lt;/code&gt; file like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LOCALSTACK_AUTH_TOKEN=...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;.env&lt;/code&gt; file should be ignored by Git:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the project contains the setup contract, but not the secret.&lt;/p&gt;

&lt;h2&gt;
  
  
  Passing the Token to LocalStack
&lt;/h2&gt;

&lt;p&gt;A Docker Compose service can reference the variable as usual:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;localstack&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;localstack/localstack:stable&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;4566:4566"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;4510-4559:4510-4559"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;LOCALSTACK_AUTH_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${LOCALSTACK_AUTH_TOKEN:?Run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;npx&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;envilder&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;first}"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/var/run/docker.sock:/var/run/docker.sock"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Docker Compose automatically reads a &lt;code&gt;.env&lt;/code&gt; file from the project directory for variable interpolation.&lt;/p&gt;

&lt;p&gt;If your generated env file lives somewhere else, you can pass it explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nt"&gt;--env-file&lt;/span&gt; path/to/.env up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The payoff is what a new contributor sees after cloning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx envilder &lt;span class="nt"&gt;--map&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;envilder.json &lt;span class="nt"&gt;--envfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.env
docker compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two commands, no Slack message asking "where do I get the token?", no secret in Git.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not direnv, 1Password, or chamber?
&lt;/h2&gt;

&lt;p&gt;For one developer, &lt;code&gt;export LOCALSTACK_AUTH_TOKEN=...&lt;/code&gt; works, but it creates hidden local state the repo never documents. The interesting comparison is against the tools that already resolve secrets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;direnv&lt;/strong&gt; loads env vars when you enter a directory, but &lt;code&gt;.envrc&lt;/code&gt; is just shell. You still write &lt;code&gt;export LOCALSTACK_AUTH_TOKEN=$(aws ssm get-parameter ...)&lt;/code&gt; yourself, per variable, per project. It is a loader, not a resolver, and the mapping lives in bespoke shell instead of a declared contract.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1Password &lt;code&gt;op run&lt;/code&gt;&lt;/strong&gt; injects secrets at runtime and is excellent, but it assumes 1Password is your store. If your secrets already live in AWS SSM or Azure Key Vault, you are adding a vendor, not removing one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;chamber&lt;/strong&gt; is the closest match for the AWS-only case:
&lt;code&gt;chamber exec service -- docker compose up&lt;/code&gt; reads straight from SSM. If you never leave AWS and only need secrets at the command line, chamber or a three-line script is genuinely enough.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Envilder's narrow bet is different on three points:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The mapping is an explicit &lt;code&gt;name -&amp;gt; path&lt;/code&gt; contract committed as JSON, not a service prefix or shell glue.&lt;/li&gt;
&lt;li&gt;The store is your own cloud. No third-party infrastructure holds the secret.&lt;/li&gt;
&lt;li&gt;The same map drives the CLI here, CI, and in-process resolution through the SDKs, so local dev and runtime read one contract.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you only ever touch AWS from a shell, you may not need it. The case shows up when you have more than one provider, more than one language, or want the same declared contract locally, in CI, and at runtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Slightly Meta Part
&lt;/h2&gt;

&lt;p&gt;I ran into this while working on Envilder.&lt;/p&gt;

&lt;p&gt;Envilder uses LocalStack for integration testing.&lt;/p&gt;

&lt;p&gt;LocalStack needs &lt;code&gt;LOCALSTACK_AUTH_TOKEN&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So I used Envilder to inject the token needed to start the LocalStack environment used to test Envilder.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2tfkdag8d7ske6xb59ta.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2tfkdag8d7ske6xb59ta.png" alt="Envilder uses Envilder to inject LocalStack token"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The tool became its own first customer, which is always a useful kind of feedback.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Note on LocalStack Auth Tokens
&lt;/h2&gt;

&lt;p&gt;LocalStack's documentation is clear that &lt;code&gt;LOCALSTACK_AUTH_TOKEN&lt;/code&gt; should be kept confidential and should not be committed to source control.&lt;/p&gt;

&lt;p&gt;This post is not about bypassing that requirement.&lt;/p&gt;

&lt;p&gt;It is about treating the token like any other secret:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;store it safely&lt;/li&gt;
&lt;li&gt;resolve it when needed&lt;/li&gt;
&lt;li&gt;avoid leaking it into Git&lt;/li&gt;
&lt;li&gt;keep the project setup reproducible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For open source maintainers, this matters. A project can require credentials for local or CI workflows and still provide a clean setup path for contributors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;LOCALSTACK_AUTH_TOKEN&lt;/code&gt; is just one example of a broader problem.&lt;/p&gt;

&lt;p&gt;Projects often need secrets during local development, CI/CD, tests, and runtime. The hard part is not only storing those secrets safely. It is keeping the mapping between "what the app needs" and "where the secret lives" clear and consistent.&lt;/p&gt;

&lt;p&gt;The pattern I like is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;secret values outside Git
secret mappings inside Git
one contract for local dev, CI/CD, and runtime
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the reason I am building Envilder.&lt;/p&gt;

&lt;p&gt;Not to add another place to store secrets.&lt;/p&gt;

&lt;p&gt;Just to make secret resolution explicit, repeatable, and versionable.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>localstack</category>
      <category>docker</category>
      <category>secrets</category>
    </item>
    <item>
      <title>One year of Envilder: from a CLI script to SDKs, push mode, and a website</title>
      <dc:creator>Marçal Albert Castellví</dc:creator>
      <pubDate>Thu, 07 May 2026 00:11:10 +0000</pubDate>
      <link>https://dev.to/macalbert/one-year-of-envilder-from-a-cli-script-to-sdks-push-mode-and-a-website-h49</link>
      <guid>https://dev.to/macalbert/one-year-of-envilder-from-a-cli-script-to-sdks-push-mode-and-a-website-h49</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a follow-up to my &lt;a href="https://dev.to/macalbert/stop-hardcoding-secrets-generate-env-files-from-aws-ssm-with-a-simple-cli-f77"&gt;first post about Envilder&lt;/a&gt;, where I introduced it as a simple CLI to generate &lt;code&gt;.env&lt;/code&gt; files from AWS SSM. A year later, it has grown quite a bit, and I want to share what changed, why, and what I learned building it almost entirely with AI.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Where we left off
&lt;/h2&gt;

&lt;p&gt;A year ago, Envilder did one thing: pull secrets from AWS SSM Parameter Store and write them to a &lt;code&gt;.env&lt;/code&gt; file. That was already useful. It removed the "what's the DB password?" Slack messages and kept onboarding fast.&lt;/p&gt;

&lt;p&gt;But real usage exposed real gaps. If you haven't seen Envilder before, here's the basic flow: create secrets via CLI and consume them in your app:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/1189935282" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  The map file: one contract, every context
&lt;/h2&gt;

&lt;p&gt;Before getting into features, this is the core idea behind Envilder and what makes it different from ad-hoc scripts.&lt;/p&gt;

&lt;p&gt;Everything in Envilder revolves around a single JSON file: &lt;code&gt;envilder.json&lt;/code&gt;. It's a declarative contract that decouples your application from the secret provider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"$schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://envilder.com/schema/map-file.v1.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"$config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"aws"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"profile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-profile"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"DB_PASSWORD"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/my-app/prod/db-password"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"API_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/my-app/prod/api-key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"STRIPE_SECRET"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/my-app/prod/stripe-secret"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Left side: the environment variable name your app expects. Right side: the path in your secret provider. The &lt;code&gt;$config&lt;/code&gt; block declares the provider and credentials.&lt;/p&gt;

&lt;p&gt;The key point: &lt;strong&gt;your application never knows where secrets come from&lt;/strong&gt;. It depends on &lt;code&gt;envilder.json&lt;/code&gt;, not on AWS SSM, not on Azure Key Vault. If you migrate from SSM to Key Vault tomorrow, you change the &lt;code&gt;$config&lt;/code&gt; block. Your app code, your CI/CD pipelines, your onboarding scripts don't change at all. The SDKs even let you override the provider at runtime via a fluent builder, without touching the file.&lt;/p&gt;

&lt;p&gt;At the SDK level, this goes further: the code depends on an &lt;code&gt;ISecretProvider&lt;/code&gt; abstraction, not on AWS or Azure directly. The map file feeds that abstraction. Switch provider in &lt;code&gt;$config&lt;/code&gt;, your app code stays the same.&lt;/p&gt;

&lt;p&gt;And because &lt;code&gt;envilder.json&lt;/code&gt; contains paths, not values, it &lt;strong&gt;lives in your repo&lt;/strong&gt;, versionable, reviewable, shared across the team. When someone joins the project, they run one command and get every secret they need. When someone adds a new secret, the diff in &lt;code&gt;envilder.json&lt;/code&gt; is the documentation. The same file is consumed by the CLI, all three SDKs, and the GitHub Action. One contract, every context.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed (and why)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Push mode: stop switching tools
&lt;/h3&gt;

&lt;p&gt;The first friction: every time someone needed to add a new secret, they had to open the AWS Console or use the AWS CLI directly. Envilder was a read-only tool.&lt;/p&gt;

&lt;p&gt;Now you can push secrets to the cloud directly from Envilder. The powerful part: it accepts an &lt;code&gt;.env&lt;/code&gt; file and your &lt;code&gt;envilder.json&lt;/code&gt;, and pushes everything in one go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;envilder &lt;span class="nt"&gt;--push&lt;/span&gt; &lt;span class="nt"&gt;--env-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.env &lt;span class="nt"&gt;--map-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;envilder.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This reads the &lt;code&gt;.env&lt;/code&gt; values, maps them through &lt;code&gt;envilder.json&lt;/code&gt; to the right provider paths, and creates (or updates) all secrets at once. New project? Define your &lt;code&gt;envilder.json&lt;/code&gt;, write your &lt;code&gt;.env&lt;/code&gt; locally, push. Done. No clicking through the AWS Console, no running 15 &lt;code&gt;aws ssm put-parameter&lt;/code&gt; commands.&lt;/p&gt;

&lt;p&gt;You can also push a single key when needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;envilder &lt;span class="nt"&gt;--push&lt;/span&gt; &lt;span class="nt"&gt;--key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;DB_PASSWORD &lt;span class="nt"&gt;--value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;12345 &lt;span class="nt"&gt;--ssm-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/my-app/db/password
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One tool for reading and writing. No context switching.&lt;/p&gt;

&lt;p&gt;One detail worth noting about pull: when generating your &lt;code&gt;.env&lt;/code&gt;, Envilder only overwrites the keys declared in &lt;code&gt;envilder.json&lt;/code&gt;. Any other variables already in your &lt;code&gt;.env&lt;/code&gt; are left untouched. This means you can safely mix Envilder-managed secrets with local-only variables (like &lt;code&gt;DEBUG=true&lt;/code&gt; or &lt;code&gt;LOG_LEVEL=verbose&lt;/code&gt;) without losing them on every pull.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. SDKs: because &lt;code&gt;.env&lt;/code&gt; files are a liability
&lt;/h3&gt;

&lt;p&gt;Generating &lt;code&gt;.env&lt;/code&gt; files was the original goal, but it's inherently insecure: secrets land on disk, they get accidentally committed, they go stale. The safer approach is resolving secrets at runtime, directly in your application.&lt;/p&gt;

&lt;p&gt;Envilder now has SDKs for three platforms:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Python&lt;/strong&gt; (&lt;code&gt;pip install envilder&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;envilder&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Envilder&lt;/span&gt;

&lt;span class="n"&gt;Envilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;envilder.json&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# secrets are now in os.environ, no file on disk
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;.NET&lt;/strong&gt; (&lt;code&gt;dotnet add package Envilder&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Via IConfiguration (ASP.NET)&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ConfigurationBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddEnvilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"envilder.json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Or one-liner&lt;/span&gt;
&lt;span class="n"&gt;Envilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"envilder.json"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The .NET SDK targets .NET Standard 2.0, so it works from .NET Framework 4.6.1 all the way to .NET 10. It integrates natively with &lt;code&gt;IConfiguration&lt;/code&gt; and &lt;code&gt;IServiceCollection&lt;/code&gt;. It feels like a first-class .NET library, not a wrapper.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TypeScript/JavaScript&lt;/strong&gt; (&lt;code&gt;@envilder/sdk&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Envilder&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@envilder/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;secrets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Envilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolveFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;envilder.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All three SDKs support a fluent builder for runtime overrides (switch profile, provider, or vault URL without touching the map file), environment-based loading, and secret validation.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Azure Key Vault support
&lt;/h3&gt;

&lt;p&gt;This is the payoff of the abstraction. The SDK architecture already had a provider interface (&lt;code&gt;ISecretProvider&lt;/code&gt;), so adding Azure Key Vault was a natural extension. Same &lt;code&gt;envilder.json&lt;/code&gt;, different &lt;code&gt;$config&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"$config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"azure"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"vaultUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://my-vault.vault.azure.net"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"DB_PASSWORD"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"db-password"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your app code doesn't change. You can even implement your own provider (HashiCorp Vault, GCP Secret Manager) by plugging in the interface.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. LocalStack supports Envilder, and Envilder uses itself
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://localstack.cloud/" rel="noopener noreferrer"&gt;LocalStack&lt;/a&gt; supports the Envilder project, which means the acceptance tests run against a local AWS emulation with full SSM support.&lt;/p&gt;

&lt;p&gt;The fun part: LocalStack now requires an auth token to run. How does Envilder manage that token? &lt;strong&gt;With itself.&lt;/strong&gt; The CI pipeline uses Envilder to resolve the &lt;code&gt;LOCALSTACK_AUTH_TOKEN&lt;/code&gt; from SSM before running the tests that validate Envilder against LocalStack. It references itself as a dependency of its own test infrastructure.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I wrote up this pattern in full, from the &lt;code&gt;envilder.json&lt;/code&gt; mapping to the Docker Compose wiring that keeps the token out of Git: &lt;a href="https://dev.to/macalbert/how-i-run-localstack-without-committing-localstackauthtoken-34gk"&gt;How I run LocalStack without committing LOCALSTACK_AUTH_TOKEN&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  5. GitHub Action
&lt;/h3&gt;

&lt;p&gt;CI/CD was always the primary use case, so there's now an official GitHub Action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;macalbert/envilder/github-action@v0.7.9&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;map-file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;envilder.json&lt;/span&gt;
    &lt;span class="na"&gt;env-file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.env&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. A website
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://envilder.com" rel="noopener noreferrer"&gt;envilder.com&lt;/a&gt;: documentation, schema references, and a landing page. Nothing fancy, but it makes the project feel real and gives the SDKs a proper home.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where Envilder fits
&lt;/h2&gt;

&lt;p&gt;Doppler and Infisical are full platforms with their own infrastructure. Your secrets are stored on their servers, managed through their dashboards. That's a valid choice, but it comes with cost (Doppler Team at $21/user/month, Infisical Pro at $18/identity/month) and a trust trade-off.&lt;/p&gt;

&lt;p&gt;Envilder has no infrastructure. Zero. Your secrets stay in your cloud (AWS SSM or Azure Key Vault) and never pass through a third party. Audit trails? CloudTrail or Azure Monitor. Access control? IAM or Azure RBAC. Encryption at rest, versioning? Already there. You're not giving anything up. Those capabilities come from the provider you already pay for.&lt;/p&gt;

&lt;p&gt;Envilder just makes them easy to consume everywhere: local dev, CI/CD, application runtime. One &lt;code&gt;envilder.json&lt;/code&gt;, one command, SDKs for three platforms. No servers, no middleman, no SaaS fees. MIT licensed.&lt;/p&gt;




&lt;h2&gt;
  
  
  The AI part (brief version, full post coming)
&lt;/h2&gt;

&lt;p&gt;I built most of this project with AI assistance. Started with GPT-4 a year ago, went through several Claude models (Sonnet, Haiku), and the real leap came with Claude Opus 4.5 for planning and architecture decisions. For implementation with good skill definitions, Sonnet remains excellent and more cost-effective.&lt;/p&gt;

&lt;p&gt;I also use &lt;a href="https://coderabbit.ai/" rel="noopener noreferrer"&gt;CodeRabbit&lt;/a&gt; for automated code review on every PR. It catches things I miss and forces consistency.&lt;/p&gt;

&lt;p&gt;I'm writing a dedicated post about what worked, what didn't, and where AI genuinely accelerated the project versus where it got in the way. Stay tuned.&lt;/p&gt;




&lt;h2&gt;
  
  
  Numbers (honest ones)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;350 commits, 39 releases&lt;/li&gt;
&lt;li&gt;8 contributors: 1 human, 7 bots (Copilot, Gemini, CodeRabbit, Jules, Dependabot, GitHub Advanced Security)&lt;/li&gt;
&lt;li&gt;SDKs published on &lt;a href="https://www.npmjs.com/package/@envilder/sdk" rel="noopener noreferrer"&gt;npm&lt;/a&gt;, &lt;a href="https://pypi.org/project/envilder/" rel="noopener noreferrer"&gt;PyPI&lt;/a&gt;, and &lt;a href="https://www.nuget.org/packages/Envilder" rel="noopener noreferrer"&gt;NuGet&lt;/a&gt; with full CI/CD pipelines&lt;/li&gt;
&lt;li&gt;Used internally across multiple projects at &lt;a href="https://m47labs.com" rel="noopener noreferrer"&gt;M47 AI Company&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Trusted Publishing enabled on PyPI (Sigstore attestations)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/macalbert/envilder/blob/main/ROADMAP.md" rel="noopener noreferrer"&gt;roadmap&lt;/a&gt; includes drift detection (check mode), auto-discovery for bulk parameter fetching, and more provider backends. But the priority is adoption: making it easy for people to try, and making sure it works perfectly for the simple use cases it targets.&lt;/p&gt;

&lt;p&gt;If you manage secrets with AWS SSM or Azure Key Vault and the big platforms feel like overkill, give Envilder a try:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🌐 &lt;a href="https://envilder.com" rel="noopener noreferrer"&gt;envilder.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔧 &lt;a href="https://github.com/macalbert/envilder" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📦 &lt;a href="https://www.npmjs.com/package/envilder" rel="noopener noreferrer"&gt;npm (CLI)&lt;/a&gt; · &lt;a href="https://www.npmjs.com/package/@envilder/sdk" rel="noopener noreferrer"&gt;npm (SDK)&lt;/a&gt; · &lt;a href="https://pypi.org/project/envilder/" rel="noopener noreferrer"&gt;PyPI&lt;/a&gt; · &lt;a href="https://www.nuget.org/packages/Envilder" rel="noopener noreferrer"&gt;NuGet&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd love feedback, especially from people who tried the first version.&lt;/p&gt;

&lt;p&gt;A special thanks to &lt;a href="https://www.linkedin.com/in/brianrinaldi/" rel="noopener noreferrer"&gt;Brian Rinaldi&lt;/a&gt; and the &lt;a href="https://localstack.cloud/" rel="noopener noreferrer"&gt;LocalStack&lt;/a&gt; team for accepting Envilder into the LocalStack for Open Source program. Their fully subsidized Ultimate tier license is what powers our acceptance test suite against a local AWS emulation.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>devops</category>
      <category>ai</category>
      <category>aws</category>
    </item>
    <item>
      <title>From chaos to consistency: how we centralized secrets with AWS SSM and a simple CLI</title>
      <dc:creator>Marçal Albert Castellví</dc:creator>
      <pubDate>Sat, 10 May 2025 16:18:29 +0000</pubDate>
      <link>https://dev.to/macalbert/stop-hardcoding-secrets-generate-env-files-from-aws-ssm-with-a-simple-cli-f77</link>
      <guid>https://dev.to/macalbert/stop-hardcoding-secrets-generate-env-files-from-aws-ssm-with-a-simple-cli-f77</guid>
      <description>&lt;p&gt;At &lt;a href="https://m47labs.com" rel="noopener noreferrer"&gt;M47&lt;/a&gt;, security is one of our concerns across all our AI and cloud-native projects. That’s why we store all sensitive configurations in a secure and centralized place like the AWS SSM Parameter Store. While our repositories are private, that’s not enough. Secrets don’t belong in code.&lt;/p&gt;

&lt;p&gt;We deliberately use &lt;strong&gt;Parameter Store over Secrets Manager&lt;/strong&gt; because our needs don’t require secret rotation or tight lifecycle policies, and SSM gives us all the flexibility and control we need for storing tokens, API keys, and service credentials.&lt;/p&gt;

&lt;p&gt;But then comes the friction:&lt;br&gt;&lt;br&gt;
Every time we onboard someone, clone a project, create/update a new CD pipeline, or adjust a Dockerfile, &lt;strong&gt;we have to manually fetch and sync secrets&lt;/strong&gt;. This leads to overhead, mistakes, and inconsistencies between local and CD pipelines.&lt;/p&gt;

&lt;p&gt;That’s why I built &lt;strong&gt;Envilder&lt;/strong&gt;. A CLI tool to automate the generation of &lt;code&gt;.env&lt;/code&gt; files from a single source of truth: AWS SSM.&lt;br&gt;&lt;br&gt;
It helps us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep secrets in one place (SSM)&lt;/li&gt;
&lt;li&gt;Stay consistent across teams and environments&lt;/li&gt;
&lt;li&gt;Avoid copy-pasting or writing fragile scripts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since we often work with &lt;strong&gt;multiple AWS CLI profiles&lt;/strong&gt;, Envilder also supports switching profiles easily to handle multi-account setups.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/macalbert/envilder" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;&lt;br&gt;&lt;br&gt;
👉 [Full guide continues below ⬇️]&lt;/p&gt;


&lt;h2&gt;
  
  
  💡 What does it do?
&lt;/h2&gt;

&lt;p&gt;Envilder reads a mapping file that links environment variable names to AWS SSM parameter paths. Then it fetches the values securely and writes a clean &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;


&lt;h2&gt;
  
  
  🧩 Example
&lt;/h2&gt;

&lt;p&gt;Your &lt;code&gt;param-map.json&lt;/code&gt; might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"DB_HOST"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/my-app/dev/DB_HOST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"DB_PASSWORD"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/my-app/dev/DB_PASSWORD"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;envilder &lt;span class="nt"&gt;--map&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;param-map.json &lt;span class="nt"&gt;--envfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DB_HOST=mydb.cluster-xyz.rds.amazonaws.com
DB_PASSWORD=supersecret
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also use different AWS CLI profiles:&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="nv"&gt;AWS_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;staging envilder &lt;span class="nt"&gt;--map&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;param-map.json &lt;span class="nt"&gt;--envfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  👥 Why it helps teams
&lt;/h2&gt;

&lt;p&gt;This small tool makes a big difference when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🧑‍💻 &lt;strong&gt;Onboarding new team members&lt;/strong&gt;: no more “what’s the DB password?”&lt;/li&gt;
&lt;li&gt;🔄 &lt;strong&gt;Keeping environments in sync&lt;/strong&gt;: any change in SSM is reflected across the team&lt;/li&gt;
&lt;li&gt;⚙️ &lt;strong&gt;CI/CD pipelines always up-to-date&lt;/strong&gt;: e.g. GitHub Actions, CodeBuild, GitLab&lt;/li&gt;
&lt;li&gt;🧼 &lt;strong&gt;Centralized configuration&lt;/strong&gt;: avoid duplication and keep secrets in one secure place&lt;/li&gt;
&lt;li&gt;🧭 &lt;strong&gt;Supports multiple AWS profiles&lt;/strong&gt;: ideal for multi-account or multi-env setups&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ✅ Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Works with SecureString and plain parameters&lt;/li&gt;
&lt;li&gt;CLI-first, fast, and script-friendly&lt;/li&gt;
&lt;li&gt;Compatible with any CI/CD system&lt;/li&gt;
&lt;li&gt;Supports static values and fallbacks&lt;/li&gt;
&lt;li&gt;AWS profile support (&lt;code&gt;AWS_PROFILE&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📦 Install
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; envilder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;envilder &lt;span class="nt"&gt;--map&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;param-map.json &lt;span class="nt"&gt;--envfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.env &lt;span class="nt"&gt;--profile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;aws-account
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🙌 I’d love your feedback
&lt;/h2&gt;

&lt;p&gt;It’s still an early-stage project, but already helpful in several real-world teams.&lt;/p&gt;

&lt;p&gt;If this sounds familiar, or you’ve solved this differently, I’d love to hear from you.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/macalbert/envilder" rel="noopener noreferrer"&gt;https://github.com/macalbert/envilder&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Update (2026):&lt;/strong&gt; &lt;em&gt;That was stage 1: a CLI that writes &lt;code&gt;.env&lt;/code&gt; files. Envilder has since leveled up with SDKs for three languages, push mode, and Azure support. → Next level: &lt;a href="https://dev.to/macalbert/one-year-of-envilder-from-a-cli-script-to-sdks-push-mode-and-a-website-h49"&gt;One year of Envilder&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>cli</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
