How I run LocalStack without committing LOCALSTACK_AUTH_TOKEN

How I run LocalStack without committing LOCALSTACK_AUTH_TOKEN

1 6
calendar_today agoschedule4 min read
— Originally published at dev.to

Using Envilder to keep the LocalStack auth token out of Git while preserving a reproducible local Docker Compose setup.

I wanted a reproducible LocalStack setup without committing LOCALSTACK_AUTH_TOKEN to the repository.

That sounds simple, but it touches a common local development problem:

How do you make a project easy to run without putting real secrets in Git?

LocalStack expects the auth token to be available through the LOCALSTACK_AUTH_TOKEN environment variable when starting it with Docker, Docker Compose, the LocalStack CLI, or CI workflows.

Since LocalStack for AWS 2026.03.0, it ships as a consolidated Docker image and requires an auth token to start, so managing LOCALSTACK_AUTH_TOKEN cleanly is now part of the normal setup path, not just a Pro-only edge case.

That token is a secret, so I did not want to:

  • commit it to the repository
  • paste it into docker-compose.yml
  • duplicate it across helper scripts
  • rely on a manual export LOCALSTACK_AUTH_TOKEN=... step every time
  • make the setup work only on my machine

What I wanted instead was a small, repeatable contract:

this project needs LOCALSTACK_AUTH_TOKEN
resolve it from the secret store
inject it locally when needed
do not commit the value

That is the pattern I ended up using with Envilder.

The Pattern

The idea is simple:

  • secret values stay in a real secret store
  • the repository contains only the mapping
  • local development generates a .env file from that mapping
  • Docker Compose reads the generated .env
  • the token never gets committed

In this case, the secret is LOCALSTACK_AUTH_TOKEN.

In another project, it could be a database password, webhook secret, API key, or service credential.

Defining the Secret Mapping

Here is a minimal envilder.json example using AWS SSM Parameter Store:

{
  "$schema": "https://envilder.com/schema/map-file.v1.json",
  "$config": {
    "provider": "aws",
    "profile": "default"
  },
  "LOCALSTACK_AUTH_TOKEN": "/envilder/localstack/auth-token"
}

This file is safe to commit because it does not contain the token.

It only says:

_To produce LOCALSTACK_AUTH_TOKEN, resolve this value from the secret store._

The actual token remains outside the repository.

Generating the Local .env

Before starting LocalStack, generate the local environment file:

npx envilder --map=envilder.json --envfile=.env

That produces a local .env file like this:

LOCALSTACK_AUTH_TOKEN=...

The .env file should be ignored by Git:

.env

Now the project contains the setup contract, but not the secret.

Passing the Token to LocalStack

A Docker Compose service can reference the variable as usual:

services:
  localstack:
    image: localstack/localstack:stable
    ports:
      - "4566:4566"
      - "4510-4559:4510-4559"
    environment:
      LOCALSTACK_AUTH_TOKEN: \$"{LOCALSTACK_AUTH_TOKEN:?Run npx envilder first}"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"

Docker Compose automatically reads a .env file from the project directory for variable interpolation.

If your generated env file lives somewhere else, you can pass it explicitly:

docker compose --env-file path/to/.env up

The payoff is what a new contributor sees after cloning:

npx envilder --map=envilder.json --envfile=.env
docker compose up

Two commands, no Slack message asking "where do I get the token?", no secret in Git.

Why not direnv, 1Password, or chamber?

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

  • direnv loads env vars when you enter a directory, but .envrc is just shell. You still write export LOCALSTACK_AUTH_TOKEN=$(aws ssm get-parameter ...) yourself, per variable, per project. It is a loader, not a resolver, and the mapping lives in bespoke shell instead of a declared contract.
  • 1Password op run 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.
  • chamber is the closest match for the AWS-only case:
    chamber exec service -- docker compose up 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.

Envilder's narrow bet is different on three points:

  1. The mapping is an explicit name -> path contract committed as JSON, not a service prefix or shell glue.
  2. The store is your own cloud. No third-party infrastructure holds the secret.
  3. The same map drives the CLI here, CI, and in-process resolution through the SDKs, so local dev and runtime read one contract.

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.

The Slightly Meta Part

I ran into this while working on Envilder.

Envilder uses LocalStack for integration testing.

LocalStack needs LOCALSTACK_AUTH_TOKEN.

So I used Envilder to inject the token needed to start the LocalStack environment used to test Envilder.

Envilder uses Envilder to inject LocalStack token

The tool became its own first customer, which is always a useful kind of feedback.

A Note on LocalStack Auth Tokens

LocalStack's documentation is clear that LOCALSTACK_AUTH_TOKEN should be kept confidential and should not be committed to source control.

This post is not about bypassing that requirement.

It is about treating the token like any other secret:

  • store it safely
  • resolve it when needed
  • avoid leaking it into Git
  • keep the project setup reproducible

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.

Takeaway

LOCALSTACK_AUTH_TOKEN is just one example of a broader problem.

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.

The pattern I like is:

secret values outside Git
secret mappings inside Git
one contract for local dev, CI/CD, and runtime

That is the reason I am building Envilder.

Not to add another place to store secrets.

Just to make secret resolution explicit, repeatable, and versionable.

173 Points7 Badges1 6
Barcelonaenvilder.com
2Posts
2Comments
Build your own developer journey
Track progress. Share learning. Stay consistent.
🔥 Join developers growing publicly
Share your knowledge, build in public, and grow your developer presence with a global community.

More Posts

I’m a Senior Dev and I’ve Forgotten How to Think Without a Prompt

Karol Modelskiverified - Mar 19

How I Built a React Portfolio in 7 Days That Landed ₹1.2L in Freelance Work

Dharanidharan - Feb 9

How to Reduce Your AWS Bill by 50%

rogo032 - Jan 27

Implementing Cellular Redundancy: Cross-Cloud Failover with AWS Transit Gateway and Azure ExpressRou

Cláudio Raposo - May 5

Designing a Multicloud Cellular Architecture for Blast Radius Containment

Cláudio Raposo - May 4
chevron_left

Related Jobs

Commenters (This Week)

1 comment
1 comment
1 comment

Contribute meaningful comments to climb the leaderboard and earn badges!