Learn continuous integration and deployment — Last updated: September 2026
CI/CD stands for continuous integration and continuous deployment (or delivery). It is the automated pipeline that takes code from a repository and turns it into a running service — building, testing, and shipping it with as little manual intervention as possible.
A CI/CD pipeline is not just a convenience. It is what makes deployments consistent and repeatable. A manual deployment depends on someone remembering every step in the right order. A pipeline runs the same steps every time, fails fast when something is wrong, and produces an artifact that is the same every time it builds the same source.
The deployment simulator at LearnToDeploy includes a CI/CD pipeline editor so you can practice configuring build stages, watching them run, and diagnosing what goes wrong when a pipeline fails.
Continuous integration (CI) is the part of the pipeline that runs on every change to the source code. Its job is to verify that the change is sound before it goes any further.
package-lock.json,
requirements.txt, go.sum, Cargo.lock. Installing from a lockfile
ensures the build uses the exact versions that were tested.
The key principle of CI is that it runs on every change, automatically, and it fails the change if any step fails. This means the main branch is always in a state that could be deployed — because anything that would break that state is caught before it gets there.
Continuous deployment (CD) is the part of the pipeline that takes the built artifact and ships it — to a staging environment, to production, or both. The difference between deployment and delivery is whether the final step is automatic (deployment) or requires manual approval (delivery).
A pipeline is made of stages, and each stage has a job. A typical sequence is:
stage: install → npm ci / pip install / go mod download stage: check → lint, format, type-check stage: test → run the test suite stage: build → compile, bundle, or build an image stage: deploy → push artifact, restart service stage: verify → health check, smoke test
Stages run in order, and a failure in one stage stops the pipeline. This is what makes the pipeline a gate: if the tests fail, the build never runs. If the build fails, the deployment never happens. Each stage protects the next.
In the simulator, you work with build stages directly — configuring them, watching them run, and seeing what the pipeline log looks like when a stage fails. The failure might be a test that returns the wrong exit code, a build command that references a file that does not exist, or a deployment that targets the wrong port.
An artifact is the output of the build stage — the thing that gets deployed. It might be a compiled binary, a Docker image, a bundle of static files, or a directory of installed dependencies and source code.
The artifact is important because it is what separates building from deploying. The build stage produces the artifact and verifies it. The deployment stage takes the artifact and ships it. The artifact itself does not change between builds — if you build the same source with the same configuration, you get the same artifact.
Versioning artifacts matters. If you deploy myapp:latest and something goes wrong, you need to know
what :latest was at that moment, and you need to be able to deploy the previous version. Tagging
images with a version number or a git commit hash makes deployments traceable and rollbacks possible.
docker build -t myapp:1.2.0 . docker tag myapp:1.2.0 myapp:latest docker push myapp:1.2.0 docker push myapp:latest
A deployment gate is a check that runs after the deployment to verify it was successful. The most common gate is a health check — an HTTP request to a known endpoint that returns a status code indicating whether the service is alive and functioning.
A health check can be simple — return 200 from /health — or it can verify dependencies — check that
the database is reachable, that the cache is connected, that the API can query its dependencies. The more the
health check verifies, the more confident you can be that the deployment is actually healthy.
# A health check that verifies the app and its database
@app.route("/health")
def health():
try:
db.execute("SELECT 1")
return {"status": "healthy"}, 200
except Exception:
return {"status": "unhealthy"}, 503
Pipelines fail for predictable reasons. Knowing the common failure modes makes them easier to diagnose.
The deployment simulator includes projects where the CI/CD pipeline is part of the challenge. You configure the build stages, run the pipeline, and figure out why it fails — then fix it and run it again until the health check passes.
The LearnToDeploy deployment simulator lets you practice CI/CD without a real pipeline system. You configure build stages, run them, watch the output, and diagnose failures. The simulator responds with real build logs, test output, and deployment results — so you can practice reading a pipeline log and figuring out which stage failed and why.
For the concepts behind each stage, see the deployment concepts library, including entries on building applications, environment variables, and health checks.