If a Heroku config var will not save from the dashboard, the fastest way past it is the CLI, because heroku config:set returns an actual error when something is wrong. The dashboard’s editor fails silently in at least five distinct situations, and the value simply disappears when you navigate away.
This is a genuinely frustrating class of bug because there is no feedback. You type a key, type a value, click something, move to another tab, come back, and the row is gone. No toast, no red text, nothing in the console that looks relevant. Working out which of several unrelated causes applies is the whole task.
Table of contents
- Use the CLI first, because it tells you what happened
- Cause one: the editor has no save button
- Cause two: browser extensions
- Cause three: your role does not permit it
- Cause four: the 32KB limit
- Cause five: you are editing a different app
- What good environment variable practice looks like
- How this fits the rest of the stack
- FAQ
Use the CLI first, because it tells you what happened
Before diagnosing the dashboard, sidestep it. The CLI performs the same operation against the same API and reports failures properly.
# Log in
heroku login
# List current values
heroku config --app your-app-name
# Set one
heroku config:set API_KEY=abc123 --app your-app-name
# Set several at once
heroku config:set DB_HOST=db.example.com DB_PORT=5432 --app your-app-name
# Read one
heroku config:get API_KEY --app your-app-name
# Remove one
heroku config:unset API_KEY --app your-app-name
If the CLI succeeds and the dashboard did not, the problem was the dashboard — a browser issue, covered below — and you can move on with your day.
If the CLI also fails, read the error. It will name the cause: insufficient permissions, an app you do not have access to, a value exceeding the size limit, or an authentication token that has expired. That message is the thing the dashboard was not showing you.
One detail on the CLI: a value containing spaces or shell metacharacters needs quoting, and a value containing a dollar sign will be expanded by your shell unless single-quoted. Setting a password containing a dollar sign without quotes is a classic way to store a truncated value and then spend an hour wondering why authentication fails.
Cause one: the editor has no save button
The most common reason, and it is a user-interface confusion rather than a fault.
The dashboard’s config vars editor has an Add button for new rows, but editing an existing value commits when the field loses focus rather than on an explicit save. If you type a new value and then immediately click away to another section, or close the tab, or hit browser back, the change may not have been committed.
The reliable sequence is: type the value, press Tab or click on neutral space to blur the field, wait a moment, then reload the page and confirm the value persisted. Reloading is the only verification that matters — the field showing your text proves nothing, because that is just what you typed.
For a new variable, the key and value both need filling before Add becomes effective, and an empty key silently does nothing.
Cause two: browser extensions
Content blockers, privacy extensions, and password managers all interfere with this particular editor, and it is a well-attested cause.
Password managers are the worst offenders. They see a field that resembles a credential input, attempt to autofill or offer to save, and in the process disrupt the field’s event handling. The value you typed is replaced, or the blur event that would commit it never fires cleanly.
Ad and tracker blockers can block the API request the editor makes, which fails silently in the page.
The test takes ten seconds: open the dashboard in a private window with extensions disabled and try again. If it works there, an extension is the cause, and you can either exclude the domain or simply use the CLI, which is faster anyway.
Cause three: your role does not permit it
On a Heroku Team or Enterprise account, permissions are granular, and config vars are treated as sensitive because they hold credentials.
A collaborator with view access can see the app and its settings without being able to change them. Depending on the interface version, the fields may render as editable and then reject the change, which produces exactly the silent failure being described.
The CLI is unambiguous here — it returns a forbidden error naming the permission problem. If you get that, the fix is an admin granting you the right role, not anything you can do in the browser.
Apps inside a Private Space or governed by a compliance policy can restrict this further, and in some configurations config var changes are deliberately restricted to specific roles. That is a policy decision rather than a bug, and it is worth confirming with whoever administers the account before assuming something is broken.
Cause four: the 32KB limit
The total size of all config vars for one app is capped at 32KB. Not per variable — the whole set combined.
This sounds generous and is regularly hit by one specific thing: pasting a multi-line private key, a service-account JSON blob, or a full certificate chain into a config var. A single service-account JSON can be several kilobytes, and three or four of them plus normal configuration reaches the ceiling.
When you hit it, an addition fails. The CLI says so; the dashboard tends not to.
Check the current size:
heroku config --json --app your-app-name | wc -c
If that is approaching 32768, the fix is to stop putting large blobs in environment variables. Base64-encoding a key makes it smaller to look at and does not make it smaller in bytes — it makes it larger. The right answer is to reference a secret held elsewhere, or to reduce what is stored. Large credentials in environment variables is a pattern that hits a wall on every platform eventually, not just this one.
Cause five: you are editing a different app
Worth stating because it accounts for more of these than anyone likes to admit.
Pipelines with review, staging, and production apps produce several similarly named entries in the dashboard, and browser tabs left open from an earlier session point at whichever app you were looking at then. Setting a variable perfectly successfully on the staging app while testing production is indistinguishable from the variable not saving.
Always pass —app explicitly on the CLI rather than relying on the git remote, and read the app name in the dashboard header before typing. Then verify by reading the value back from the app you actually care about.
The same applies to the deploy that follows. Config var changes restart the dynos, and if you changed the wrong app, the restart happened somewhere you were not watching.
What good environment variable practice looks like
Stepping back from the immediate problem, this class of frustration comes from configuration living in a dashboard that a person edits by hand and nobody audits.
A few habits that hold on any platform:
- Configuration lives in the platform, not in a committed file. A .env in the repository is the failure this whole mechanism exists to prevent.
- Every variable the application requires should be validated at startup, with a clear error naming what is missing. Silent undefined values that surface as a null reference three layers deep waste far more time than an explicit check.
- Keep an .env.example in the repository listing every key with no values, so a new developer knows what to ask for.
- Environment differences should be values, not code paths. If production behaves differently because of an if statement rather than a variable, the difference is untestable.
- Rotating a credential should be one change in one place, applied on the next deploy. If it means editing several dashboards, it will not happen on schedule.
On RunxBuild, environment variables are set per service and applied at deploy, and the deploy that applied them is in the history alongside the build log — so a configuration change is a recorded event with a rollback target rather than an unlogged edit somebody made in a browser tab.
How this fits the rest of the stack
Config vars that will not save are almost always the dashboard rather than the platform, and the CLI resolves the ambiguity in one command because it actually reports errors. The deeper point is that configuration edited by hand in a browser, with no record of who changed what, is fragile regardless of which platform is hosting it. Keeping variables per service and applying them through a deploy that appears in the history makes a bad value something you can roll back rather than something you have to remember. If you are pricing a move, the RunxBuild hosting calculator shows the service and database as separate line items.
Useful related references:
- Heroku Env Variables: The Config Vars, the .env Mismatch, the Secret Manager, and the Migration to Modern Platforms
- PostgreSQL View Can’t Edit: Why Your View Is Read-Only and How to Fix It
- Can’t Open the SSH Pub File? Here’s What’s Going On
- Services on RunxBuild
FAQ
Why can I not add config vars in the Heroku dashboard?
The usual causes are a browser extension interfering with the field, a role without permission to change them, the combined 32KB size limit being reached, or the editor never committing because the field did not lose focus. Run the same change with heroku config:set, which returns an actual error naming the cause.
Is there a limit on Heroku config vars?
Yes, 32KB total across all config vars for an app, not per variable. It is most often hit by pasting service-account JSON blobs or private keys. Check with heroku config —json | wc -c. Base64-encoding does not help, since encoding makes the value larger rather than smaller.
How do I set config vars from the command line?
heroku config:set KEY=value —app your-app-name, with several key-value pairs in one command if needed. Quote values containing spaces, and single-quote anything with a dollar sign so your shell does not expand it — storing a truncated password this way is a common and confusing mistake.
Do config vars require a restart to take effect?
Changing them restarts the dynos automatically, so the new values are live on the next boot. Code that reads an environment variable once at startup will not see a change without that restart, which is why the platform triggers one rather than leaving it to you.
Are config vars secure enough for secrets?
They are the intended place for credentials and considerably better than a committed file. The limits worth knowing are that anyone with access to the app can read them, they appear in some log and error contexts if your code prints them, and there is no per-variable audit trail. For high-sensitivity credentials, reference a dedicated secret store instead.