Stevic International Limited

The boring parts of web development are the parts that ship

· Stevic Admin
The boring parts of web development are the parts that ship

A client asked us last month which framework they should use for a new internal app. We said the boring one. They were disappointed. They had hoped we would pick something interesting.

Six weeks later, the app was in production and the only ticket their team had filed was a request to change a colour.

That is the trade we keep arguing for. And here is why it is a hard sell.

The shiny thing is rarely the bottleneck

When you are early in a project, the technology choices feel enormous. React or Vue. Next or Remix. Vercel or self-hosted. Postgres or SQLite. People agonise.

Then you start building, and you realise the thing slowing you down is not your framework. It is that nobody decided whose name appears on invoices. Or what happens when an admin deletes a customer with open orders. Or how the import file gets validated before half a thousand rows get rejected silently.

The framework helps with about 5% of those decisions. Everything else is product work that has to happen in any stack.

Boring tech, fast iteration

The internal app I mentioned uses Laravel, server-rendered Blade templates, a sprinkle of Alpine.js for tiny interactions, and Tailwind for styles. It runs on a single small VM with Postgres on the same machine. No SPA. No JSON API. No state management library. No build pipeline beyond npm run build.

The team that uses it does not care. They click links, fill forms, and get work done.

What they do care about: it loads fast on bad connections (we have offices in places with patchy 4G), it works on whatever browser is on the office laptop, and the admin can change a label without a redeploy.

That last bit cost us nothing to build. It would have cost a fortune if the app had been an SPA on top of a separate API — every label change becoming a coordination problem across two codebases.

The default that is wrong for most teams

The default these days is React + a JSON API + a separate backend. For consumer products at scale, that makes sense. For most internal tools and small-to-mid SaaS, it is overkill. You pay for:

  • Two deployments instead of one.
  • Two test suites.
  • Loading state, refetch state, optimistic state, error state — for every interaction.
  • A larger attack surface.
  • A bigger team to maintain it.

For what gain? Smoother transitions and the option to ship a mobile app later. If those things are not your bottleneck right now, you are paying upfront for problems you do not have.

How we pick what to use

A short checklist we actually use:

  1. What language does the team already know? Add a new language only with a good reason.
  2. How much realtime do we actually need? "Realtime" is often "five seconds is fine."
  3. Who is going to maintain it in two years? If the answer is "we will hire someone," pick what is easy to hire for, not what is clever.
  4. What is the smallest thing that solves the problem? Build that. Add complexity only when something breaks.

The unfun conclusion

Most web applications are CRUD with auth, an admin panel, a few reports, and an email or two. The technology to do that has been solved for fifteen years. The interesting work is in modelling the problem correctly, writing the right validations, and shipping fast enough to learn what your users actually need.

We pick the boring stack so we can spend our attention on the part that is hard