The Native Build Server is an alternative deployment pipeline that moves the build process from the CLI client to a centralized build server infrastructure. Instead of building Docker images locally or via Depot on the client machine, the CLI packages the deployment context into an archive, uploads it to object storage, and enqueues a build job on the server. The build server then downloads the archive, installs dependencies, builds the worker code, creates the container image, and pushes it to the registry.
This system enables faster deployments by offloading resource-intensive build operations to dedicated infrastructure and supports detached deployments where the CLI can return immediately after queueing the build. For information about the local and remote (Depot) build pipelines that this system replaces, see 7.3. For general deployment process details, see 7.4.
Sources: packages/cli-v3/src/commands/deploy.ts986-1173 apps/webapp/app/v3/services/initializeDeployment.server.ts253-286
Sources: packages/cli-v3/src/commands/deploy.ts986-1173 apps/webapp/app/v3/services/initializeDeployment.server.ts1-296 apps/webapp/app/v3/services/deployment.server.ts1-511
Sources: packages/cli-v3/src/commands/deploy.ts986-1173 apps/webapp/app/v3/services/initializeDeployment.server.ts253-286 apps/webapp/app/routes/api.v1.deployments.$deploymentId.progress.ts1-82
The CLI creates a compressed archive of the deployment context using createContextArchive() from packages/cli-v3/src/deploy/archiveContext.ts This archive contains:
package.json and lock filestrigger.config.tssyncEnvVars extension)The archive is created with either zstd or gzip compression based on the --compression flag (defaults to zstd).
Implementation in CLI:
The artifact upload follows a two-step process:
/api/v1/artifacts to get S3 upload credentialsThe server validates the artifact size against configured limits and returns upload credentials:
| Field | Description |
|---|---|
artifactKey | Unique identifier for the artifact in S3 |
uploadUrl | S3 presigned POST URL |
uploadFields | Additional form fields required by S3 |
expiresAt | Expiration timestamp for the upload URL |
CLI Upload Implementation:
Sources: packages/cli-v3/src/commands/deploy.ts1001-1067 apps/webapp/app/routes/api.v1.artifacts.ts1-92
When initializing a deployment with isNativeBuild: true, the request includes additional metadata stored in buildServerMetadata:
The deployment is created with status: "PENDING" instead of "BUILDING", indicating it's waiting in the build queue:
Sources: apps/webapp/app/v3/services/initializeDeployment.server.ts154-286
If skipEnqueue is not set (default behavior), the deployment is immediately enqueued for building:
The enqueueBuild method delegates to the platform service (cloud-only):
The build server (not included in the repository) performs the following operations:
/api/v1/deployments/:id/progress to update statuspnpm install with the project's dependenciesSources: apps/webapp/app/v3/services/initializeDeployment.server.ts253-286 apps/webapp/app/v3/services/deployment.server.ts335-351
The progressDeployment method in DeploymentService handles the state transitions:
The progress endpoint validates the current deployment status and moves it through the pipeline:
Each deployment status has an associated timeout. When a deployment transitions, the timeout is extended:
Sources: apps/webapp/app/v3/services/deployment.server.ts43-182 apps/webapp/app/routes/api.v1.deployments.$deploymentId.progress.ts1-82
The native build server uses S2 (StreamStore) to provide real-time event logs during the build process. Each deployment gets its own dedicated stream:
Streams follow the pattern:
projects/{projectExternalRef}/deployments/{deploymentShortCode}
For example: projects/proj_abc123/deployments/xyz789ab
S2 access tokens are cached in Redis to avoid repeatedly issuing new tokens:
Build servers and CLI clients append events to the stream using appendToEventLog:
Events conform to the DeploymentEvent schema defined in packages/core/src/v3/schemas/api.ts749-784:
Sources: apps/webapp/app/v3/services/deployment.server.ts17-28 apps/webapp/app/v3/services/deployment.server.ts353-469 packages/core/src/v3/schemas/api.ts749-784
The native build server is enabled via CLI flags:
| Flag | Description |
|---|---|
--native-build-server | Explicitly enable native build server |
--detach | Return immediately after queueing (implies --native-build-server) |
--compression <algo> | Archive compression algorithm (zstd or gzip, default: zstd) |
--compression-level <n> | Compression level (optional) |
The deploy command validates that native builds are not mixed with local builds:
After enqueueing the build, the CLI displays the deployment information and optionally detaches:
If --detach is not specified, the CLI would typically subscribe to the S2 event stream to display real-time logs (implementation not shown in provided files).
Sources: packages/cli-v3/src/commands/deploy.ts63-90 packages/cli-v3/src/commands/deploy.ts986-1173
This service orchestrates the deployment initialization for native builds:
Key responsibilities:
PENDING statusbuildServerMetadata for the build serverskipEnqueue is true)Configuration for native builds:
The timeout is configured differently based on initial status:
Provides methods for managing deployment lifecycle:
| Method | Purpose |
|---|---|
progressDeployment() | Advance deployment through PENDING → INSTALLING → BUILDING |
cancelDeployment() | Cancel a deployment that's not yet in a final state |
enqueueBuild() | Submit build job to the platform queue |
createEventStream() | Create S2 stream for deployment logs |
getEventStreamAccessToken() | Get/cache S2 read token for clients |
appendToEventLog() | Write events to the S2 stream |
Handles artifact creation and presigned URL generation (not shown in provided files but referenced in apps/webapp/app/routes/api.v1.artifacts.ts36-40):
The service validates artifact size limits and generates S3 presigned POST URLs with appropriate security policies.
Sources: apps/webapp/app/v3/services/initializeDeployment.server.ts1-296 apps/webapp/app/v3/services/deployment.server.ts30-511 apps/webapp/app/routes/api.v1.artifacts.ts1-92
Creates an artifact and returns presigned upload credentials.
Request Body:
Response:
Error Responses:
400: Artifact size exceeds limit401: Invalid or missing API key500: Failed to create presigned POST or internal errorInitializes a new deployment.
Request Body (Native Build):
Response:
Updates deployment status during build progression.
Request Body:
Response:
204: Successfully progressed404: Deployment not found409: Deployment cannot be progressed (not in PENDING or INSTALLING state)500: Internal server errorFinalizes the deployment after successful build and image push.
Request Body:
Response: Server-Sent Events stream with:
event: log - Build progress logsevent: ping - Keepalive every 10 secondsevent: complete - Successful finalizationevent: error - Error during finalizationSources: apps/webapp/app/routes/api.v1.artifacts.ts1-92 packages/core/src/v3/schemas/api.ts557-593 packages/core/src/v3/schemas/api.ts595-644 apps/webapp/app/routes/api.v1.deployments.$deploymentId.progress.ts1-82 apps/webapp/app/routes/api.v3.deployments.$deploymentId.finalize.ts1-105
The following environment variables control the native build server behavior:
| Variable | Purpose | Default |
|---|---|---|
S2_ENABLED | Enable S2 event streaming | "0" (disabled) |
S2_ACCESS_TOKEN | S2 API access token | - |
S2_DEPLOYMENT_LOGS_BASIN_NAME | S2 basin name for deployment logs | - |
DEPLOY_QUEUE_TIMEOUT_MS | Timeout for deployments in PENDING status | - |
DEPLOY_TIMEOUT_MS | Timeout for INSTALLING/BUILDING/DEPLOYING | - |
ARTIFACTS_BUCKET_NAME | S3 bucket for deployment artifacts | - |
ARTIFACTS_BUCKET_REGION | AWS region for artifacts bucket | - |
The buildServerMetadata field stores native build configuration:
This metadata is stored in the WorkerDeployment.buildServerMetadata JSON field and used by the build server to:
artifactKey)configFilePath)skipPromotion)buildId)The native build server integrates with GitHub deployments when skipEnqueue is true. This allows the GitHub integration to control when builds are queued:
When triggered via GitHub integration, the deployment is initialized but not immediately enqueued, allowing the GitHub app to handle build orchestration separately.
Sources: apps/webapp/app/v3/services/initializeDeployment.server.ts242-286 packages/core/src/v3/schemas/api.ts488-495 apps/webapp/app/v3/services/deployment.server.ts17-28
If artifact upload fails, the CLI cleans up the temporary archive and reports the error:
If enqueueing the build fails, the deployment is automatically canceled:
If S2 stream creation fails, the deployment continues without real-time logs:
Deployments that exceed their timeout are automatically marked as TIMED_OUT by the TimeoutDeploymentService. The timeout duration depends on the deployment status:
DEPLOY_QUEUE_TIMEOUT_MS (typically longer to accommodate queue wait times)DEPLOY_TIMEOUT_MSTimeouts are extended when the deployment progresses to a new status.
Sources: packages/cli-v3/src/commands/deploy.ts1069-1072 apps/webapp/app/v3/services/initializeDeployment.server.ts168-286 apps/webapp/app/v3/services/deployment.server.ts156-170
Refresh this wiki