Adios
BlogEngineering

Engineering

From Source to a Healthy Release: What a Deploy Actually Does

A deploy command crosses several boundaries: source packaging, build, runtime start, readiness, promotion, and public routing. Each can fail differently.

Adios team9 min read

A green build is not a live application. Between the source on a developer's machine and a public URL sit several independent checks, each with its own evidence and recovery path.

The source boundary: capture what will be built

The first question is deceptively simple: which files does this deploy represent? A local directory, a Git revision, and an open workspace can have different contents. If the platform cannot name the exact source it built, later debugging becomes guesswork. Adios records source as an artifact so a deployment can be tied back to code that can be reopened in a workspace.

The package should exclude disposable output such as node_modules and local build directories, while keeping the lockfile, manifest, and files the build needs. A successful upload only proves the package arrived. It does not prove the code compiles or that the runtime can start.

The build boundary: produce a versioned output

The build stage installs dependencies, runs the declared build command, and produces the output that a workload will start. A failed build should leave logs and a failure result, not a half-promoted release. Adios exposes build logs separately from runtime logs because package resolution and compilation failures have different owners from application startup failures.

For a Go API, the build output may be a binary. For Next.js, it includes server and asset output. For a Python service, the important work may be installing pinned dependencies and preparing the environment. The shape varies, but the invariant is the same: the runtime starts an identified output derived from identified source, under an explicit build contract.

  • —Record the source artifact and build identifier.
  • —Keep the build command in adios.yaml and the project scripts.
  • —Inspect build logs when dependency installation or compilation fails.
  • —Do not infer runtime health from a successful build.

The runtime boundary: start the right process

Once a build exists, the worker must start the declared production process with its environment, resource limits, and network settings. A common failure is a process listening on a different port from the manifest. Another is binding only to localhost when the gateway needs to reach the workload listener. Missing secrets and required managed resources can also cause a process to exit immediately or appear alive without serving requests.

Adios creates a runtime version with one or more replicas. The manifest describes the region, replica count, start command, port, and health path. That is enough for a reviewer to ask whether the new version can run safely without relying on a dashboard setting that was never committed.

A small API deploy contract

name: api
region: de
replicas: 2
build_cmd: go build -o /app/api ./cmd/api
start_cmd: /app/api

runtime:
  name: go@1.25
  port: 8080
  health_path: /healthz

The readiness boundary: prove this version can serve

A process can be running while its routes return errors. Readiness asks whether this version can take a real request. A useful health path should fail within a deadline when a required dependency is unavailable and recover after that dependency returns. It should avoid expensive work that turns the probe itself into load.

The Adios quickstart describes promotion after a deployment is healthy. The CLI also probes a configured public health path and can report the current route as healthy. These are different observations: replica readiness protects the candidate version; a public probe checks what a client can reach through ingress. A complete verification needs both, plus a request to a representative application route.

The promotion boundary: make the new version current

A deployment version and the current release are separate ideas. Keeping them separate lets an operator inspect a failed or superseded version without pretending it is the version serving users. The route should point to the version that passed the required checks, and a failed candidate should leave the previous current release available.

This is also where rollback has a concrete meaning: select a known earlier healthy version, verify its resources and schema compatibility, and move the route back. An application database migration can make that harder even if the platform keeps old runtime output. Review backward compatibility before treating rollback as automatic.

The public route boundary: test what users see

The final request crosses DNS, TLS, an ingress gateway, route lookup, and the selected workload. A failure at any of these points can appear to a user as 'the deploy is broken' even when the container is healthy. Request the real hostname and path, check redirects and certificates, and compare the response with the version you intended to promote.

For a custom domain, DNS verification and certificate issuance are additional gates. For an anycast address, the edge that receives the request may be in a different city from the workload. The point of the public smoke test is to exercise that entire path, rather than stopping at a local health check.

  • —Use build logs for packaging and compilation errors.
  • —Use runtime logs for start, dependency, and health errors.
  • —Use a public HTTPS request for TLS, route, and release selection errors.
  • —Record the source artifact and version beside the public response.

A deploy is complete when the evidence agrees

The useful output of a deploy is more than a URL. It is a chain connecting source, build, runtime version, readiness result, promoted release, and public response. When those identifiers agree, a developer can answer what is live and how to recover. When they disagree, the boundary where the evidence stops tells you where to investigate next.

  All articles