Backend Development

Chapter 12
Version Control, Delivery, and Deployment

Certificate in Full stack programming
Backend Development   •   Certificate

Version Control, Delivery, and Deployment

Introduction

Backend software is not complete when it runs on a developer’s computer. It must be changed safely, tested consistently, packaged reproducibly, and delivered to environments where users and other services can depend on it. Version control and deployment practices provide the operational bridge between source code and a reliable running service.

This chapter examines the practical delivery lifecycle of a backend application. It connects Git workflows, branching, commits, pull requests, dependency locking, automated builds, environment variables, continuous integration and continuous delivery, containers, cloud platforms, and environment separation. The emphasis is on principles that apply across languages and platforms rather than on one vendor’s tools.

Learning Objectives

By the end of this chapter, a learner should be able to:

  • explain how Git records and coordinates software changes;
  • create meaningful commits and use branches and pull requests effectively;
  • distinguish dependency declarations from dependency lock files;
  • design a basic automated build and test pipeline;
  • manage configuration through environment variables without exposing secrets;
  • distinguish development, staging, and production environments;
  • package a backend service in a container;
  • describe common cloud deployment models and release strategies; and
  • identify operational, security, and governance risks in delivery pipelines.

1. Version Control as a Delivery Foundation

Version control is a system for recording changes to files so that developers can inspect history, collaborate, compare versions, and restore earlier states. Git is a distributed version control system: each clone contains the project’s history, allowing many operations without a central server. Platforms such as GitHub, GitLab, and Bitbucket add remote hosting, access control, issue tracking, and pull requests; they are not replacements for Git itself.

A Git repository usually contains a working tree, a staging area, and commits. The working tree contains files currently being edited. The staging area records the precise changes intended for the next commit. A commit is a permanent record, identified by a hash, that includes a snapshot of tracked content, metadata, and a reference to its parent commit. A branch is a movable reference to a commit, while a tag is normally a named reference used for a release or other significant point.

A useful basic sequence is:

git clone <repository-url>
git switch -c feature/user-registration
# edit files
git status
git diff
git add src/ tests/
git commit -m "Add user registration endpoint"
git push -u origin feature/user-registration

The commit should represent a coherent change. A small, focused commit is easier to review, revert, and troubleshoot than a commit that combines formatting, dependency updates, database changes, and unrelated features.

Good commit practice

A useful commit message states the change in an imperative style, such as “Validate login credentials” rather than “Validation added.” The body may explain motivation, compatibility implications, or migration requirements. Generated files should be committed only when the project convention requires them. Secrets, local configuration files, build output, and personal editor settings should normally be excluded through .gitignore.

Git history is not a security boundary. Removing a password from the current file does not remove it from earlier commits, forks, caches, or logs. If a secret is committed, it must be revoked or rotated immediately, followed by appropriate history remediation.

2. Branches, Integration, and Pull Requests

A branch permits work to proceed without changing the shared release line. Common models include:

ModelMain ideaStrengthRisk
Feature branchesShort-lived branch per changeClear review boundaryLong branches create merge conflicts
Trunk-based developmentFrequent integration into a protected main branchSmall integration batchesRequires strong automated tests
Release branchesStabilize a planned release separatelyUseful for scheduled releasesCan create duplicated work
Gitflow-style modelDedicated feature, release, and hotfix branchesExplicit release stagesOften heavyweight for small teams

There is no universally correct branching model. A small service with continuous delivery often benefits from short-lived branches and a protected main branch. A regulated product with coordinated release windows may need release branches and formal approvals.

A pull request is a proposed change accompanied by discussion, automated checks, and review. A sound pull-request process normally includes:

  1. a clear description of the problem and solution;
  2. tests or evidence of behavior;
  3. review by appropriate maintainers;
  4. automated linting, security checks, and tests;
  5. resolution of review comments; and
  6. a merge method consistent with the project’s history policy.

Branch protection can require successful checks, code-owner approval, signed commits, or up-to-date branches. These controls reduce accidental changes but do not replace technical judgment. Reviewers should examine error handling, authorization, database effects, logging, backward compatibility, and test quality—not merely formatting.

3. Dependency Management and Reproducible Builds

A backend application depends on language packages, operating-system libraries, build tools, and sometimes services such as databases. A dependency declaration expresses acceptable versions; a lock file records a resolved dependency graph, including transitive dependencies and often integrity information.

For example, a declaration might permit a library version within a compatible range, while a lock file records the exact version selected at installation time. This distinction matters because two installations made at different times can otherwise receive different transitive packages.

A reproducible build aims to produce equivalent artifacts from the same source, dependency definitions, and build instructions. Reproducibility is not always perfect: timestamps, compiler versions, native libraries, and external downloads can introduce variation. Nevertheless, teams should pin important toolchain versions, commit the appropriate lock file, use deterministic installation commands, and avoid silently downloading unverified dependencies during deployment.

Typical practices include:

  • use the package manager’s lock file in applications;
  • separate runtime dependencies from development-only dependencies;
  • update dependencies deliberately and review release notes;
  • scan packages for known vulnerabilities;
  • verify package integrity where supported; and
  • test upgrades in an isolated environment before production use.

Locking versions does not eliminate vulnerabilities. It makes the installed state visible and repeatable, which improves the ability to assess and correct risk.

4. Build Automation and Continuous Integration

A build is a repeatable process that may install dependencies, compile source code, generate assets, run tests, perform static analysis, and produce a deployable artifact. Build automation places these actions in scripts or pipeline definitions rather than relying on undocumented personal procedures.

Continuous integration (CI) means that changes are integrated frequently and automatically validated. A basic CI pipeline may perform the following stages:

Commit or pull request
        ↓
Install locked dependencies
        ↓
Lint and type-check
        ↓
Run unit and integration tests
        ↓
Security and license checks
        ↓
Build versioned artifact
        ↓
Publish artifact or report failure

Tests should be layered. Unit tests are fast and isolate functions or modules. Integration tests exercise boundaries such as databases or queues. End-to-end tests validate a complete user-visible workflow but are usually slower and more fragile. A pipeline should fail when a required quality condition is not met, while non-blocking informational checks should be clearly identified as such.

A useful quality metric is test coverage, but coverage is not a direct measure of correctness. A test suite can execute many lines without checking meaningful outcomes, security boundaries, or failure conditions. Teams should prioritize behavior, risk, and maintainability over a target percentage alone.

5. Configuration, Environment Variables, and Secrets

Configuration varies between environments: database addresses, ports, log levels, feature flags, and external service endpoints are common examples. Environment variables provide a simple interface for supplying configuration at process startup:

DATABASE_URL=postgresql://app_user:[email protected]/app
PORT=8080
LOG_LEVEL=info

Application code should read configuration through a validated configuration module rather than repeatedly accessing process variables throughout the codebase. Required values should cause a clear startup failure when absent or malformed. Defaults are appropriate only for safe, non-sensitive settings.

Environment variables are not automatically secret. They may be visible to process inspection, crash reports, deployment interfaces, container metadata, or logs. Passwords, API keys, signing keys, and tokens should be stored in a dedicated secret-management system or protected CI/CD secret store. They should not be committed to source control or printed in diagnostic output.

Configuration should be externalized, but configuration schemas should be versioned. A schema can document type, required status, allowed values, and security sensitivity. For example, PORT should be parsed as an integer and constrained to a valid range; NODE_ENV or an equivalent mode should be restricted to known values.

6. Development, Staging, and Production

Environment separation reduces the chance that experimentation damages real data or users.

  • Development supports rapid coding and debugging. It may use local services, test data, verbose logs, and automatic reloads.
  • Staging should resemble production sufficiently to expose integration and deployment problems. It normally uses isolated accounts and non-production data.
  • Production serves real users and requires controlled access, monitoring, backups, security controls, and explicit change management.

Similarity between staging and production should include runtime versions, container images, database engines, network policies, and configuration structure where practical. Data should not be copied into staging without authorization and appropriate masking. Production credentials must never be reused in development.

Database migrations deserve special attention. A migration changes persistent state and may be difficult to reverse. Backward-compatible, expand-and-contract migrations are often safer: first add a new column or behavior, deploy code that can work with both old and new structures, migrate data, and remove obsolete structures only after all old code is gone.

7. Continuous Delivery and Continuous Deployment

Continuous delivery means that every change that passes the required pipeline is kept in a deployable state; release to production may still require human approval. Continuous deployment automatically releases qualifying changes to production. Both depend on reliable automation, but continuous deployment demands especially strong testing, observability, rollback, and organizational confidence.

A typical delivery pipeline is:

  1. build an immutable artifact from a specific commit;
  2. store the artifact in a registry;
  3. deploy the same artifact to staging;
  4. run smoke, integration, and security checks;
  5. obtain approval if policy requires it;
  6. deploy to production using a controlled strategy; and
  7. monitor health and business signals.

The same artifact should move between environments. Rebuilding separately for staging and production can produce differences that were never tested. A release identifier should connect source commit, build logs, artifact digest, deployment event, and runtime version.

Deployment strategies include:

  • Rolling deployment: replace instances gradually. It uses resources efficiently but can temporarily run mixed versions.
  • Blue-green deployment: maintain two environments and switch traffic from the old (blue) version to the new (green) version. Rollback is rapid, but duplicated infrastructure may cost more.
  • Canary deployment: send a small proportion of traffic to the new version, observe it, and increase traffic if healthy. It reduces exposure but requires routing and monitoring capability.

Rollback is not always safe when a release changes data irreversibly. Teams should define rollback and roll-forward procedures before deployment.

8. Containers and Cloud Platforms

A container packages an application with its user-space dependencies while sharing the host operating system kernel. It is not the same as a virtual machine: a virtual machine includes a guest operating system, whereas a container typically uses an image layered on the host kernel through a container runtime.

A minimal Dockerfile for a compiled or packaged backend might resemble:

FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY dist ./dist
USER node
EXPOSE 8080
CMD ["node", "dist/server.js"]

The exact commands depend on the language. Important principles are to use a trusted and appropriately pinned base image, minimize layers and contents, avoid root execution where possible, exclude development files, and scan images for vulnerabilities. A container should normally be stateless: persistent data belongs in managed storage or a database, not in the writable container filesystem.

Cloud platforms commonly provide infrastructure in several forms:

  • Infrastructure as a Service (IaaS): virtual machines, networks, and storage are managed by the customer.
  • Platform as a Service (PaaS): the provider manages much of the runtime and scaling; the developer supplies application code or an image.
  • Container orchestration: a platform schedules containers, manages service discovery, health checks, scaling, and rollout policies.
  • Serverless functions: the provider runs short-lived functions in response to events, with operational limits and execution-based pricing.

Cloud deployment does not remove engineering responsibility. Identity permissions, network exposure, backups, data residency, logging, cost controls, and provider dependency remain important design concerns.

9. Observability and Operational Safety

A deployed service must be observable. Logs record events and diagnostic context; metrics represent measurements such as request rate, latency, error rate, and resource usage; traces follow a request across services. Logs should be structured, time-synchronized, searchable, and free of secrets or unnecessary personal data.

Health checks should distinguish liveness from readiness. A liveness check asks whether the process is functioning sufficiently to remain running. A readiness check asks whether it can receive traffic, including whether essential dependencies are available. A service that is alive but not ready should not receive requests during startup or dependency failure.

Useful operational objectives include availability targets, latency thresholds, and recovery expectations. Two common concepts are:

  • Recovery Time Objective (RTO): the maximum acceptable time to restore service after a disruption.
  • Recovery Point Objective (RPO): the maximum acceptable amount of data loss measured in time.

For example, an RPO of 15 minutes implies that backup or replication design should limit recoverable data loss to approximately 15 minutes under stated assumptions. These are business requirements, not universal technical constants.

10. Illustrative Case: Deploying a Course API

Background

A fictional training provider operates a REST API for courses, enrolments, and learner progress. Developers previously copied files manually to a virtual machine. The service had no consistent dependency versions, credentials were stored in a shared configuration file, and releases occasionally interrupted active requests.

Problem

A security update required a rapid, auditable release. The team could not identify which source version was running, staging differed from production, and rollback depended on reconstructing an old server directory.

Analysis

The risks were not limited to deployment mechanics. Manual copying weakened traceability; unpinned dependencies weakened reproducibility; shared credentials increased exposure; and the absence of health checks made it difficult to distinguish a bad release from a temporary dependency failure.

Approach and solution

The team adopted a protected main branch and short-lived feature branches. Pull requests required two checks: tests and a vulnerability scan. The package lock file was committed, and CI used the package manager’s locked-install command. A pipeline built a container image tagged with the commit identifier and stored it in a private registry.

Development, staging, and production received separate databases and credentials. Secrets moved to the cloud provider’s secret store. Staging used the same image that would later be promoted to production. A readiness endpoint checked database connectivity, while a liveness endpoint verified that the process event loop remained functional.

The deployment initially used a rolling strategy. Because the API contract was maintained during migration, old and new instances could coexist. The team added structured logs, request identifiers, error-rate alerts, and an automated rollback rule for a sustained increase in failed requests.

Outcome

The organization could identify the exact commit, dependency state, image, and deployment event associated with a release. The security update was tested in staging and promoted without manually rebuilding the application. Operators retained the ability to stop the rollout and investigate using logs and metrics.

Learning points

The principal improvement was not a particular cloud product. It was the creation of a chain of evidence from change to artifact to environment. Automation reduced variation, while environment separation and secret management reduced the consequences of mistakes. The process also demonstrated that rollback, observability, and database compatibility must be designed alongside deployment rather than added afterward.

11. Challenges, Ethics, and Governance

Delivery systems can amplify mistakes: a faulty commit can be distributed to every production instance within minutes. Therefore, organizations should apply least privilege to repositories, registries, cloud accounts, and pipeline identities. Pipeline credentials should be short-lived where possible, and deployment actions should be auditable.

Software supply-chain risks include compromised dependencies, malicious packages, poisoned build inputs, vulnerable base images, and unauthorized pipeline changes. Defenses include dependency review, provenance records, signed artifacts, protected branches, isolated build runners, image scanning, and rapid patch procedures.

Privacy must also be considered. Logs and test datasets can contain personal information. Data minimization, access controls, retention limits, masking, and applicable privacy regulations should guide their use. Automated deployment should not bypass required approvals for systems affecting safety, finances, or legally protected data.

Artificial intelligence can assist with commit summaries, test suggestions, vulnerability triage, and deployment diagnostics. However, generated code and generated pipeline changes require human review. AI tools may reproduce insecure patterns, mishandle confidential source code, or produce plausible but incorrect operational advice. Accountability remains with the engineers and organization operating the service.

Best Practices Checklist

  • Commit small, coherent changes and review them through pull requests.
  • Protect the main branch with automated checks and appropriate approvals.
  • Commit application lock files and use deterministic installation commands.
  • Build once and promote the same immutable artifact.
  • Validate configuration at startup and keep secrets outside source control.
  • Keep development, staging, and production credentials and data separate.
  • Use least-privilege identities for developers and pipelines.
  • Make containers small, patched, non-root where practical, and stateless.
  • Add health checks, structured logs, metrics, and deployment alerts.
  • Test migrations, rollback, backup restoration, and disaster recovery.
  • Record source, artifact, dependency, and deployment information for traceability.

Chapter Summary

Version control provides the historical and collaborative foundation for backend delivery. Git branches isolate work, commits record coherent changes, and pull requests combine review with automated validation. Dependency declarations and lock files serve different purposes: the former express acceptable versions, while the latter improve repeatability by recording resolved dependencies.

Build automation and CI turn quality checks into repeatable processes. Environment variables externalize configuration, but secret values require dedicated protection. Development, staging, and production should be separated while remaining sufficiently similar to expose deployment defects. Continuous delivery keeps software deployable; continuous deployment releases it automatically when organizational controls permit.

Containers package applications consistently, while cloud platforms provide varying levels of infrastructure abstraction. Reliable deployment also requires immutable artifacts, compatible database migrations, observability, rollback planning, security controls, and governance. The professional goal is not merely to deploy quickly, but to deliver changes safely, traceably, and recoverably.

Key Terms

Git: A distributed version control system for recording and coordinating file changes.

Repository: A project directory containing source files and version history.

Commit: A recorded snapshot of project changes with metadata and parent references.

Branch: A movable reference used to develop a line of changes.

Pull request: A reviewed proposal to merge changes into another branch.

Dependency: External software required by an application.

Lock file: A file recording resolved dependency versions and related integrity data.

Build artifact: A packaged output suitable for testing or deployment.

Continuous integration: Frequent integration of changes with automated validation.

Continuous delivery: Keeping validated changes in a deployable state.

Continuous deployment: Automatically releasing qualifying changes to production.

Environment variable: A process-level configuration value supplied outside source code.

Secret: Sensitive information such as a password, token, or private key.

Container: An isolated process package sharing the host operating-system kernel.

Image: An immutable or versioned filesystem template used to create containers.

Staging: A pre-production environment used for realistic validation.

Rolling deployment: Gradual replacement of instances running an older version.

Canary deployment: Limited release of a new version before wider exposure.

Observability: The ability to understand system behavior through logs, metrics, and traces.

Rollback: Returning service to an earlier release or safe operational state.

Review Questions

Short Answer Questions

  1. What is the difference between a Git branch and a Git commit?
  2. Why is a lock file useful in an application repository?
  3. Why should secrets not be stored in ordinary environment files committed to Git?
  4. Distinguish continuous delivery from continuous deployment.
  5. What is the difference between a liveness check and a readiness check?

Long Answer Questions

  1. Explain how a pull-request workflow can improve both software quality and team coordination.
  2. Describe a CI/CD pipeline for a backend service, from commit through production monitoring.
  3. Compare rolling, blue-green, and canary deployment strategies, including their risks.
  4. Explain why development, staging, and production environments should be separated but similar.
  5. Discuss the main security risks in containerized delivery and suitable controls.

Analytical / Application Questions

  1. A team discovers that staging and production use different runtime versions and that production was rebuilt manually after staging tests. Analyze the risks and propose a corrected delivery design.
  2. During a rolling deployment, the new version requires a database column that the old version does not understand. Design a migration and release sequence that permits safe coexistence and rollback.
  3. An API’s error rate increases after a canary release, but CPU and memory remain normal. Identify the evidence you would collect, the decision criteria you would apply, and the safest immediate action.

Multiple Choice Questions with Answers

Question 1

Which Git object records a coherent snapshot of project changes?

A. A commit

B. A branch

C. A remote

D. A workspace

Correct Answer: A. A commit

Question 2

What is the principal purpose of a dependency lock file?

A. To store application passwords

B. To record resolved dependency versions for repeatable installation

C. To replace automated tests

D. To define cloud network routes

Correct Answer: B. To record resolved dependency versions for repeatable installation

Question 3

Which practice best protects a production API key?

A. Commit it to a private repository

B. Place it in a code comment

C. Store it in a protected secret-management system

D. Print it in startup logs

Correct Answer: C. Store it in a protected secret-management system

Question 4

What does continuous integration primarily automate?

A. Frequent validation of integrated code changes

B. Manual assignment of cloud invoices

C. Permanent deletion of old branches

D. Replacement of all production databases

Correct Answer: A. Frequent validation of integrated code changes

Question 5

Which statement correctly describes continuous deployment?

A. Every developer deploys directly from a laptop

B. Qualifying changes are automatically released to production

C. Only dependencies are deployed automatically

D. Deployment is prohibited without rebuilding by hand

Correct Answer: B. Qualifying changes are automatically released to production

Question 6

Which deployment strategy sends a small proportion of traffic to a new version first?

A. Canary deployment

B. Big-bang deployment

C. Cold backup

D. Source checkout

Correct Answer: A. Canary deployment

Question 7

Why should the same built artifact be promoted from staging to production?

A. It ensures production receives the artifact that was tested

B. It eliminates the need for source control

C. It guarantees that application defects cannot occur

D. It allows secrets to be embedded in the image

Correct Answer: A. It ensures production receives the artifact that was tested

Question 8

Which statement about containers is correct?

A. Every container includes a complete guest operating system

B. Containers generally share the host kernel

C. Containers automatically provide encrypted databases

D. Containers cannot be used in cloud platforms

Correct Answer: B. Containers generally share the host kernel

Question 9

What does a readiness check determine?

A. Whether a service should receive traffic

B. Whether source code has a valid license

C. Whether a developer has approved a pull request

D. Whether a dependency is the newest available version

Correct Answer: A. Whether a service should receive traffic

Question 10

Which action is most appropriate after a secret is committed to a repository?

A. Rename the variable and leave the secret active

B. Revoke or rotate the secret immediately

C. Delete only the current working-tree file

D. Add the secret to the lock file

Correct Answer: B. Revoke or rotate the secret immediately

Backend Development
Chapter 12 of 14