Files
member-console/docs/settings-and-configuration.md
T
cgalo5758 e581bf81c3 Add typed config keys and config CLI
Parse every config value through a single declared type at save, boot,
and validate, and expose the settings seam from the terminal so
operators can list, set, clear, and validate overrides without SQL.
2026-09-05 17:47:04 -05:00

12 KiB

title, audience, summary
title audience summary
Settings and Configuration
developer
admin
Why software uses two words for what a program is told, what each word carries, a rule for choosing between them, and how this console applies the rule.

Settings and Configuration

Most software that runs for other people ends up with two words for the same underlying thing: the values a program is told rather than born with. A page in the product says Settings. The file on disk, the environment variable, the flag, the command line and the code that reads them say config or configuration. Teams often treat this as sloppiness and try to pick one word. This document argues that the two words are doing real work, says what each one carries, gives a rule you can apply, and shows how the member console applies it. It is written for people building any software with a settings surface, not only for this codebase.

Two words, two doors

Think of a product as one store of values with several doors into it. Each door has a convention, and the word follows the door.

"Configuration" is the word on the deployer's doors. It names how a running process is told things by whoever installs and operates it: a file it reads at start, an environment variable, a command-line flag, a declaration in code that says a key exists and what type it has, and the command-line tool that reads and writes those. The Twelve-Factor App defines the term this way: "an app's config is everything that is likely to vary between deploys," and it excludes "internal application config" that does not vary between deploys (12factor.net/config). Kubernetes uses the same sense: a ConfigMap exists to "decouple environment-specific configuration from your container images" (kubernetes.io).

The command line belongs to this side even though a human types into it. The convention is unanimous. Git's config command reads and writes "configuration variables" in scopes named after where the file lives: system, global, local, worktree (git-scm.com). kubectl config is documented as "Modify kubeconfig files" (kubernetes.io). npm config is documented as "Manage the npm configuration files", with set, get, delete and list subcommands (docs.npmjs.com). gcloud config sets and lists properties of the current configuration (cloud.google.com). Someone at a terminal expects config; a settings command beside migrate and start asks them to translate.

"Settings" is the word on the product's door. It names what someone changes from inside the product, on a page with controls, expecting the change to take effect and to be there next time. macOS renamed System Preferences to System Settings in macOS Ventura and redesigned the app to look like the one on iOS (Wikipedia); Apple's own guide for it is titled "Customize your Mac with System Settings" (support.apple.com). Windows, Android, GitHub, GitLab, Stripe's dashboard, Grafana and WordPress all put the word Settings on the page a person opens to change things.

The two words are not two kinds of value. The same value is often both: a port number is configuration to the person who wrote it into an environment variable and a setting to the person who reads it on an admin page, greyed out, with "from the environment" beside it. What changes is which door you came in through.

The same product, both words, on purpose

The clearest evidence that the split is deliberate is how many products keep both words and keep them apart.

Product The page's word The deployer's word Where the seam is
Visual Studio Code the Settings editor settings.json, and Command Palette entries still named "Preferences: Open User Settings (JSON)" the editor "is the user interface that enables you to review and modify setting values that are stored in a settings.json file" (code.visualstudio.com)
Firefox the Settings page (about:preferences) the preferences system libpref, with defaults from pref data files and user values in prefs.js and user.js, edited raw at about:config, whose support article is titled "Configuration Editor" the page shows a curated subset; the editor shows every pref by its internal name (firefox-source-docs.mozilla.org)
PostgreSQL SHOW and SET for "configuration settings" inside a session, the pg_settings view postgresql.conf, "configuration parameters", ALTER SYSTEM, which the manual calls "functionally equivalent to editing postgresql.conf" the file and the SQL command write the same parameters; the words follow the door you came in through (postgresql.org)
macOS System Settings property lists and the defaults command the app is a view over the same keys the command line writes
npm none; a command-line tool has one door npm config set, .npmrc one door, one word (docs.npmjs.com)

Read the table as one pattern. The door with a page on the other side says settings. The door with a file, a flag, a terminal or another program on the other side says configuration. VS Code even keeps a third word, Preferences, in the menu that opens the first door, a leftover from an era when personal software said preferences for what business software said options.

A rule you can apply

Choose the word by door, not by value and not by whether a human is present.

  1. The product's pages say "settings": page titles and leads, the admin panel, help text on those pages, and documentation addressed to the people who use them. An environment-sourced or infrastructure value is still a setting on a page; show it with its source, and read-only where it cannot change at runtime.
  2. The deployer's doors say "config": the declaration of a key and its type, the environment variable, the config file, the flag, the code that layers them, boot validation, the command-line tool, and documentation addressed to the people wiring a deployment.
  3. Never let the doors disagree about the value. One parser, one store, one set of rules, however many doors. A value refused on the page is refused at the terminal with the same sentence, and a value the page would not accept is not one a config file may contain either.
  4. Do not invent a third word for the case where a value happens to be both. "Options", "preferences" and "parameters" each have a history, and adding one to a product that already has two words makes the reader guess which of three things they are looking at.

Two consequences follow. A product with one door needs one word: a command-line tool with no admin page says config everywhere, as npm does, and a consumer app with no deployer says settings everywhere. And a product with both doors should expect its words to meet at a seam and should name the seam once, in writing, so nobody has to rediscover it.

When people get it wrong

The common failure is the deployer's word leaking onto the page. A page titled Settings whose first sentence says "Runtime configuration for Stripe" is telling the person that the thing they are about to edit belongs to someone else. The console had exactly that sentence until 2026-09-05.

The opposite failure is the page's word leaking into the deployer's doors. A command group named settings beside migrate and start, reached from a terminal where every other tool says config, asks the deployer to learn a private word for a public convention. The console had that for about an hour on the same day, because the first draft of this rule said "any door a human uses says settings" and the maintainer asked whether a command was not "more code than interface". It is: the terminal is the deployer's door, whoever is typing.

A third failure is mixing within one door: validate-config beside settings set and settings clear in the same command list. The reader has to know that the first word means the second.

How the member console applies it

The console has both doors and one store, so it uses both words and keeps them apart.

  • The pages say settings. The operator panel's pages are titled "Stripe settings" and "FedWiki settings"; the deferred deployment-wide page is "Instance settings"; the person-facing specification is integration-settings. The settings page lead says "Each setting uses its override if one is stored, otherwise the environment value, otherwise its default."
  • The deployer's doors say config. A key is declared as a ConfigKey with a value type in internal/config; the environment reference documents "configuration keys" for whoever wires a deployment; the boot overlay layers stored overrides over environment values; boot validation parses every value through one parser; the command group is member-console config, with list, set, clear and validate; the specification for the declaration seam is integration-config-declaration.
  • The seam is one store, one parser, two doors. Stored overrides live in one table; the page and the command line reach it through one settings service, and both parse a value with the same function, so a refusal reads the same on the page, at the terminal, and in a boot that finds a bad stored value. The two backing stores the console happens to have (the boot-applied overlay and a small runtime table) are an implementation split behind one surface, not a distinction the person sees.
  • A value from the environment is still a setting on the page. The settings page lists environment-sourced keys with their source and shows them read-only; the future instance settings page extends the same treatment to the console's own infrastructure keys. This was the maintainer's ruling when a narrower line was proposed: "Ideally we'd want all configs as instance settings, even if they are display only because they are infra stuff."

The rule is normative for this repository in the ui-vocabulary specification ("The word follows the door"), which is what stops it from depending on anyone's memory.

Sources