Most client sites we run into lean on a stack comprised of multiple outside tools and services. One deploys the code. One monitors whether the site is up. Another handles caching. Each tool doing its thing in the background. For years we have managed each by hand, one stack at a time, clicking through a different dashboard for every tool. With Infrastructure as Code, we now write all of that down as code instead.
Today, all of that previously disparate work now lives in the project’s repository. The workflow shift fundamentally changed how we work.
Here’s the short version for anyone who doesn’t live in the dev world. A repository (repo) is a shared folder with a full history. Every change gets tracked: who made it, when, and why, and you can rewind any of it. Infrastructure as code, or IaC, means the settings for those outside tools stop living in a dashboard you have to remember to click through and start living in a written recipe. Anyone on the team can follow the recipe and get the same result.
That one move gave us a single source of truth, a repeatable process, and a safe lane to let AI help. Below is what we built and how it plays out day to day.
The old way cost too much time and didn’t leave any breadcrumbs
Standing up a stack used to mean logging into the web firewall, then into our monitoring service, then into the server, each one separately, each one configured by hand. Most of those changes left no record. Someone would adjust a caching rule six months back, and we had no way of knowing who did it or what they were trying to fix.
We did one project to craft hundreds of distributor/re-seller websites supporting one consumer brand. That project runs four top-level domains, with each carrying its own unique configuration. Every time we changed a caching rule, we made the same edit four times by hand. Caching rules are not simple toggles. We write small regex patterns that catch product pages but skip the admin view when someone’s signed in; little strings meant to match specific URLs. Copy that across four places and you can transpose a character or miss one entirely. Now multiply that by every caching rule change across every client and every tool.
When something broke, the forensic trail was thin. We hit exactly that for a separate direct-to-consumer brand in the healthcare space. Any dev who’s been in the trenches has experienced the day spent tearing our hair out over settings and code that had been shipped the week before, convinced we’d caused a problem we were watching unfold. Amazon had changed their billing. With no clean way to see when individual changes actually went live, it’s easy to fall into panic versus checking what actually happened.
Enter IaC
Solving such challenges required some innovative thinking. We stood up a template repository that holds the configuration for a client’s whole stack as code. The deploy settings, the monitoring checks, the caching rules – all written in files you can read, review, and version.
A few tools do the heavy lifting, and here’s the one-line job each one does:
- GitHub Actions runs a small program automatically when we push code, so a commit can trigger a deploy or a check without anyone having to click anything.
- DeployHQ pushes approved code out to a client’s dev, staging, and production sites.
- Checkly is our monitoring service. Think of it as a smoke detector on every site: it runs checks and tells us the second something breaks, ideally before the client notices.
- OpenTofu pulls down the settings a tool like Cloudflare currently has running and saves them to the repo, so the file reflects exactly what’s live and changes to that file are what update the live settings, after review.
- Ansible automates our software provisioning and configuration, ensuring that once a server is spun up, it’s exactly the same every single time without any manual tinkering.
None of this is an exotic, off-the-shelf invention. These tools already integrate well together. We refined the setup we already had and wrote it all down in one place.
Enterprise tooling reaches every client now
This is the payoff we care about most. A year ago, giving every client the same enterprise-grade tooling that our biggest accounts get would have required an untenable amount of work for a dev team our size. The new template makes it easy, and with a minimal cost. We build the recipe once and run it for our clients with little effort.
Until recently, clients didn’t manage their code in GitHub. Now every site does. That shift unlocks everything else: the review process, the audit trail, the repeatable deployments. Small sites get the controls that used to be reserved for big clients with big budgets.
Repeatable results means accuracy and efficiency
The repo gives us three things we didn’t have before.
First, diffs. Before we push a change, we can see the exact differences and confirm we’re touching only what we mean to touch. That client’s caching rule from earlier? We change one line, and it lands cleanly across all four domains. No transcription, no missed subdomain.
Second, an audit trail. Every change carries who made it, when, and a note about why. When a site starts misbehaving, we can look up exactly when a change shipped. If the trouble started Thursday and we didn’t push that setting until Friday, we’ve ruled it out in seconds. That’s the observability we were missing during the B2C client’s project.
Third, less context switching. Moving between clients used to burn real mental energy: pulling Client A’s whole stack out of your head and loading Client B’s. Now we open the repo and read how this client deploys, how they cache, and what we monitor, all in one spot. That one actually surprised us with how much it helped.
Letting AI draft changes without losing sleep
Because the config lives as code, we can hand a draft change to an AI agent like Claude and vet it before anything ships. Nothing EVER goes live un-reviewed. We compare the proposed change against what’s currently on the site and against the documented options in the recipe, then approve it. That review step is the whole reason we’re comfortable letting AI touch client infrastructure at all.
The guardrails backing that up are worth naming:
- Linters check the syntax of a config file automatically. Since these files get generated programmatically, a linter confirms the syntax is clean before it goes anywhere.
- gitleaks scans for secrets, so we don’t accidentally push an API key or credential into a live config. It runs in CI on both our Node and WordPress variants.
- CLI testing lets us run a change against the dev site before it ever reaches production.
Where we actually are
We started this recently, so I won’t hand you a dramatic war story about the day it saved us. What I can tell you is what it’s built to catch. A quick uptime ping sees a server answer “200, I’m up” and calls it good, even if the page loaded blank. A browser-based smoke test loads the site the way a person would and confirms it actually rendered, so it catches the broken-but-technically-up case that a fast hand-check sails right past.
A few specific notes on scope: The login-flow check is written but switched off by default, so it isn’t quietly running. Automated device testing is a next step for us, not something we’re doing today. And we have clients scaffolded that aren’t live yet. We’d rather show the edges than over-sell the finished picture.
Start in the repo if you’re stuck in the manual mud
If your setup lives in dashboards and one person’s memory, start here: get your code into a repository. Think of it as “version-control safety 101,” and it’s the foundation for everything above. From there, go after your biggest pain point. For us that was getting every dev set up to deploy, and automating it gave back the most time the fastest.
Enterprise tooling for every client, not just the big ones. The setup stops living in one person’s head and starts living in a place the whole team can read.