How we build, and why
Four decades of shipping, distilled into a handful of convictions - about owning your stack, committing to your database, and choosing boring tools that still work in five years.
The premise - software should last
Software should remain understandable, maintainable and deployable for many years. This is not an aspiration. It is a constraint that every engineering decision within Reepolee exists to satisfy.
Why modern web engineering
needs rethinking
- Framework churn - what you chose last year is already legacy.
- Dependency growth - each new feature adds transitive dependencies you didn't choose.
- Abstraction overload - layers of indirection that hide the actual behaviour.
- Operational complexity - infrastructure that requires dedicated teams to manage.
- Vendor dependence - migration costs that make leaving impossible.
The principles
These aren't preferences. They're conclusions - formed by maintaining what we built years later, and by watching the comfortable alternatives fail in slow, expensive ways.
There is an unofficial ranking in this industry that assigns credibility based on what you use, and we stopped paying attention to it a long time ago. We pick technology for the job in front of us, not for what it signals to other developers: the language a whole team can actually read, the database your people know well enough to debug at two in the morning, the editor and the operating system you happen to think fastest in.
A theoretically superior tool that nobody on the team can operate under pressure is the wrong tool. The software we ship has never once cared which setup it was written on, and in the end, neither do we.
We grew tired of opening a project that ran fine six months ago and losing a day to untangling dependencies before writing a single line of business logic. So we shrank the part we own down to almost nothing: zero runtime dependencies, and the few third-party files that remain are downloaded once, read, and committed straight into the repository rather than pulled fresh from a registry that can change its mind or vanish overnight.
The smaller the surface you do not control, the fewer surprises arrive at the worst possible moment. The goal is a simple one - to open the project after half a year and have it feel exactly like the day you left it.
AI tools are genuinely useful and we reach for them every day, but most of the work we see handed to them does not actually need thinking - it needs consistency. Anything with a correct, stable, codifiable answer belongs in a generator, not in a probabilistic guess that costs money on every call and drifts a little each time five developers phrase the same request five different ways.
We encode the conventions once - the naming, the validation, the transaction boundaries, the rules a domain quietly depends on - review them together, and apply them everywhere without variation. The model is for the genuinely novel, hard reasoning; the generator is for consistency, and consistency is what a business is really paying for when it buys software.
There is a piece of received wisdom that says you should design every application so the database can be swapped out at any moment, and for most projects it is a comfortable fiction that quietly costs far more than it ever returns. In practice the database is almost never replaced, so we treat it as what it really is: permanent, and the single source of truth.
That means using what it actually offers - real SQL you can read, views, constraints, deliberate column names chosen before a line of code is generated - rather than hiding it behind a layer that pretends every database is the same. You pay for that imagined portability every single day, in features avoided and complexity added, for a migration that in all likelihood will never come.
Simplicity is not a concession made by a team too small to do things properly - it is a deliberate choice, and for the small to mid-sized applications we build it is usually the correct one. The right amount of complexity is as little as the problem genuinely demands: no build step standing between the code and the running server, each feature living in its own folder instead of scattered across technical layers, a modern browser baseline rather than a decade of accumulated workarounds, sensible defaults instead of endless configuration nobody remembers the reason for.
Every layer you choose not to add is a layer that cannot fail, cannot be exploited, and cannot stand between you and the running code when something finally goes wrong at the worst possible time.
Where your software runs is a business decision with real consequences, not a technical detail to leave to whoever happened to set up the account. For the kind of organization we build for - the ones with a known, bounded audience rather than millions of strangers - the honest answer is often your own modest server, on a small VPS or sitting quietly in the building itself.
The cost is predictable to the cent, the control is genuinely yours, the data-protection story is as simple as knowing exactly where the data lives, and the application keeps working when the internet, or someone else's data center, has a bad day. The deployment is unglamorous on purpose: pull the latest code, restart the process, and it is done.
Most of what we build on is deliberately boring: server-side rendering, SQL, code generation - old ideas the industry briefly convinced itself it had outgrown and is now quietly returning to, because they never actually stopped being correct. The one genuine frontier bet is the runtime underneath, which we adopted early and on purpose, and that kind of early, hands-on experience compounds in a way no blog post can hand you later.
Boring where it should be boring, early where it is worth being early. The payoff is a single project that can bend from a static marketing page into an authenticated admin panel without being thrown away and rewritten the moment a client changes direction. Over five years, the boring choice almost always wins.
Not all software carries the same stakes, and pretending it does is one of the more expensive mistakes of the last decade. When a like count is wrong for thirty seconds nobody is harmed; when an invoice goes out for the wrong amount, everyone is harmed, loudly and at length.
So we hold a different standard for the code that touches money, inventory, or records - the rigor this work always deserved before anyone was in a hurry: real tests around the edge cases that actually matter, real human review of anything important, and configuration that fails loudly and refuses to start rather than limping forward on a silent default that quietly does the wrong thing. Speed is wonderful, but it is never an excuse to ship something that is wrong.
Architecture - how principles shape structure
The architecture follows from the principles rather than dictating them. Server-side rendering means the application is a request-response cycle, not a client-side state machine. Minimal dependencies mean the dependency graph is shallow enough to reason about. Explicit routing means the structure of the application mirrors its URL structure.
Every architectural decision in Reepolee exists because the alternative would violate one of the principles - not because it is fashionable.
Development workflow - engineering, not project management
- Understand the problem before designing the solution.
- Design explicitly - document the architecture before writing code.
- Build incrementally - ship small, measurable changes.
- Control complexity - each addition must justify its cost.
- Continuously simplify - refactor as understanding deepens.
- Maintain ownership - the team that builds it maintains it.
Operational principles - how we deploy and run
- Predictable deployment - pull the latest code and restart.
- Secure tunnels - development and deployment without exposing ports.
- On-premise capability - your infrastructure, your control.
- Infrastructure ownership - knowing where your software runs means knowing how it behaves.
- Operational transparency - logs, metrics, and observability built in.
Reference implementation - the Reepolee System
The Reepolee System is the commercially licensed production-ready implementation of every principle on this page. It exists to prove that these principles can be embodied in working software - not just described in documentation.
Static first - grow without migrating
Not every project needs a server on day one. ReeWeb, our free standalone static site generator, is the first rung: extract the archive, run bun dev, and bun ssg renders a static site - multi-language through plain JSON files, zero runtime dependencies. When the project needs a CMS, a database or a backoffice, you install Reepolee in parallel and it becomes the server for ReeWeb: fetch_collection() pulls live content into the same templates. Growth is an addition, not a migration.