It's been a while since the Twelve-Factor App was created. Does it still hold up?
When your app needs secrets, like API keys, managing them in files can be difficult. That's why the 12-factor app architecture recommends using the UNIX environment.
For most teams and apps, this is still a great solution. Most hosting environments allow control over the UNIX environment available to an app that's running, and they allow changing the values of the various variables without having to redeploy the app.
This can be useful when you need to rotate a secret. You can change the value, restart the app and now you are using the new value.
To safely rotate secrets without downtime, you need to be able to make sure both the old and new secrets are valid at the same time. When you create the new one and trigger a restart of your apps, you'll have older ones running with the old secret.
Depending on how the secret is managed by the third party, you can often do the rotation, then check with the third-party to make sure the old secret isn't being used. Once you are confident it's not, delete it.
Putting config in the environment may seem like a pain for local development since you don't want to set a bunch of environment variables in your local shell just to work on a specific app. Fortunately, most app ecosystems provide a way to do this, like Ruby's dotenv, or Node's dotenv, or even the programming-language agnostic direnv.
The great thing about using libraries like this is that your app doesn't have to check if it's running in production or development in order to figure out where configuration is stored—it can always use the UNIX environment.
Plus, you can check these dotenv files into version control and use them for documentation. I like to include instructions on where the secrets came from and how to generate them, for example:
# We get webhooks from Intercom
#
# The real one available from Intercom's Web UI:
# https://app.intercom.com/a/apps/XXXX/developer-hub/app-packages/YYYY/basic-info
INTERCOM_CLIENT_SECRET=fake
# We use the Sendgrid API to send transactional emails.
#
# Generate a new API key here: https://app.sendgrid.com/settings/api_keys
# You should not need real keys locally.
SENDGRID_API_KEY=fake
The UNIX environment isn't great for highly structured information, such as translations or framework configuration. Fortunately, this type of configuration doesn't need to be changed on the fly. It can be stored in structured files like JSON, YAML, or source code.
To make changes to this sort of data, you'll need to make a code change and re-deploy the app. This is usually fine, since a) you might want a code review of changes to complicated data structures, and b) the data shouldn't be changing that often or with such immediacy that it can't wait for CI build and deploy.
It's hard to keep up with everything, and sometimes I learn something that has been common knowledge for a while. Maybe this happens to you.
I've been writing a lot of JavaScript recently, exploring Web Components (check out some posts on my blog for a preview of what I've been working on). It has required a lot of debugging. I've been using esbuild to compile all the JavaScript.
Well, today I learned that if you --minify
JavaScript, it will change all the class names. I do a lot of console.log("%s: some message",this.constructor.name)
so I know where console messages are coming from. this.constructor.name
is the class name and when it's rewritten it…doesn't work so well.
I guess this is maybe obvious to most people? I like the class names (and other names) to be preserved, so for esbuild anyway, I'm using --minify --keep-names
.
Unless otherwise noted, my emails were written entirely by me without any assistance from a generative AI.