Skip to content

Conversation

@nicktrn
Copy link
Collaborator

@nicktrn nicktrn commented Dec 9, 2025

This will speed up ice cold starts (*) for two reasons:

  • better compression ratio
  • faster decompression

This is a minor release because zstd compression will now be enabled by default for all deployments.

(*) ice cold starts happen when deploy images are not cached on the worker node yet. These cold start durations are highly dependent on image size and as it turns out, also the type of compression used.

@changeset-bot
Copy link

changeset-bot bot commented Dec 9, 2025

🦋 Changeset detected

Latest commit: 09ce3b3

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 26 packages
Name Type
trigger.dev Minor
d3-chat Patch
references-d3-openai-agents Patch
references-nextjs-realtime Patch
references-realtime-hooks-test Patch
references-realtime-streams Patch
references-telemetry Patch
@trigger.dev/build Minor
@trigger.dev/core Minor
@trigger.dev/python Minor
@trigger.dev/react-hooks Minor
@trigger.dev/redis-worker Minor
@trigger.dev/rsc Minor
@trigger.dev/schema-to-json Minor
@trigger.dev/sdk Minor
@trigger.dev/database Minor
@trigger.dev/otlp-importer Minor
@internal/cache Patch
@internal/clickhouse Patch
@internal/redis Patch
@internal/replication Patch
@internal/run-engine Patch
@internal/schedule-engine Patch
@internal/testcontainers Patch
@internal/tracing Patch
@internal/zod-worker Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@nicktrn nicktrn changed the title feat: deploy image zstd compression feat(cli): enable zstd compression for deployment images Dec 9, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 9, 2025

Walkthrough

This change introduces configurable zstd and gzip compression support for Docker image builds during deployment. The changeset modifies the CLI deploy command to accept compression-related options (compression algorithm, compression level for cache layers, and force-compression behavior) and propagates these through the build pipeline. A cache option replaces the previous noCache option with inverted semantics. A new getOutputOptions helper function constructs output configuration arguments with compression settings for both local and remote builds, while cache compression is conditionally appended to registry cache configurations.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Semantic inversion of caching behavior: The noCache option is replaced with cache (default true), inverting the boolean logic. Verify that all code paths correctly derive noCache: !options.cache and that no references to the old option remain.
  • Compression option propagation: Options flow from deploy.ts through buildImage.ts (remoteBuildImage, localBuildImage, buildImage). Ensure all paths receive and correctly apply compression settings.
  • getOutputOptions helper function: Verify correct construction of output array with conditional compression-level and force-compression arguments, and that it integrates correctly into both remote and local build flows.
  • Cache compression configuration: Check that cacheCompression is properly appended to cache-to arguments when using registry caching and that gzip (non-zstd) defaults maintain backward compatibility.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description lacks required template sections including a closed issue link, checklist, testing steps, and changelog entry. Complete the PR description template by adding: issue number in 'Closes #', checking off checklist items, describing testing steps, and including a brief changelog summary.
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: enabling zstd compression for deployment images in the CLI.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/image-zstd-compression

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
packages/cli-v3/src/deploy/buildImage.ts (1)

1128-1167: Minor behavioral nuance: forceCompression applies even when compression is unset or gzip

getOutputOptions will add force-compression=true whenever forceCompression is truthy, regardless of whether compression is "zstd", "gzip", or undefined. Given the CLI help text (“Enabled by default when using zstd”), that’s slightly broader than advertised if someone explicitly switches to gzip but doesn’t override the flag.

Functionally this is safe (it just forces recompression with the default algorithm) but may have a small performance cost on gzip builds.

If you want behavior to strictly match the help text, you could gate this on compression === "zstd" or clarify the description. Example tweak:

-  if (forceCompression) {
-    outputOptions.push("force-compression=true");
-  }
+  if (forceCompression && compression === "zstd") {
+    outputOptions.push("force-compression=true");
+  }
packages/cli-v3/src/commands/deploy.ts (1)

181-197: Force-compression flags: confirm Commander semantics or simplify

You define both --force-compression and --no-force-compression as separate CommandOptions for the same underlying property:

new CommandOption("--force-compression", ...)
new CommandOption("--no-force-compression", ...)

Commander typically handles “no-” negation automatically when only the negative form is declared, and having both positive and negative options for the same name can be a little opaque.

Behavior here is likely fine (last flag on the command line wins), but you might simplify by:

  • Keeping only --no-force-compression (with docs stating “enabled by default”), or
  • Using a single .option("--force-compression", "...") with .default(true) and letting Commander’s negation --no-force-compression be inferred if that works in your current version.

Not urgent, but worth double-checking for clarity and to avoid any future surprises if Commander changes how duplicate option names are handled.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2c3cb4a and 09ce3b3.

📒 Files selected for processing (3)
  • .changeset/great-pillows-look.md (1 hunks)
  • packages/cli-v3/src/commands/deploy.ts (5 hunks)
  • packages/cli-v3/src/deploy/buildImage.ts (11 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

Files:

  • packages/cli-v3/src/deploy/buildImage.ts
  • packages/cli-v3/src/commands/deploy.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Files:

  • packages/cli-v3/src/deploy/buildImage.ts
  • packages/cli-v3/src/commands/deploy.ts
**/*.{js,ts,jsx,tsx,json,md,css,scss}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier

Files:

  • packages/cli-v3/src/deploy/buildImage.ts
  • packages/cli-v3/src/commands/deploy.ts
🧬 Code graph analysis (1)
packages/cli-v3/src/deploy/buildImage.ts (1)
apps/coordinator/src/exec.ts (1)
  • push (167-173)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (23)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (7)
.changeset/great-pillows-look.md (1)

1-5: Changelog entry is well-formatted and accurately describes the change.

The Changesets file correctly specifies a minor version bump for the new zstd compression feature and uses a clear, descriptive commit-style message that aligns with the PR objectives.

packages/cli-v3/src/deploy/buildImage.ts (3)

16-27: Compression options plumbed correctly through buildImage and into local/remote builds

The new compression, cacheCompression, compressionLevel, and forceCompression fields are consistently typed across BuildImageOptions and forwarded correctly into both the local and remote build paths. The destructuring and call sites for localBuildImage and remoteBuildImage line up with the option names, so there’s no obvious wiring bug here.

Also applies to: 58-91, 93-121


156-179: Remote build output configuration: semantics look sound, but worth validating against Depot/BuildKit behavior

Using getOutputOptions to construct --output type=image,... with optional compression=zstd, compression-level, and force-compression keeps the logic centralized and matches BuildKit’s expected keys. Passing push=true here and relying on --save plus Depot’s handling of the image tag looks reasonable, but it does couple behavior to Depot’s support for the same output options and their interaction with --save.

I’d keep this as-is but explicitly validate against your target Depot/BuildKit versions that:

  • --output type=image,...,push=true works as expected with Depot’s build subcommand.
  • Combining --save with --output type=image,... does not change semantics or cause warnings/errors.

Also applies to: 196-208, 209-245


325-352: Local build: cache compression and output options integration looks correct

For self‑hosted builds:

  • compression and forceCompression are passed into getOutputOptions, so image-layer compression is handled uniformly with the remote path.
  • cacheCompression is only applied to the registry cache via --cache-to ...${cacheCompression === "zstd" ? ",compression=zstd" : ""}, which is a safe opt-in for zstd while preserving gzip as the implicit default.
  • --output and the constructed outputOptions are appended once, and the -t imageTag flag is still present, so tagging and compression configuration remain explicit.

This all aligns with the stated goal of defaulting to zstd while keeping gzip behavior unchanged when requested.

Also applies to: 354-365, 532-555, 560-562

packages/cli-v3/src/commands/deploy.ts (3)

63-90: Cache and compression defaults align with PR intent

Defining:

  • cache: z.boolean().default(true) and later using noCache: !options.cache preserves the previous “cached by default, opt-out with --no-cache” behavior while giving you a positively named flag in the typed options.
  • compression and cacheCompression defaulting to "zstd" matches the stated goal of enabling zstd by default, and leaves room for callers to opt back to "gzip".

Given Commander’s semantics for --no-cache/--cache and --compression/--cache-compression choices, this schema is consistent with the CLI surface.


518-563: buildImage invocation: cache and compression options are wired through correctly

The call to buildImage now:

  • Derives noCache as !options.cache, matching the new positive cache flag.
  • Forwards compression, cacheCompression, compressionLevel, and forceCompression directly from the parsed CLI options.

This matches the shape of BuildImageOptions and the wiring in buildImage.ts, so the deploy command is correctly propagating the new compression controls into the build pipeline.


164-197: Type mismatch risk for compressionLevel: defined but unused

The --compression-level option is defined with no .argParser() for numeric coercion, which means Commander.js will pass a string value. While compressionLevel is not currently used in the deploy handler, if it were to be used as a number (e.g., in a future implementation), it would cause a type error at runtime.

To prevent future issues, add numeric coercion to the option definition:

new CommandOption(
  "--compression-level <level>",
  "The compression level to use when building the image."
)
  .argParser((v) => Number(v))
  .hideHelp()

Alternatively, ensure any future usage of compressionLevel explicitly coerces it via Number() or parseInt().

@nicktrn nicktrn merged commit 74e9246 into main Dec 10, 2025
31 checks passed
@nicktrn nicktrn deleted the feat/image-zstd-compression branch December 10, 2025 14:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants