← Blog

·

category: Deployment title: What Happens Inside a Deployment Pipeline: A Step-by-Step Walkthrough date: 2026-06-01 excerpt: "Deploy" is a button you press and then wait. Here is what actually happens between the button press and the live URL, and why each step can fail. author: name: Thomas avatar: /avatar_tpl.jpg

When you push code and trigger a deployment, a lot happens before your app is live. Most platforms hide this behind a spinner and a success or failure message. Understanding what actually happens at each step makes failures much easier to diagnose and gives you a clearer picture of what you are trusting a deployment platform to do correctly.

Here is what a deployment pipeline looks like, step by step.

Step 1: Source acquisition

The pipeline starts by fetching your code. This usually means pulling from a Git repository: either the latest commit on a branch, a specific commit reference, or a tag.

This step can fail if the platform cannot access the repository. Common causes: the access token has expired, the repository became private after the integration was set up, or a branch was deleted.

If the pipeline is triggered by a webhook from GitHub or GitLab, this step also validates the webhook payload. A misconfigured secret causes the webhook to be rejected and the deployment never starts.

Step 2: Environment setup

The platform sets up the environment where the build will run. This means selecting a base image or container, setting environment variables for the build context, and preparing the filesystem.

This step is mostly invisible. It matters because the build environment determines what system dependencies are available, what version of Node.js or Python runs the build, and what architecture the binaries are compiled for.

If your app requires a specific Node.js version and the build environment uses a different one, packages that include native binaries will compile for the wrong version and fail at runtime. The error message, something like "invalid ELF header" or "incompatible native module", looks alarming but points to a version mismatch.

Step 3: Dependency installation

The platform installs your dependencies. For a Node.js app this is npm install, npm ci, yarn install, or pnpm install depending on the lockfile it detects.

This step reads your package.json and lockfile, downloads packages from the registry, and populates node_modules. On first install, this can take a minute or two. With caching it is usually fast.

Common failures here: a package that was installed globally on your local machine is not in package.json and therefore not installed; a package version that existed when you last ran install has been unpublished from the registry; a private package requires credentials that are not configured on the build server.

Step 4: Build

The platform runs your build command. For most JavaScript frameworks this is something like npm run build, which compiles TypeScript, bundles JavaScript, runs CSS processing, and produces output optimized for production.

This is one of the most common failure points. TypeScript errors that were suppressed locally fail the build. Missing environment variables that are read at build time (common in Next.js and similar frameworks) cause the build to fail or produce broken output. Build scripts that reference local paths or tools that are not available on the build server fail here.

The output of this step is a directory of compiled, optimized files that the runtime will serve.

Step 5: Database migrations

If the pipeline is configured to run database migrations (and it should be, for any app that has a database), this step runs your migration command against the production database.

This step runs after the build and before the app starts serving traffic. The reason is ordering: your new code may reference columns or tables that only exist after the migration runs. If the app starts before migrations complete, queries against the new schema fail.

If migrations fail, the pipeline should stop here. The old version of your app stays running. This is the correct behavior. Deploying new code on top of an unmigrated database causes both new and old code to fail.

Step 6: Container creation or process restart

The platform takes your build output and either packages it into a container image or prepares it to run as a process. For containerized platforms, this means writing a Dockerfile (or using a generated one), building the image, and pushing it to a registry.

This step is where deployment platforms make different choices about how to run your app. Some run processes directly. Some use containers. Some use serverless functions. The choice affects how environment variables are injected, how file persistence works, and how the app is restarted when it crashes.

Step 7: Health check

Before routing traffic to the new version, the platform starts the app and checks that it is responding correctly. It makes HTTP requests to a health check endpoint, usually /health, /healthz, or just /, and waits for a successful response.

If the health check fails, the deployment is marked as failed and traffic continues going to the old version. This is the safety net that prevents a broken deploy from taking down your app.

Common health check failures: the app crashes on startup due to a missing environment variable, the app takes too long to start and times out the health check, or the health check endpoint does not exist and the platform gets a 404.

Step 8: Traffic switch

Once the health check passes, the platform switches traffic from the old version to the new one. Depending on the platform, this is instantaneous (a DNS or load balancer change) or gradual (a percentage rollout).

From this point forward, new requests go to the new version. The old version either terminates immediately or runs for a short period to finish handling in-flight requests.

Step 9: Cleanup

The platform cleans up build artifacts, removes the old container or process, and updates its internal state to record the new deployment.

This step is invisible unless it fails, which is rare.

What Jetpacked's pipeline looks like

Jetpacked runs all six phases (source acquisition, environment setup, dependency installation, build, migrations, and deployment) in a defined order with explicit failure handling at each step. If migrations fail, the new code does not go live. If the build fails, the database is not touched. If the health check fails, the old version stays up.

Each phase is logged so you can see exactly what ran, what output it produced, and where something went wrong. The goal is that a failed deployment should tell you clearly what happened and what to fix, not leave you reading tea leaves in a stream of terminal output.

Deploy your app in minutes

Jetpacked handles Docker, HTTPS, databases, and deployments so you can focus on building.

Launch your app free