Skip to content

feat(dev): connect-only sst dev — finish the parked skip-when-unchanged gate#6926

Closed
benderTheCrime wants to merge 1 commit into
anomalyco:devfrom
boombox-labs:feat/connect-only-dev-skip
Closed

feat(dev): connect-only sst dev — finish the parked skip-when-unchanged gate#6926
benderTheCrime wants to merge 1 commit into
anomalyco:devfrom
boombox-labs:feat/connect-only-dev-skip

Conversation

@benderTheCrime

@benderTheCrime benderTheCrime commented Jun 24, 2026

Copy link
Copy Markdown

Finish the parked connect-only skip: skip the per-startup pulumi up when nothing changed

pkg/project/run.go has a skip gate that's been disabled in place:

// disable for now until we hash env too
if input.SkipHash != "" && buildResult.OutputFiles[0].Hash == input.SkipHash && false {
    bus.Publish(&SkipEvent{})
    return nil
}

This PR finishes it (the "hash env too" part) and wires up the dev side, behind an opt-in flag.

Why. On a large app, sst dev runs a full pulumi up over every resource on every startup. On a ~3,000-resource app a true no-op startup still spends ~4–5 min in the up (config eval + bootstrap + bridge are <5s; functions build lazily on first invoke). The cost scales with resource count, not with anything the user changed.

What it does

Opt-in SST_DEV_SKIP_UNCHANGED=1: when the fully-resolved deployment fingerprint matches the last successful deploy, skip the pulumi up entirely and reuse the already-deployed stage. Startup drops from minutes to single-digit seconds.

  • Re-enables the gate behind the flag, comparing a per-stage fingerprint persisted next to state (.sst/skiphash.<stage>).
  • Fingerprint (devSkipParts) = the esbuild config/infra bundle hash plus the env that gets baked into functions but isn't in the bundle — the missing "hash env too": secrets, _fallback secrets, SST-injected env (excluding the rotating SST_AWS_* credentials, which otherwise change the hash every run), resolved link values, and provider/SST versions. Per-component, so a declined skip logs exactly what changed.
  • SST_DEV_SKIP_MAX_AGE (seconds) forces a periodic real up to reconcile out-of-band drift, which input-hashing can't detect.
  • Dev target replay. The Pulumi program (skipped) is what normally registers the local dev function targets via Runtime.AddTarget; without them a skip connects the bridge but routes nothing (function not found). So the aws runtime registers targets from already-deployed state at its own startup (Project.DevTargets → rebuilds a runtime.BuildInput per function from each function's _live output + resolved links + the app-wide LambdaEncryptionKey). Done in the runtime, not published from the skip path, to avoid the race (the runtime subscribes only after blocking on AppSync-readiness).

Validation

Built and run against a real ~3,000-resource app:

  • No-op restart skips in seconds (vs. ~5 min): skipping deploy — deployment fingerprint unchanged.
  • Changing a secret → fingerprint differs → real deploy (no stale serve).
  • GraphQL/Lambda dev works off the skipped stage (replay registers all functions).

Notes

  • Opt-in; default behavior is unchanged.
  • Residual gap (documented): ambient process.env read directly in sst.config.ts and out-of-band drift aren't caught by input-hashing — SST_DEV_SKIP_MAX_AGE is the backstop.
  • Branched from v4.14.1 (currently 15 commits behind dev, clean ancestor — diff is just the 3 files); happy to rebase onto dev.
  • Touches pkg/project/run.go, pkg/flag/flag.go, cmd/sst/mosaic/aws/function.go.

…en unchanged

Opt-in via SST_DEV_SKIP_UNCHANGED. When the fully-resolved deployment
fingerprint matches the last successful deploy, skip the `pulumi up`
entirely and reuse the already-deployed stage — cutting `sst dev` startup
from minutes to seconds on large stacks (the up is otherwise a full diff
over every resource on every startup).

- Re-enable the parked skip gate in pkg/project/run.go behind the flag,
  gated on a per-stage fingerprint persisted next to state.
- Fingerprint (devSkipParts) = the config/infra bundle hash plus the env
  baked into functions that the bundle misses: secrets, _fallback secrets,
  SST-injected env (excluding the rotating SST_AWS_* credentials), resolved
  link values, and provider/SST versions. This is the "hash env too" the
  upstream `&& false` gate was waiting on.
- SST_DEV_SKIP_MAX_AGE forces a periodic real up to reconcile out-of-band drift.
- Register dev function targets from already-deployed state at the aws
  runtime's own startup (Project.DevTargets), so a skip still serves
  GraphQL/Lambda — race-free, vs. the program's AddTarget which the skip avoids.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@benderTheCrime benderTheCrime force-pushed the feat/connect-only-dev-skip branch from e8c4beb to 8bfb96c Compare June 25, 2026 21:52
@benderTheCrime

Copy link
Copy Markdown
Author

@vimtor @thdxr - this is here if you want it at any point! let me know!

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.

1 participant