Skip to main content
Back to Insights

Why we develop on the exact stack we run in production

Valentin Zsigmond
Valentin ZsigmondJun 3, 20265 min read

Every developer knows the sentence "works on my machine." It is usually said with a shrug, right after something that behaved perfectly in development did something strange on the live server. Somewhere between the two environments, a difference in a version, a setting, or a piece of infrastructure turned the same code into different behavior.

We decided some years ago that we did not want that gap to exist at all. Today, when someone on our team works on a client site, their machine runs the exact production stack: the same hardened containers we deploy to live servers, the same web server configuration, the same TLS setup, the same way all the pieces are wired together. Not a lightweight imitation of production. Production itself, running locally.

This article is about why we built our platform that way, what it removes from deploy day, and what it changes about how confidently work ships.

Where the gap comes from

The gap between development and production does not appear because anyone is careless. It appears because the two environments have different jobs. A development setup is optimized for convenience: quick to install, easy to reset, tolerant of mistakes. A production server is optimized for security and stability: locked down, hardened, precise about permissions. Left to evolve separately, the two drift apart in a hundred small ways. A PHP version here, a web server directive there, a caching layer that exists in one place and not the other.

Each difference is individually harmless. The problem is that code and configuration interact, and every difference is a place where behavior can diverge. Testing on a setup that only resembles production means every deploy carries a residue of untested assumptions. Most days that residue is invisible. On the wrong day, it is the whole afternoon.

What identical means in practice

Our hosting platform runs sites in hardened containers that we build and maintain ourselves. When a developer starts a project locally, the platform starts those same containers on their machine: the same PHP runtime with the same extensions and the same limits, the same web server with the same configuration files, the same database engine, the same cache, the same directory layout and permission model. The site answers on a local domain over TLS, with certificates the browser trusts, because production runs TLS and so should everything that claims to reproduce it.

The consequence is simple to state: if it works locally, it works live, because locally and live are the same stack. There is no translation step where a site gets adapted from the development environment to the server. The environment travels with the site.

It also shortens onboarding. A new developer joining a project runs one command and has production in front of them, TLS and all, instead of spending their first days assembling an approximation of it by hand and discovering its gaps for months afterwards.

The class of surprises this eliminates

A whole category of deploy-day problems simply has no room to exist. A rewrite rule that behaves differently between web servers cannot bite when there is only one web server configuration. An upload limit or memory ceiling that differs between environments cannot cause a failure that only shows up live. Mixed-content warnings that tend to appear the first time a site runs behind TLS cannot appear late, because the site has been behind TLS since its first local page load.

What is left to go wrong is the code and the content themselves, which is exactly where attention belongs. When something fails in development, we can trust it would have failed live, so it gets fixed now. When something passes, the pass means something. Testing stops being a rehearsal in a different theater and becomes the actual performance, just earlier.

Deploys become boring, in the best way

The same philosophy continues into how changes ship. A deploy on our platform is an explicit, tracked release: a specific, known state of the code goes out, the release is recorded, and if anything looks wrong the previous release is one action away. Two deploys aimed at the same environment queue up and run in order instead of colliding. None of this is heroic. It is deliberately mundane.

Combine that with a development environment that tells the truth, and deploys change character. They stop being events that need a quiet Friday and a held breath. Small changes ship as small releases, frequently, because each one has already run on the production stack before it ever left a development machine.

The same truth for every environment

The local machine is not the only place this parity applies. When a project needs a staging environment, or a temporary environment to preview one specific piece of work, our platform creates it from the same recipe: the same containers, the same configuration, the same TLS. A client reviewing a change on a preview link is seeing exactly how it will behave in production, not an approximation of it.

Database copies pulled into those environments are scrubbed of personal data on the way, so realism does not come at the price of privacy. The result is a chain of environments, from a development laptop to a preview to production, that differ in their data and their audience but never in their behavior.

Why we built it instead of assembling it

We run our own managed hosting platform, and that is what makes this possible. Because we control how production is put together, we can make the same composition run anywhere, and keep the two in lockstep: when the production stack is updated, the development stack updates with it, because they are built from the same pieces. Parity is not a policy we enforce with discipline. It is a property of the system, and that is the only kind of parity that survives busy weeks.

Drupal deserves this kind of foundation, incidentally. The framework itself is disciplined about configuration and deployment, with a clear model for moving changes between environments. Giving it infrastructure that behaves identically everywhere lets that discipline pay off in full.

What this means if we build or host your site

You will mostly notice it as an absence. Launches that go quietly. Changes that arrive when promised and behave the way the demo behaved. No vocabulary of "it worked in staging" entering your project. And underneath the calm sits a practical benefit: because shipping is low-risk, improvements ship in small steps instead of accumulating into large, tense releases. A site that receives many small, safe changes stays modern in a way that a site waiting for the next big careful update does not.

"Works on my machine" and "works live" becoming the same sentence was the goal. Everything else, the calmer launches, the faster iteration, the shorter path from idea to production, follows from that one decision.

Share this article
Valentin Zsigmond
Written by
Valentin Zsigmond
Founder & Lead Engineer

Full-stack Drupal architect with almost two decades of experience leading large teams in enterprise environments. Founded Tilizy Digital to bring senior-level expertise directly to the organizations that need it. Mentor to dozens of Drupal developers and creator of SDX — a Drupal extension for building modern frontends with React and Vue.

Enjoyed this article?

If this resonated, imagine what we could do working together on your Drupal site.