DEV Community

Cover image for From Commit to Production: What Actually Happens When You Ship an Update
Elizabeth Omito
Elizabeth Omito

Posted on

From Commit to Production: What Actually Happens When You Ship an Update

I used to think shipping an update was straightforward: make a change, commit it, push it, and the application is updated but git push is only the beginning.

Once I started paying more attention to DevOps, I became more interested in what happens between a developer pushing code and a user actually receiving that change.

How does the code get tested? How is it built? Where does the built application go? How does the server know there is a new version?
and how do we make sure the new version is actually working?

The answer is a delivery pipeline.

The journey from code to production

At a high level, the process looks something like this:

Developer
   ↓
Git Push
   ↓
Repository
   ↓
CI Pipeline
   ↓
Test & Validate
   ↓
Build
   ↓
Artifact / Container Image
   ↓
Deployment
   ↓
Health Checks
   ↓
Production
   ↓
Monitoring
   ↓
User
Enter fullscreen mode Exit fullscreen mode

Each stage has a different responsibility, and each one exists to reduce a particular type of risk.

1. It starts with a commit

A developer makes a change locally and commits it:

git add .
git commit -m "Fix authentication issue"
git push origin main
Enter fullscreen mode Exit fullscreen mode

The important distinction is that pushing code to a repository does not mean the code has been deployed. At this point, the repository contains the new version, but the application users are interacting with may still be running the previous version. Something still has to take that change and move it through the delivery process.

2. The repository triggers the pipeline

A CI/CD system can listen for events such as a push or pull request.

For example, a GitHub Actions workflow might contain:

on:
  push:
    branches:
      - main
Enter fullscreen mode Exit fullscreen mode

The push becomes the trigger for the pipeline.

A runner is then provisioned to execute the workflow, which may include installing dependencies, running tests, performing static analysis, building the application, and eventually deploying it.This is where the repository stops being just a place to store code and becomes part of the software delivery process.

3. CI validates the change

Before putting a new version into production, we want some confidence that it works.

A pipeline might run:

Install dependencies
        ↓
Lint
        ↓
Unit tests
        ↓
Integration tests
        ↓
Security checks
        ↓
Build
Enter fullscreen mode Exit fullscreen mode

If a test fails, the pipeline should stop.

This is one of the biggest advantages of automation. Instead of relying entirely on someone remembering to perform the same checks every time, the pipeline can enforce them consistently.

A failed pipeline is not necessarily a bad thing, sometimes the pipeline failing is exactly what prevents broken code from reaching production.

4. The application is built

Once the code passes validation, it needs to be transformed into something that can actually be deployed.

For a Go application, that could mean compiling the source into a binary:

go build
Enter fullscreen mode Exit fullscreen mode

For a frontend application, the process might produce optimized static assets:

npm run build
Enter fullscreen mode Exit fullscreen mode

In a containerized environment, the application might instead be packaged as a Docker image:

Source Code
     ↓
Docker Build
     ↓
Container Image
Enter fullscreen mode Exit fullscreen mode

This introduces an important concept:

The source code in the repository is not necessarily the same thing that gets deployed.

What gets deployed is usually a build artifact, a compiled binary, static files, package or container image.

5. The artifact needs somewhere to go

If we're deploying containers, the resulting image typically needs to be stored somewhere accessible to the deployment environment.

The flow becomes:

Git Repository
      ↓
CI
      ↓
Build
      ↓
Container Image
      ↓
Container Registry
Enter fullscreen mode Exit fullscreen mode

The registry acts as a source from which deployment infrastructure can retrieve a specific version of the application, this also makes versioning important, instead of thinking only in terms of "latest", we can identify exactly which version we're deploying.

For example:

my-app:v1.4.2
Enter fullscreen mode Exit fullscreen mode

That makes it easier to know what is running and when necessary, roll back to a previous version.

6. Deployment is where the new version reaches the infrastructure

Now we get to the part people usually associate with "shipping."

The deployment system takes the artifact and updates the environment where the application runs.

That environment could be:

  • a virtual machine
  • a container platform
  • Kubernetes
  • a cloud service
  • a serverless platform

A simplified container deployment might look like:

Container Registry
        ↓
Pull new image
        ↓
Start new container
        ↓
Health check
        ↓
Route traffic
Enter fullscreen mode Exit fullscreen mode

But deploying a new version isn't always as simple as stopping the old application and starting the new one, doing that could create downtime this is why deployment strategies matter.

7. How do we update production without taking it down?

Imagine two application instances are currently running version 1.0:

Load Balancer
    /     \
 v1.0     v1.0
Enter fullscreen mode Exit fullscreen mode

A rolling deployment might gradually replace them:

Load Balancer
    /     \
 v1.1     v1.0
Enter fullscreen mode Exit fullscreen mode

Then:

Load Balancer
    /     \
 v1.1     v1.1
Enter fullscreen mode Exit fullscreen mode

Other approaches include blue-green and canary deployments.

The strategy depends on the application, infrastructure, risk tolerance, and how much control we need over the rollout. The underlying goal is the same: introduce change without unnecessarily disrupting users.

8. A successful deployment doesn't necessarily mean a healthy application

This is one of the areas I find particularly interesting about DevOps. A deployment command can succeed while the application itself is broken.

The server may have successfully received the new version, but perhaps:

  • the application cannot connect to the database
  • an environment variable is missing
  • an external API is unavailable
  • a new endpoint is returning errors
  • memory usage has increased significantly

So after deployment, we need ways to determine whether the application is actually healthy.

That can include:

Deployment
    ↓
Health checks
    ↓
Logs
    ↓
Metrics
    ↓
Alerts
Enter fullscreen mode Exit fullscreen mode

This is where observability becomes important.

We're no longer asking only:

"Did the deployment complete?"

We're asking:

"Is the system behaving as expected after the deployment?"

9. And then there is the database

Application deployments become even more interesting when database changes are involved. Suppose version 2 of an application expects a new column:

Application v2
       ↓
Database schema v2
Enter fullscreen mode Exit fullscreen mode

What happens if some application instances are still running version 1?

During a rolling deployment, both versions might temporarily exist at the same time.This means database changes often need to be designed with backward compatibility in mind. A migration isn't simply a separate task that happens before or after deployment. It can be part of the overall deployment strategy. This is one reason production deployments require more thought than simply replacing one version of the application with another.

10. What happens when something goes wrong?

No delivery pipeline eliminates failure. The goal is to make failures detectable, controlled, and recoverable.

If version 1.5 introduces a critical problem, we may need to:

Detect issue
     ↓
Stop rollout
     ↓
Rollback / restore previous version
     ↓
Investigate
     ↓
Fix
     ↓
Deploy again
Enter fullscreen mode Exit fullscreen mode

This is where automation becomes especially valuable. A reliable delivery process shouldn't only answer:

"How do we deploy?"

It should also answer:

"How do we safely recover when the deployment goes wrong?"

So, how does an update actually reach the user?

It isn't a single action.

It's a chain of systems and decisions:

Code Change
    ↓
Commit
    ↓
Git Repository
    ↓
CI Trigger
    ↓
Tests & Validation
    ↓
Build
    ↓
Artifact
    ↓
Deployment
    ↓
Health Checks
    ↓
Traffic Routing
    ↓
Monitoring
    ↓
User
Enter fullscreen mode Exit fullscreen mode

And every arrow represents another potential failure point. That's what has made me look at software delivery differently. Writing the code is one part of building software. Getting that code reliably, safely, and repeatedly into the hands of users is another engineering problem altogether.

The more I learn about DevOps, the more I see it not simply as a collection of tools, but as the engineering of that path from a developer's commit all the way to a reliable production system.

Top comments (0)