Деплои
What happens between a push and a running container, how to read build and runtime logs, redeploy, roll back, cancel, and what each status means.
A deployment is one build-and-rollout of a service in an environment. It is created by a push to the tracked branch, by skiffly up, by a redeploy from the dashboard or by serviceInstanceDeployV2. The previous deployment keeps serving traffic until the new one passes its health check, then it is removed.
Lifecycle#
QUEUED → BUILDING → DEPLOYING → SUCCESS
↘ FAILED ↘ CRASHED
↘ SLEEPING (App Sleeping) ⇄ SUCCESS
any → REMOVED (replaced, cancelled, service deleted)| Status | Meaning |
|---|---|
QUEUED | waiting for a node; the only state that can be cancelled |
BUILDING | Railpack/Dockerfile build in progress (or waiting for a build slot: two builds run at once per node) |
DEPLOYING | image pushed, containers starting, health check not passed yet |
SUCCESS | live and receiving traffic |
FAILED | build failed, or the container never became healthy in time (see limits), or the quota was exceeded |
CRASHED | the container exited repeatedly after going live (three restarts in a row) |
SLEEPING | scaled to zero by App Sleeping; the next request wakes it |
REMOVED | replaced by a newer deployment, cancelled, or the service was deleted |
The full enum is Railway-compatible; see the status reference.
Triggers#
- Push to the tracked branch of a connected repository (or the PR branch in a
pr-*environment). skiffly upuploads the current directory, builds it and streams the logs;--gitbuilds the pushed head of the connected repository instead, and--git --commit <sha>picks a commit.- Redeploy rebuilds and redeploys the latest commit with the current variables and settings (
serviceInstanceRedeploy,skiffly redeploy, MCPredeploy). - Deploy starts a fresh build (
serviceInstanceDeployV2, MCPdeploy). - Variable changes redeploy the affected services about five seconds after the last change (several edits in a row become one deployment): the service that owns the variable plus every service referencing it with
${{service.VAR}}; a shared variable redeploys every service in the environment. PassskipDeploys: true(skiffly variables set --skip-deploys, MCPskipDeploys) to only save. Services that have never been deployed are left alone. - Settings changes: saving runtime settings (replicas, CPU/memory, health check path and timeout, start command, cron, restart policy, builder, Dockerfile path, build command, root directory, branch) redeploys a running service (
serviceInstanceUpdate,skipDeploys: trueto only save). Watch paths apply to the next push and App Sleeping is applied in place — neither redeploys. - Roll back deploys the saved image of an earlier deployment, see below.
Logs#
Three streams per deployment: build, runtime (deploy) and system (restarts, OOM kills, scheduling events).
skiffly logs # runtime logs of the latest deployment
skiffly logs -f # follow (polls every 2 s)
skiffly logs --build # build output
skiffly logs --system # scheduler / restarts / OOM
skiffly logs -n 500 --filter "error"
skiffly logs <deploymentId>Logs are kept in a rolling buffer of the last 5 000 lines per deployment; environmentLogs merges the buffers of the environment's latest deployments. Older lines are not retrievable, so ship anything you must keep to your own log service from the app.
Redeploy, roll back, restart, cancel#
| Action | What it does | CLI | GraphQL |
|---|---|---|---|
| Redeploy | rebuild the latest commit, current variables and settings | skiffly redeploy | serviceInstanceRedeploy(serviceId, environmentId) / deploymentRedeploy(id) |
| Roll back | new deployment from an older deployment's saved image and its variables — no rebuild | dashboard | deploymentRollback(id) / deploymentRollbackV2(id) / deploymentRedeploy(id, usePreviousImageTag: true) |
| Restart | restart the containers in place, no new deployment | skiffly restart | serviceRestart(serviceId, environmentId) |
| Cancel | drop a QUEUED deployment | dashboard | deploymentCancel(id) |
| Remove | stop serving a deployment | dashboard | deploymentRemove(id) |
Rollback#
Every deployment that reached the run stage keeps its built image in the registry, together with a snapshot of the variables and runtime settings it ran with. Roll back to this in the deployment's menu (or deploymentRollback(id)) creates a new deployment from that image and snapshot: no clone, no build — the Build stage is skipped and the rollout takes as long as the containers need to start. Domains, volumes, TCP proxies and the resource limits are today's; the image, variables, start command, health check, replicas, cron and restart policy come from the snapshot. For image services the same tag is redeployed. The new deployment shows up as Rollback to <commit> with trigger rollback.
Deployment.canRollback is true when the deployment ran (SUCCESS, REMOVED, CRASHED, SLEEPING) and its image is still in the registry. Images are kept for the 10 most recent deployments of a service that ran, except deployments that have been REMOVED for more than 14 days; images of failed builds, cancelled deployments and older ones are deleted by a nightly retention job (imageRemovedAt is set and rollback is refused with a clear error — redeploy the commit instead). Rollbacks never touch the image the service is currently running.
Rollouts and downtime#
A new deployment starts alongside the old one and receives traffic once the health check passes; then the old containers are stopped. With a health check path this is zero-downtime for HTTP services. Services with a volume are the exception: the volume can be mounted by one container at a time, so the old one stops first (a few seconds of downtime for databases).
A rollout that has not become healthy within 10 minutes is marked FAILED and the previous deployment keeps running. Builds or rollouts that stop reporting for 20 minutes (a node went away) are failed by a watchdog.
Deployment metadata#
Each deployment records the commit SHA and message, the trigger (webhook, manual, redeploy, rollback, variables, pr-preview, upload, billing), who started it and a message explaining waits and failures (ImagePullBackOff, OOMKilled, CrashLoopBackOff: <last log lines>, exceeded quota). skiffly deployment list and deployments(input: { serviceId, environmentId }) return them.
Metrics#
CPU, memory and egress per service are available in Project → Observability for the last hour, 6 hours, 24 hours or 7 days (serviceMetrics(environmentId, range: H1 | H6 | H24 | D7)). Raw samples (about one per minute) are kept for 7 days; hourly aggregates are kept for 90 days and feed Workspace → Usage, which shows the same numbers aggregated into the billing period.