Stop Configuring Everything: Why Conventions Win

Open laptop with code on screen and notebook

I’ve walked into more projects than I can count that kicked off with a “simple” config file and somehow mutated into a sprawling YAML mess. The kind of mess that takes longer to untangle than building the actual feature. It’s a tired pattern across tech: we grab configuration because it feels responsible and flexible, then we choke on the complexity we invited. The alternative—convention—gets dismissed as training wheels. That’s a mistake.

Convention isn’t the absence of design. It’s a deliberate choice to quit making the same damn decisions over and over. Configuration isn’t evil; it’s just handed out like candy at a parade. Most teams don’t need a thousand knobs. They need something that works, and works the same way every single time. This piece digs into what configuration and convention actually mean, where each one earns its keep, and why I’ll reach for convention first. Every time.

What Configuration Actually Means

Configuration is an explicit set of instructions. You spell out exactly what you want—usually through files, environment variables, CLI flags, or some UI. The pitch is control. Don’t like a behavior? Flip a value and the system bends. In theory, nothing’s welded shut; everything’s adjustable.

In practice, configuration turns into a liability the second you have more than one environment. Dev, staging, prod, Bob’s laptop that runs a slightly off-kilter OS—each one needs its own tweak. Before you know it, that clean config file sprouts conditionals, overrides, and secrets nobody remembers to rotate. The control you grabbed gets burned on managing the control itself.

I’ve watched teams lose days chasing a misconfigured timeout buried three layers deep in a Helm chart. That’s not engineering. That’s digital archaeology. Configuration doesn’t shrink complexity—it shoves it into a corner and calls it flexibility.

What Convention Actually Means

Convention is a paved path. The system makes a call for you based on an agreed pattern, and you walk it. Rails is the poster child: models go in app/models, controllers in app/controllers, and everything clicks together. You don’t hand-crank the routing table unless you’ve got a bloody good reason to stray.

The muscle of convention isn’t laziness. It’s consistency across time and people. A fresh developer jumps in and already knows where stuff lives because every Rails app looks roughly identical. When I crack open code I wrote six months ago, I’m not rebuilding the mental map of some bespoke directory structure I dreamed up at 2 a.m.

Conventions document themselves, too. A file in migrations/ is obviously a migration. No README required to explain that “database change scripts live in db_scripts, except seed data which hangs out in bootstrap but only for staging.” The structure carries the meaning.

The Trade-off Nobody Talks About

Configuration fans will tell you conventions are rigid. They’re not wrong—rigidity is the whole point. It’s a feature when you’re trying to keep five or fifty people rowing the same direction without endless sync meetings. Every “flexible” decision you bless today is a decision somebody else has to reverse-engineer tomorrow.

The real swap is between decision fatigue and customizability. Configuration hands you infinite customizability in exchange for infinite decisions. Convention hands you zero decisions for the common path and forces you to justify any detour. I’ll take the latter. Most detours aren’t justified—they’re preferences wearing a requirements disguise.

Think about your last project. How many config values were genuinely business-critical versus “someone thought it’d be neat to change the background color without a redeploy”? Yeah.

Whiteboard with software architecture diagrams

When Configuration Wins

I’m not burying configuration. It’s the right tool in clear-cut cases:

  • Operational secrets: API keys, database passwords, certificates. These can’t be hardcoded or guessed by convention. They have to be injected from a secure source at runtime.
  • Environment-specific behavior: A payment gateway URL is different in staging versus production. Convention can’t divine that, and you wouldn’t want it to. A handful of environment variables handles this without drama.
  • True multi-tenant systems: Building a SaaS where each customer has genuinely different workflows? You need configuration. But even then, you’d better ship strong defaults and a schema that stops customers from painting themselves into a corner.

The thread tying these together: they’re external constraints. They come from the operating environment or the business domain, not from an engineer’s itch to tweak. When the outside world forces variation, configuration absorbs it. When the variation is homegrown, configuration just rationalizes it.

When Convention Wins

Convention wins just about everywhere else. Project structure, build pipelines, naming standards, code organization. It wins in frameworks that obsess over the 80% use case and optimize the hell out of it. Django’s admin, Spring Boot’s auto-configuration, Next.js file-based routing—these aren’t happy accidents. They’re tools that say, “We know what you’re up to, and we already handled the boring bits.”

The quiet superpower here is tooling support. Linters, formatters, static analyzers, IDE plugins—they all hum along better with convention. They can make safe bets because the codebase isn’t a special snowflake. When you fight the convention, you pick a fight with the tools too. That means more grunt work, more bugs, and more hours burned on stuff that ships zero value.

I once watched a team decide to reorganize their React component folder layout to be “domain-driven.” They burned two weeks arguing about what a domain even was, then another month shuffling files. The app behaved exactly the same after. Zero user value. Pure convention-violation tax.

How to Choose Without Overthinking

Here’s my rule of thumb: configure only what varies by environment or by tenant. Convention everything else. If you’re setting a config value that’s identical across every environment, it’s not configuration—it’s a constant that wandered into the wrong file. If you’re inventing a directory layout that’s unique to your project, you’re erecting a learning curve that has no reason to exist.

Start with the framework’s defaults. If the framework doesn’t hand you a convention, grab the dullest, most obvious pattern available and write it down once. That’s your team’s convention now. Don’t debate it for three sprints. Don’t schedule a design review. Make the call, log it in a one-page ADR, and move on. The specific convention matters far less than the fact that there is one.

Fight the temptation to “future-proof” with extra configuration. You won’t need that config toggle for a database migration strategy that might materialize in two years. You’ll forget it exists, and it’ll rot. When the future actually shows up, you’ll have more context and can make a sharper decision then. Premature configuration is the root of plenty of evil.

Developer working with multiple monitors

The Social Layer

Configuration versus convention isn’t just a tech debate. It’s a people debate. Configuration says, “I trust you to make the right call.” Convention says, “We’ve already agreed on a right call, so let’s all use it.” The first approach scales to one person. The second scales to a team.

I’ve noticed that loud opinions about configuration often come from senior engineers itching to express individuality through code. That’s fine for a side project. It’s a drag on a team that needs to ship and onboard people fast. The best engineers I’ve worked with are aggressively boring. They grab conventions, stick to them, and aim their creativity at the gnarly problems that actually set the product apart.

If your configuration file outweighs your business logic, you’ve lost the thread. The code should say what the application does; configuration should only say how it plugs into things outside its control. Everything else is noise.

FAQ

Is convention just for frameworks like Rails or Django?

Hardly. Conventions sprout anywhere a pattern repeats. Even inside a custom Go microservice, you can plant conventions: drop handlers in handlers/, business logic in services/, use the same logging shape everywhere. Frameworks productize conventions, that’s all. You can—and should—grow your own where frameworks don’t reach.

What if my project honestly needs a lot of configuration?

Then own it, but own it carefully. Validate configuration at startup, not deep in the stack at runtime when it blows up. Reach for strongly typed config objects instead of magic strings. Shrink the configuration surface as much as you can—every knob you add is a knob someone will twist wrong. And document the living hell out of it, because the next person won’t share your context.

How do I nudge my team toward more conventions?

Don’t lead with philosophy. Lead with the pain. “We lost four hours debugging that YAML indentation fiasco last sprint. If we’d used the framework’s default config format, that headache wouldn’t exist.” Then pitch one specific convention, roll it out, and let the outcome do the talking. People shift when the current way stings, not when they’re handed a lecture about a better way.

Can conventions be changed later?

Sure, but you’d better have a sharp reason. Changing a convention forces every contributor to unlearn and relearn. That cost is real and almost always underestimated. I treat convention changes like API breaking changes: they demand a migration plan, clear communication, and a payoff that’s worth the disruption. If the payoff is “I like this way better,” it’s not enough.

At the tail end of a long project, the code you didn’t write and the choices you didn’t make are often the heaviest contributors to success. Configuration feels like power. Convention is actual power—the power to quit reinventing wheels and start shipping. Pick accordingly.