DEV Community

Cover image for Configuration Needs Semantics
bwi
bwi

Posted on

Configuration Needs Semantics

Configuration is everywhere.

It's the mechanism that lets applications change behavior without recompiling, redeploying, or rewriting code.
Timeouts, limits, feature switches, credentials, rollout toggles — configuration is how software adapts to its environment.

And anything that's everywhere is easy to treat as trivial.

In many systems, configuration consists of a boolean here, a string there, maybe a rule evaluated at runtime.
And this works surprisingly well. You can build entire products on top of nothing more than key–value pairs.

But while the code may not care, the people working with the system do.
And that is where problems begin.

This article is not about how to implement configuration. It is about why configuration needs semantics — and what happens when it doesn’t.


Everything Could Be Configuration

Imagine a small billing service with a single config.json:

{
  "paymentTimeoutSeconds": 30,
  "enableNewCheckoutFlow": true,
  "goldPlanAccess": true,
  "stripeApiKey": "sk_live_..."
}
Enter fullscreen mode Exit fullscreen mode

Technically, these are just values.

Semantically, these values represent very different kinds of concerns:
some describe behavior,
some control rollout,
some grant access,
and some should be treated as confidential.

From a purely technical perspective, all of them could be modeled the same way:

  • true / false
  • strings
  • numbers
  • rules evaluated against context

And in many systems, they are exactly that.

This is appealing because it is:

  • simple
  • flexible
  • uniform

But this uniformity comes at a cost.


Why This Works Technically — and Fails Mentally

The runtime does not care why a value exists.
It only cares what the value is.

But humans are different.

When developers, architects, or product owners make decisions based on configuration, they inevitably form expectations.

In many systems, configuration is just a JSON file, an environment variable,
or a key–value store.
From that alone, you cannot tell whether a value represents one kind of configuration or another.

You also cannot answer questions like:

  • how long something is expected to exist
  • who owns it
  • whether it may be removed
  • whether it is temporary or permanent
  • whether it is safe to change

The configuration source is semantically silent.
Expectations come not from the file, but from how values are used in code.

If everything is consumed the same way, then everything means the same thing.

This is not a technical failure.
It is a mental model failure.

Meaning does not come from data types or storage.
It comes from intent.


Semantics Through Explicit Categories

To avoid this, configuration needs more than values.
It needs meaning.

One way to provide that meaning is by using explicit categories.
Not because the system requires them — but because humans do.

Below are four common categories that often get conflated, despite answering very different questions.


Configuration

Defines:

Baseline system behavior.

Characteristics:

  • usually stable
  • changed infrequently
  • no inherent expiration
  • not security-sensitive
  • not contractually relevant

Examples:

  • timeouts
  • thresholds
  • limits
  • algorithm parameters

Configuration sets the baseline behavior of a system.


Secrets

Defines:

Confidential data that must be protected.

Characteristics:

  • security boundaries
  • different storage requirements
  • restricted access
  • often rotated

Examples:

  • passwords
  • API keys
  • certificates

A secret may be “just a string” technically — but semantically it represents a security constraint, not behavior.

A secret stored as a string will eventually be logged — not out of malice, but out of invisibility.


Feature Flags

Defines:

Temporary activation of behavior.

Characteristics:

  • explicitly temporary
  • expected to disappear
  • often tied to rollout or experimentation
  • create maintenance pressure

A crucial aspect of feature flags is expected end-of-life.

Just calling something a feature flag does not make it temporary.
Only active, operational pressure to remove it does.

Without expiration tracking, warnings, or any mechanism that makes overstaying visible, you have not created a feature flag — you have created configuration with a different label.

In other words, the distinction between a feature flag and permanent configuration is not semantic, but operational: if nothing tracks expiry, notifies you of neglect, or surfaces overdue removal, then "feature flag" is just a name that was given once, not a property the system still enforces.

And this expectation strongly influences how developers:

  • review code
  • accept shortcuts
  • tolerate complexity

Entitlements

Defines:

Long-term access to behavior.

Characteristics:

  • stable
  • contractually relevant
  • audit-sensitive
  • rarely removed

Entitlements represent permissions, not rollout state.
They are expected to persist.


Same Mechanism, Different Meaning

From an implementation perspective, feature flags and entitlements may look identical:

  • a boolean
  • a rule evaluated against context
  • a configuration value

But semantically, they create very different expectations.

Aspect Feature Flag Entitlement
Expected lifetime Temporary Long-term
Removal Expected Rare
Review strictness Often relaxed High
Audit relevance* Low High

*Audit relevance here refers to contractual, legal, or billing-related accountability —
not technical logging.

These categories are not immutable — but moving between them should be an explicit decision, not an accident.

When these distinctions are blurred, systems don’t break immediately.
They slowly accumulate misunderstandings.

In many SaaS systems, a single capability goes through both stages:

  • During rollout, it is guarded by a feature flag (for example, enableNewCheckoutFlow).
  • Once stable and part of a paid plan, access is governed by an entitlement (for example, goldPlanAccess).

These are different concerns and often belong to different systems of record.
Confusing them leads to permanent flags and unclear contracts.


Maintenance, Planning, and Self-Deception

The most dangerous failure mode is not technical debt.
It is self-deception.

When something temporary is modeled as permanent — or vice versa — teams begin to lie to themselves:

  • “We’ll clean this up later.”
  • “This is just a flag.”
  • “It’s basically a permission.”

The code still compiles.
The system still runs.

But planning becomes unreliable, and maintenance decisions quietly lose clarity.


Warnings as Support, Not Enforcement

Explicit semantics are not about forcing behavior.
They are about making assumptions visible.

Instead of blocking changes, systems can surface signals:

  • warnings when temporary decisions overstay their intent
  • growing visibility when cleanup is deferred

Nothing is blocked.
Nothing breaks.

But the system no longer allows decisions to remain silent.

This protects developers and architects by turning vague pressure into explicit signals.

This is not enforcement.
It is a way to make assumptions and technical debt visible.


Conclusion

Configuration is not just about values.
It is about expectations.

Without semantics, configuration becomes a generic container where everything looks the same — and therefore means nothing.

Explicit categories do not make systems rigid.
They make intentions visible.

And visibility is often the difference between maintainable systems and ones that quietly drift out of control.

Top comments (0)