Journal / DevOps

The deployment pipeline we run for every client, from day one.

Most teams treat deployment as something you set up when you have time. We treat it as the first thing we build. Here is why, and exactly what it looks like.

RL
RBB LAB
Studio
Published 16 Jun 2026 8 min read
pipe RBB/LAB DEVOPS RBB LAB · JOURNAL 8 MIN READ

The first week of every engagement, before we write a line of product code, we build the deployment pipeline. Not a stub. Not "we will set this up properly later." The full thing: environments, CI, secrets management, observability, and a working deploy to production on day five.

Clients sometimes push back on this. The product does not exist yet. Why are we spending time on infrastructure? The answer is that without a pipeline, what you are building is not software. It is a local prototype that nobody can use, cannot be reviewed safely, and will require a painful migration to production at exactly the moment you have the least time for it.

We have seen what happens when teams skip this step. The codebase grows for three months. The first real deploy takes two weeks. Configuration assumptions that looked fine locally turn out to be wrong in production. A secret ends up committed to git. The staging environment never quite matches production, so bugs appear that nobody saw in testing. All of this is avoidable, and none of it is complicated to avoid.

A working deploy on day five means every day after is real engineering, not prototype building. The pipeline is not overhead. It is the ground you build on.

The four environments

Every project runs four environments: local, preview, staging, and production. Each has a defined purpose. Collapsing them is where problems start.

Local is where engineers write code. It runs entirely on the developer's machine with no shared services and no shared databases. Each engineer gets their own isolated instance. Shared local databases cause data corruption, hidden dependencies, and debugging sessions where the problem turns out to be somebody else's migration that did not run cleanly.

Preview is an ephemeral environment created automatically for every pull request. It runs the full application with real dependencies against a snapshot of the staging database. It lives for the life of the PR and is torn down on merge. The purpose is to let reviewers see the change running, not just read the diff. For frontend work this is especially valuable: design review in a browser beats reading JSX.

Staging is the closest approximation of production. Same infrastructure, same configuration structure, same third-party integrations pointed at sandbox endpoints. It is where QA happens and where the client accepts work before it goes live. One rule: if something is true in production, it must be true in staging. Any divergence between the two is a bug in the pipeline, not in the application.

Production is production. Only staging-tested code reaches it. Deploys are automated. No manual SSH, no file uploads, no pushing directly. The pipeline is the only path to production, without exception.

CI from commit one

Continuous integration runs on every push to every branch. The suite includes linting, type checking, unit tests, and integration tests. It runs in under four minutes. If it takes longer than four minutes, engineers stop waiting for it and start merging blind, which defeats the point.

The four-minute constraint forces discipline. You cannot add slow tests without removing or parallelising existing ones. You cannot skip linting because "it takes too long." The constraint is the policy.

<4min
CI target time
100%
PRs require green CI
0
Manual deploys to production

Branch protection is on from day one. No PR merges without green CI. No exceptions, including for the team lead and including for urgent hotfixes. If the hotfix is so urgent that you cannot wait four minutes, the incident response process is the wrong place to be discovering that the tests are broken.

We also run dependency vulnerability scanning in CI. Not as a blocking check from the start, but logged from the beginning so there is never a moment where the team discovers they have been shipping known vulnerabilities for six months. For a more detailed treatment of the security surface, see our piece on startup attack surfaces.

The deployment checklist

Every production deploy runs through the same checklist, encoded in the pipeline, not in someone's memory.

Step What it verifies Blocks deploy if failing
CI suite Tests, types, lint Yes
Dependency audit No critical CVEs in direct dependencies Yes
Migration dry-run Database migrations apply cleanly against a staging snapshot Yes
Smoke tests Critical user paths return expected responses Yes
Rollback verification Previous version is tagged and rollback script is tested No, but logged

The migration dry-run deserves emphasis. Database migrations are the most common cause of deploy failures in production systems. Running them against a snapshot of real data in staging catches column type mismatches, missing indexes on large tables, and constraint violations that unit tests never reveal. We have caught production-breaking migrations this way on several client projects.

Observability before features

On day one, before any product code, we configure three things: structured logging, error tracking, and uptime monitoring. Not dashboards. Not alerting rules. Just the plumbing so that when something breaks there is a trail to follow.

You cannot debug a system you cannot observe. Every hour spent adding observability in production is worth ten spent adding it in development.

Structured logging means every log line is JSON with a consistent schema: timestamp, level, service, request ID, user ID where applicable, and the message. Free text logs are unsearchable at scale. A consistent schema means you can write a query in thirty seconds that would otherwise take thirty minutes of grepping.

Error tracking is not optional and is not the same as logging. Logging tells you what happened. Error tracking tells you what broke, how many times, for which users, and whether it is getting better or worse. It is configured before the first endpoint is written.

Uptime monitoring is a single HTTP check against the health endpoint, with an alert to a shared channel if it fails for more than two minutes. Crude, but the number of times this has caught a silent failure that no engineer noticed for hours is not small.

Secrets and configuration

No secret ever touches the repository. Not in a .env file, not in a comment, not in a test fixture, not in a TODO. The repository is treated as permanently public, regardless of its actual visibility.

Secrets are managed through the platform's secret store and injected at deploy time as environment variables. The application reads them from the environment. It does not know and does not care where they came from.

Configuration that varies by environment follows the same pattern. A database URL is not hardcoded. A feature flag threshold is not a constant. Everything that needs to differ between staging and production is an environment variable. This is boring and correct.

What happens at handoff

At the end of an engagement, the client receives the pipeline intact. Not a diagram of it. Not documentation describing it. The running pipeline, with credentials transferred, runbooks written, and at least two engineers on the client side who have run a deploy themselves.

This is the part most agencies skip. The code is delivered. The infrastructure is standing. But nobody on the client side knows how it works, so it gradually degrades as shortcuts accumulate and the original setup decisions are forgotten. Three years later, a new team inherits something they do not understand and cannot safely change.

We build the pipeline to be understood, not just to work. The scripts are readable. The configuration is documented at the point of decision. Every part of the system has an owner on the client side before we close the engagement.

The pipeline is not a deliverable. It is the foundation everything else is built on.

RL
RBB LAB
Studio · San Marino
A small team of senior engineers building production software for businesses and founders. We ship, hand off, and disappear cleanly.
Stay in the loop

One email when we publish. Nothing else.

About once a month. Sometimes less. No funnels, no drip campaigns.

Or grab the RSS · Follow on LinkedIn / X