1525 Commits

Author SHA1 Message Date
Hendrik Liebau c00449d52b [ci] Wait for the preview tarballs before running the deploy tests (#96527)
The "Test new and changed tests when deployed" jobs install Next.js from
the preview tarballs built for the commit under test, but nothing made
them wait for those tarballs to exist. Until #96438 the job was ordered
behind `test-prod` and the other new-test jobs, which delayed it long
enough that the tarballs had usually landed by the time it looked for
them. Now that it starts immediately it frequently fails with "Artifacts
not found for commit ...".

The ordering cannot be expressed as a `needs:` entry, because the
tarballs are published by a different workflow and, for pull requests
from branches in this repository, a different event than the
`build-and-test` run that consumes them. We therefore add a
`wait-for-preview-tarball` job that polls for the tarball instead, and
make both deploy test jobs depend on it. Doing the waiting in one cheap
job keeps the deploy test matrices off their 16-core runners until there
is something for them to install.

The new job is also listed in `tests-pass`. A dependency failure skips
the jobs that need it, and a skipped job does not count as a failure, so
without that entry a tarball that never arrives would have let the
required check pass with the deploy tests never having run.

`test-new-tests-deploy-cache-components` gets the same treatment,
dropping the incidental ordering it still inherited from
`test-cache-components-prod` and picking up the docs-only guard that
`test-new-tests-deploy` already had.
2026-08-03 16:27:51 +02:00
Marcos Hernanz 439163392d Add automated code review workflow (#96359)
## Summary

Adds one protected `pull_request_target` workflow for advisory automated
review of non-draft, member-authored PRs.

The existing Vercel reviewer runs Codex, Claude, and synthesis with
read-only GitHub access. This base-owned workflow treats that result as
untrusted, validates it, and owns the only GitHub mutation.

## Write boundary

- no checkout, PR code execution, dependency installation, Actions
secrets, or shell interpolation
- globally empty permissions; the job has only OIDC and pull-request
read
- exact repository, event, author association, PR state, base SHA, and
head SHA validation
- final read-only PR revalidation immediately before publishing
- HTML comments stripped, mentions neutralized, token patterns redacted,
and output capped at 48 KB
- a write token is minted only after validation
- exactly one top-level comment `POST` or `PATCH`
- existing comments are eligible only when attributed to one of gh-sts's
immutable `general` GitHub App IDs and begin with the fixed marker
- both actions are pinned to immutable commit SHAs

The workflow intentionally runs once on `opened` or `ready_for_review`;
it does not run on `synchronize`.

## Validation

- `actionlint`
- Prettier
- syntax validation of all three embedded `github-script` programs
- upstream commit verification for both pinned actions
- independent Codex and Claude autoreview

The workflow remains inert until the matching gh-sts policy is approved.
2026-07-31 17:32:32 -04:00
Sebastian "Sebbie" Silbermann dc358f450c [ci] Run new/changed deploy tests asap (#96438)
These are equally important if not more important (since they test build
adapters) than next-start tests so we now run them immediately instead
of waiting for test-prod.

They job is now skipped entirely for docs changes. Which saves a few
seconds for docs-only changes.
2026-07-31 20:12:30 +00:00
Benjamin Woodruff f6d094061e [ci] Background some steps in build_reusable to reduce setup overhead, remove unneeded lld installation (#96195)
This is a pretty minor win, but it can save a few seconds per job.


https://github.blog/changelog/2026-06-25-actions-steps-can-now-be-run-in-parallel/

Also remove the installation of `lld` for rustc with `apt-get`. It's
very slow, and rustc should already ship with `lld` these days? The
composite action to install the rust toolchain isn't run often (test
shards download a prebuilt native binary), but `build-native` it can
block other jobs from running and become a bottleneck.

Testing the full `build-and-deploy` job, which uses the rust install
action: https://github.com/vercel/next.js/actions/runs/30138483769
2026-07-28 22:49:20 -07:00
Sebastian "Sebbie" Silbermann 1412d0fe91 [cd] Send Slack notification if publish fails (#96304)
Failing to publish (especially a partial publish) leaves Next.js in a
corrupted state that needs to be addressed immediately. However, we only
created alerts when deploy tests failed which requires a successful
publish.

Now we send special message to the same channel as broken canary and
deploy tests go.

This won't catch a failing deploy-target job. We'll see if deploy-target
also frequently fails/flakes.
2026-07-28 15:21:21 -04:00
Sebastian "Sebbie" Silbermann e8866c8b7a [ci] Skip passed-tests cache steps for jobs that never run tests (#96001)
CI jobs in `build_and_test` printed a "Cache save failed." warning from
the "Save passed-tests cache" step even when they never run tests. The
step ran for every job with an `afterBuild` command, but
`.next-test-passed.txt` is only ever written by `run-tests.js`, so jobs
like lint, rust-check, or types-and-precompiled warned on every run
because the path never existed.

`run-tests.js` already owns the decision of whether result caching is
active (`profile.cachingEnabled`), so it now signals the workflow
itself: when it opens the passed-tests file (which happens before any
test runs, and only when result caching is enabled), it writes the path
to the `passed_tests_file` step output. The "Save passed-tests cache"
step in `build_reusable.yml` only runs when that output is present and
takes its `path` from it. Jobs that never run `run-tests.js`, and
flake-detection runs (where `NEXT_FLAKE_DETECTION` disables the result
cache), never emit the output and skip the save silently. A job that
fails midway through its tests has already emitted the output, so its
partial file still saves and a genuine warning is still possible.
2026-07-21 12:21:45 +00:00
Sebastian "Sebbie" Silbermann f8dc962e17 [ci] Avoid apt-get in the next-stats-action Docker image (#95847)
The `Stats (webpack)` / `Stats (turbopack)` CI jobs have been
intermittently failing on PRs and canary (e.g. [this
run](https://github.com/vercel/next.js/actions/runs/29476089144/job/87563318723)).
The jobs run on arm64 runners, where the `ubuntu:24.04` base image
fetches apt packages from `ports.ubuntu.com`, which is intermittently
unreachable. Since `apt-get update` only warns when index fetches fail,
the Docker build breaks one layer later at `apt-get install` with
"Unable to locate package curl".

This change switches the base image to `buildpack-deps:noble-scm`, which
already ships curl, ca-certificates, and git, so the build no longer
makes any apt calls at all. The `apt-get upgrade` step is dropped along
with it; it was already a silent no-op whenever the mirror was down, and
the ephemeral CI container does not rely on it.

Both `.github/next-stats-action.Dockerfile` (the one CI builds via
`action.yml`) and the duplicate
`.github/actions/next-stats-action/Dockerfile` are updated to stay in
sync.
2026-07-17 10:45:36 -07:00
Sebastian "Sebbie" Silbermann 3ae5630d0a [ci] Allow running all deploy tests with builds from a private registry (#95784) 2026-07-16 11:33:21 +02:00
Benjamin Woodruff 0cfc85ceae Clarify AI-assisted contribution policy in PR template and AGENTS.md (#95629)
## Summary

Documents the policy around AI-assisted contributions, for both humans
and agents:

- `.github/pull_request_template.md`: notes that AI use is encouraged
for researching, creating, and reviewing changes, but contributors must
deeply understand their contributions, and PR descriptions from external
contributors must be written by a human.
- `.github/ISSUE_TEMPLATE/1.bug_report.yml`: adds the equivalent note
for bug reports — issue descriptions from external contributors must be
written by a human, though AI may help create reproductions.
- `AGENTS.md`: replaces the old "PR Descriptions" section with two new
sections. "GitHub Pull Requests" distinguishes branch PRs (agents may
write descriptions) from fork PRs targeting `vercel/next.js` (agents may
not). "GitHub Issues, Comments, and Discussions" restricts agent-written
issues, discussions, and comments to members of the
`vercel`/`vercel-labs` GitHub orgs, tells agents how to check membership
via the GitHub API, lists what agents can still help non-members with
(drafting details, reviewing, reproductions, translation, searching for
duplicates), and carves out exceptions (commenting on the user's own PR,
Vercel-operated bots, GitHub/Graphite review bots, and forks of the
repo).
- Renames the LLM watermark marker from `NEXT_JS_LLM_PR` to
`NEXT_JS_LLM` everywhere it appears (`AGENTS.md`,
`contributing/repository/pull-request-descriptions.md`, and the
`create-pr`/`backport-pr` skills), since it now also applies to issues,
discussions, and comments. Nothing in the repo consumes the old marker
name.
- `.agents/skills/create-pr/SKILL.md`: adds a "Fork PRs vs Branch PRs"
section referencing the `AGENTS.md` policy. Assorted typo fixes along
the way.

## Verification

- `gh api /user/memberships/orgs` and `gh api
orgs/vercel/members/<login>` (confirmed the documented membership checks
work and return the documented statuses)
- Not run: no test/build commands (docs-only change; prettier applied
via the pre-commit hook)

<!-- NEXT_JS_LLM -->
2026-07-10 11:27:52 -07:00
Jude Gao 45e0295d70 [ci] Bump PR stats job timeout to 35 minutes (#95592) 2026-07-08 20:09:41 -04:00
Niklas Mischkulnig da06078b9b test: Fix immutable static asset deployment tests for real (#95600)
https://github.com/vercel/next.js/pull/95550 wasn't enough:

-
https://github.com/vercel/next.js/actions/runs/28907225463/job/85769093204
-
https://github.com/vercel/next.js/actions/runs/28907225463/job/85769093252

Because `VERCEL_IMMUTABLE_STATIC_FILES_ENABLED` might be set, but it
still only works when using adapters, so it broke in the non-adapter
deploy test jobs.

Also prepare for when we switch the default of `NEXT_ENABLE_ADAPTER` by
setting it explicitly to `0` for when we want to test the old CLI
builder.
2026-07-08 14:16:35 +02:00
Benjamin Woodruff bd77087864 [ci] Migrate webpack tests back to arm runners (#95549)
I partially rolled back CI jobs because we ran out of runners. IT
increased the concurrency from 50 to 100, so I've been slowly migrating
back to arm runners while watching that we don't end up with long queue
times again.

Thread: https://vercel.slack.com/archives/C0B0LKK5QD7/p1782838752523649

Average job queue time in the last day has been 59 seconds:

https://github.com/vercel/next.js/actions/metrics/performance?dateRangeType=DATE_RANGE_TYPE_CUSTOM&range=1783296000000-1783296000000
2026-07-07 07:50:14 -07:00
Niklas Mischkulnig b3278b7573 test: Use Turbopack for 'Test new and changed tests when deployed' (#95552) 2026-07-07 16:03:00 +02:00
Niklas Mischkulnig f51577ae81 ci: Bump withgraphite/graphite-ci-action (#95562)
- https://github.com/withgraphite/graphite-ci-action/pull/50
- https://github.com/withgraphite/graphite-ci-action/pull/51
2026-07-07 13:26:25 +00:00
Benjamin Woodruff 727a3ffa86 [ci] Skip apt-installed dependencies in playwright install step (#95535)
The hypothesis is that this is just installing some font stuff that
isn't actually needed for Chromium to work:

```
The following additional packages will be installed:
  libnss3-tools xfonts-encodings xfonts-utils
Recommended packages:
  fonts-ipafont-mincho fonts-liberation-sans-narrow fonts-tlwg-loma
The following NEW packages will be installed:
  fonts-freefont-ttf fonts-ipafont-gothic fonts-liberation fonts-tlwg-loma-otf
  fonts-unifont fonts-wqy-zenhei xfonts-cyrillic xfonts-encodings
  xfonts-scalable xfonts-utils
The following packages will be upgraded:
  libnss3 libnss3-tools
2 upgraded, 10 newly installed, 0 to remove and 35 not upgraded.
```

`apt` is very slow, so skipping this step should significantly reduce
setup time per test shard.

It seems like this isn't always true for other browsers, so only skip
this for Chromium (that's fine, that's what most of our jobs use
anyways).

On 16 core arm runners, "Install Playwright Browsers" typically took
18-24 seconds. Now it takes 5-6s.

Let's estimate that saves about 15s per Linux job that installs
Chromium. Claude estimates that there are 73 chromium-only Linux jobs on
this PR:

<img width="891" height="148" alt="Screenshot 2026-07-06 at 10 30 16 PM"
src="https://github.com/user-attachments/assets/725893fa-9f6f-4806-a3b4-9858ab0ebe66"
/>

So that's 15*73/60=18.25 minutes saved per PR push (the average PR gets
many pushes). At the public (before any volume discounts) price of
$0.026/minute for the 16 core arm runners, that comes out to $0.4745 per
PR push saved.

This workflow has had 3,894 runs in the last 30 days, so that could be
$1,847/mo saved, but many of those workflow runs were canceled, and some
likely failed before getting to these jobs, so the actual savings are
probably somewhere around half of that -- scroll through
https://github.com/vercel/next.js/actions/workflows/.github/workflows/build_and_test.yml
and see that a little less than half of the workflow runs end up
canceled.
2026-07-07 09:48:46 +02:00
Sebastian "Sebbie" Silbermann cd3476c3c8 [ci] Add stats comment with partial stats (#95401)
We used to not post a comment when a part of the bundler matrix got
cancelled. Conceptually, a cancelled job is just like a failed on in the
sense of not being able to produce stats.

Now we always aggregate stats and post stats from the bundlers that did
produce them.

The risk here is a race between a run that was cancelled because another
run superseded it and the run that superseded it. Though practically,
aggregating the stats isn't slower than running the full workflow. Not
impossible (especially given how slow the Webpack job is) but incredibly
rare.
2026-07-06 19:13:28 +00:00
Sebastian "Sebbie" Silbermann f656c597c6 [fragment-scroll] Enable new scroll handler by default (#95378) 2026-07-06 18:39:07 +00:00
Hendrik Liebau 422c93ef86 Add serverComponentsHmrCancellation experimental flag (#95462)
This is the first change in a series that will let `next dev` cancel a
Server Components HMR refresh once a newer refresh supersedes it. Here
we only introduce the `experimental.serverComponentsHmrCancellation`
flag and plumb it to every place later changes will read it, without
adding any behavior yet, so on its own this change is an inert no-op.

The flag is declared in `ExperimentalConfig`, validated in the Zod
schema, and defaults to `false` in `defaultConfig`. We thread it into
the runtime config via the `NextConfigRuntime` pick list and
`getNextConfigRuntime`, expose it to user-bundled client code through
`define-env` as `process.env.__NEXT_SERVER_COMPONENTS_HMR_CANCELLATION`,
and pass it into the app render options in `base-server.ts` and the
`app-page` build template. The edge SSR template hardcodes it to
`false`, because edge rendering does not expose the Node response-close
signal the cancellation relies on.

So that the following changes are exercised as soon as their behavior
lands, `config.ts` honors a
`__NEXT_EXPERIMENTAL_SERVER_COMPONENTS_HMR_CANCELLATION` environment
variable that forces the flag on while still respecting an explicit user
config value, mirroring how `cachedNavigations` is rolled out. Both the
`test-cache-components-dev` and `test-cache-components-prod` CI shards
export that variable: the development shard so the feature is exercised
once its behavior lands, and the production shard as a guard that this
development-only feature stays inert in production even with the flag
enabled. The default stays `false`; a later change flips it once the
implementation is complete and drops the shard overrides.
2026-07-04 14:23:35 +02:00
Sebastian "Sebbie" Silbermann d3169de7e5 Collect modules with browser variants statically (#95200)
Instead of hardcoding the list, we now automatically detect any
`.browser` sibling and create a compiler alias for that module.

Together with a linting rule, we'll ensure no future regressions are
handled automatically (detection of conditional require and missing
.browser sibling).

This isn't the smoothest DX yet. Ideally we'd generate the list at
Next.js compile time (i.e. before publishing) to avoid having to rerun a
script (I'll follow-up). Generating the list during build time (next dev
or next build) is just another tiny cost users would have to pay.
2026-07-03 08:45:23 +02:00
Benjamin Woodruff 6f592dec9d [ci] Disable mid-stack PR optimization for native PR stacks (#95427)
https://vercel.slack.com/archives/C04KC8A53T7/p1783018076576349

<img width="1015" height="347" alt="Screenshot 2026-07-02 at 11 57
05 AM"
src="https://github.com/user-attachments/assets/74d99079-d165-435a-aece-161862795ef6"
/>

If we're in the middle of a stack, but the PRs below us in the stack are
already merged, we should not skip CI jobs. This logic isn't smart
enough to handle that.
2026-07-02 19:28:37 +00:00
Benjamin Woodruff 24262a8212 [ci] Actually migrate Turbopack jobs back to ARM (#95386)
This is embarrassing, I wasn't paying enough attention when I put up
#95374. We have to both change the build dependency *and* switch the
machine type...
2026-07-02 08:40:01 -07:00
Benjamin Woodruff a26a1d640b [ci] Avoid running full CI mid-stack for GH-native stacks, same as we do for Graphite (#95218)
Running CI only on the top and bottom of the stack avoids expensive
`O(n^2)` behavior when merging one PR at a time and recursively rebasing
all the others starting at the bottom of the stack.

GitHub added this to the webhook/GH actions object for us to be able to
do this: https://vercel.slack.com/archives/C01SKER9S1G/p1777926655162839

Prior to this PR being part of a stack, fails open (runs full CI):
<img width="1938" height="993" alt="Screenshot 2026-06-26 at 3 03 37 PM"
src="https://github.com/user-attachments/assets/54d6055a-2860-45b3-a03a-a9356b3db2a4"
/>

Example mid-stack run (skips the full e2e jobs):
<img width="1917" height="664" alt="Screenshot 2026-06-26 at 3 24 33 PM"
src="https://github.com/user-attachments/assets/9ee466da-f3ea-4298-b5b8-2527d197c121"
/>

https://github.com/vercel/next.js/actions/runs/28268549361/job/83760907003?pr=95219
2026-07-01 23:22:24 -07:00
Benjamin Woodruff 36331cfe3b [ci] Migrate Turbopack build_and_test jobs back to arm64, leave webpack jobs as x86-64 (#95374)
IT increased the concurrency limit from 50 to 100. This ramps back up
the `build_and_test` job. I'll keep an eye out for long queue times
before migrating us all the way back to arm64.


https://vercel.slack.com/archives/C0B0LKK5QD7/p1782910263667649?thread_ts=1782838752.523649&cid=C0B0LKK5QD7
2026-07-01 21:47:32 +00:00
Benjamin Woodruff 7b68a3135f [ci] Migrate some CI jobs back to x86-64, build both arm and x86-64 native binaries, include both os and architecture in native artifact names (#95341)
This should be a more robust version of
https://github.com/vercel/next.js/pull/95332 that re-introduces some
x86-64 runners, but also properly segments the artifact cache.

Even if we don't end up merging this, this does some cleanup of
`uploadNativeArtifact` that might be useful to pull out into a separate
PR.
2026-07-01 10:39:43 +02:00
Benjamin Woodruff 860c0742e9 [ci] Add optimize-ci, changes, and fetch-test-timings jobs to the needs list for the tests-pass job (#95339)
On #95332, the `fetch-test-timings` job failed. That caused downstream
jobs to get a "skip" state, instead of a failure state, which then
caused `tests-pass` to succeed. This is because if a dependency job
fails, GitHub's default behavior is for the downstream job to skip, and
to not cascade the failure.

Depending on all of these helper jobs seems like the simplest way to
prevent this from happening in the future.
2026-07-01 10:39:43 +02:00
Benjamin Woodruff c2edfabcdd Revert "[ci] Move some test suites back to x86-64 runners to reduce pressure on our currently-limited pool of arm runners (#95332)" (#95336)
There was a bug in this PR
(https://github.com/vercel/next.js/pull/95332#discussion_r3502904527)
but it "passed" CI and auto-merged because `fetch test timings` failed
causing downstream jobs to end up in a skipped state. I'll fix that in a
separate PR.
2026-07-01 06:07:18 +02:00
Benjamin Woodruff 792f746339 [ci] Move some test suites back to x86-64 runners to reduce pressure on our currently-limited pool of arm runners (#95332)
https://vercel.slack.com/archives/C0B0LKK5QD7/p1782838752523649

This is a mitigation until we can get IT to increase the concurrency on
`ubuntu-latest-16-core-arm-oss` runners.
2026-07-01 02:41:34 +00:00
Sebastian "Sebbie" Silbermann dcb662c7fb [ci] Add support for auth based preview build registries (#95204)
Follow-up to https://github.com/vercel/next.js/pull/93464 which didn't
consider auth based preview build registries.
2026-06-30 20:59:15 +02:00
Benjamin Woodruff 38bd101b10 [ci] Migrate build_and_test and pull_request_stats to use arm64 runners (#94870)
A 16 core x86-64 runner is $0.042/minute. A 16 core arm64 runner is
$0.026/minute.
https://docs.github.com/en/billing/reference/actions-runner-pricing

It also looks like they're faster! After factoring the performance
improvement, this appears to be a ~50% cost reduction for migrated jobs.

Datadog SQL:

```
SELECT
  REGEXP_REPLACE(ci_job_name, '\s*\([0-9]+/[0-9]+\)', '') AS ci_job_name,
  labels,
  branch,
  commit_date,
  SUM(duration) / 1000 / 1000 / 1000 / 60 as minutes,
  ci_pipeline_id
FROM dd.ci_pipelines(
    columns => ARRAY ['@git.commit.committer.date', '@ci.pipeline.id', '@duration', '@git.branch', '@ci.node.labels', '@ci.job.name'],
    event_type => 'job',
    filter => '@git.repository.id_v2:github.com/vercel/next.js @ci.pipeline.name:build-and-test @ci.provider.instance:github-actions @ci.pipeline.id:(28266192824-1 OR 28266190122-2) -@ci.job.name:*changed*',
    from_timestamp => now() - INTERVAL '30 days',
    to_timestamp => now()
  ) AS (
    commit_date VARCHAR,
    ci_pipeline_id VARCHAR,
    duration BIGINT,
    branch VARCHAR,
    labels VARCHAR,
    ci_job_name VARCHAR
  )
GROUP BY
  REGEXP_REPLACE(ci_job_name, '\s*\([0-9]+/[0-9]+\)', ''),
  labels,
  commit_date,
  branch, 
  ci_pipeline_id
ORDER BY 
  REGEXP_REPLACE(ci_job_name, '\s*\([0-9]+/[0-9]+\)', ''),
  branch,
  commit_date,
  minutes;
```


https://app.datadoghq.com/ddsql/editor?ddsql_dataset_id=34de66b9-30f4-48dd-ac98-354dc7e67fdf

Full Data:
https://docs.google.com/spreadsheets/d/1SszR3RsPeJ13nVW5ggMakwy87fkQMqWMHbZDehHH8IA/edit?usp=sharing

Here's the abbreviated data for jobs longer than 5 minutes:
<img width="1187" height="656" alt="Screenshot 2026-06-26 at 4 38 00 PM"
src="https://github.com/user-attachments/assets/9341039e-c4ea-405c-8d24-cdbc5ed1ba24"
/>

It seems like for the jobs switched over to arm64, they run in about
~73-82% of the time as arm.
2026-06-30 09:57:35 -07:00
Sebastian "Sebbie" Silbermann 287c04cf86 [ci] skip Datadog git metadata upload on junit upload (#95210)
Pass `--skip-git-metadata-upload` to all `datadog-ci junit upload`
invocations. This stops the in-CI git metadata sync, which forces an
expensive `git fetch` unshallow on every shallow CI checkout before each
test-report upload.

We don't need to upload git metadata manually since our GH actions are
directly integrated with DataDog via app.

> Git metadata upload is only required if you can’t integrate your CI
provider directly with Datadog. If you are using a [source code provider
integration](https://docs.datadoghq.com/code_coverage/setup/?tab=github#integrate-with-source-code-provider),
such as Datadog GitHub app or Gitlab integration, you can disable the
git metadata upload by passing the --skip-git-metadata-upload=1 flag to
the datadog-ci coverage upload command, like this:


--https://docs.datadoghq.com/code_coverage/setup/?tab=github#coverage-upload-outputs-could-not-sync-git-metadata-error

## test plan

- [x] no more unshallow when uploading junit reports to DataDog: [upload
from this branch shows no "syncing git
metadata"](https://github.com/vercel/next.js/actions/runs/28252881331/job/83708778650?pr=95210#step:38:113)
that [you'd used to see on prior
uploads](https://github.com/vercel/next.js/actions/runs/28252765955/job/83708485242?pr=95207#step:38:112)
2026-06-26 10:59:17 -07:00
Sebastian "Sebbie" Silbermann 1d09001f0c [cd] Allow forcing a release without new commits (#95136) 2026-06-25 05:25:22 +00:00
Sebastian "Sebbie" Silbermann 69acc33f03 [ci] Make automatic native binding install opt-in (#95114)
A `pnpm install` installs native bindings for Next.js by default. This
makes sense for local development where half of the team doesn't work on
native code and just needs the most recent bindings. However, CI almost
exclusively wants to test with bindings that are built from the current
commit. The rest doesn't need native bindings at all.

The only exception is `test_examples` which is likely not functional.
Though we still support it by allowing to opt-into automatically
installing native bindings in CI.

## test plan

- [x] fetch test timings still skips:
https://github.com/vercel/next.js/actions/runs/28087707205/job/83157705446?pr=95114#step:7:228
2026-06-24 22:39:36 +02:00
Sebastian "Sebbie" Silbermann 681940523a [cd] add ad-hoc preview release cut from canary (#95086)
Add a `preview` release type so `@preview` npm releases can be cut
**ad-hoc from `canary`** via the `Trigger Release` workflow, retiring
the dedicated long-lived preview branch. The GitHub environment has been
updated accordingly.

A preview cut produces **two commits**, pushed in a single update:

1. **Bump-to-preview** — all packages set to the computed preview
version, tagged `v…-preview.N`. This tag's build publishes `@preview`
(relies on #95085).
2. **Revert-to-canary** — restores the `-canary.N` versions so `canary`
keeps advancing its own line and isn't stranded on a preview version.

```
B  canary HEAD before cut (e.g. 16.3.0-canary.61)
│
P  v16.3.0-preview.N   ← tag here; tag build publishes @preview
│
R  canary HEAD after cut (versions restored to 16.3.0-canary.61)
```

### Preview version numbering

`base = max(canary major.minor.patch, npm @preview major.minor.patch)`:
- base still on the published preview line → continue it (`n + 1`)
- canary advanced to a higher base (or no `@preview` published) → reset
to `.0`

So if `canary` jumps to `18.0.0-canary.x` since the last
`16.3.0-preview.x`, the next cut is `18.0.0-preview.0`, not a
continuation.

## Test plan

The dry mode of `start-release.js` was extended to intercept the GH
requests and log the relevant data.

```console
$ node ./scripts/start-release.js --release-type preview --dry-run
Dry run: keeping commits locally, skipping git push and GitHub release creation
Running pnpm release-preview...
[...]
> lerna version 16.3.0-preview.4 --force-publish -y --no-push --allow-branch '**'
[...]
Creating GitHub-signed release commit(s) for v16.3.0-preview.4 from local commits 0f5c1e865cc34edb257a16823ed6525d9cd58bfc..0062348c411776271fe7eac64e97b8bad2775b77
[dry-run] GitHub API POST /repos/vercel/next.js/git/blobs [...]
[dry-run] GitHub API POST /repos/vercel/next.js/git/commits {"message":"v16.3.0-preview.4","tree":"0000000000000000000000000000000000000016","parents":["0f5c1e865cc34edb257a16823ed6525d9cd58bfc"]}
[dry-run] GitHub API POST /repos/vercel/next.js/git/commits {"message":"Restore canary version 16.3.0-canary.61 after v16.3.0-preview.4 preview release","tree":"000000000000000000000000000000000000002d","parents":["0000000000000000000000000000000000000017"]}
[dry-run] GitHub API POST /repos/vercel/next.js/git/refs {"ref":"refs/tags/v16.3.0-preview.4","sha":"0000000000000000000000000000000000000017"}
[dry-run] GitHub API PATCH /repos/vercel/next.js/git/refs/heads/sebbie/preview-release-from-canary {"sha":"000000000000000000000000000000000000002e","force":false}
Dry run: skipping local branch sync; would set sebbie/preview-release-from-canary to 000000000000000000000000000000000000002e and tag v16.3.0-preview.4 at 0000000000000000000000000000000000000017
Created GitHub-signed release tag v16.3.0-preview.4 at 0000000000000000000000000000000000000017; branch sebbie/preview-release-from-canary now at 000000000000000000000000000000000000002e
Dry run: skipping GitHub release creation
Release process is finished
```
2026-06-24 16:33:37 +02:00
Sebastian "Sebbie" Silbermann e2f853850e [ci] Make preview tarballs available while new Canaries are being published (#95112)
Fixes 

>This environment is not supported by Next.js or publish of
16.3.0-canary.64 is incomplete.

--
https://github.com/vercel/next.js/actions/runs/28082958066/job/83141991913#step:7:246
2026-06-24 16:32:48 +02:00
Sebastian "Sebbie" Silbermann c8ff8b1c52 [cd] publish on release tags instead of branch push (#95085)
That way we can push multiple commits when doing a release. For
canaries, nothing will change.

In a follow-up, we'll start cutting `@preview` from the `canary` branch.
To support that case, we need to immediately revert the version in
`lerna.json`. We shouldn't push commits indidually to avoid having an
incomplete release if something else is pushed between `@preview`
version bumps and `@canary` version reverts.

## test plan

After merge, the next canary release should publish from the
`v…-canary.N` tag run (`deploy-target = production`), while the canary
branch push for the same commit shows `skipped` — exactly one production
run per release.



<!-- NEXT_JS_LLM_PR -->
2026-06-24 08:52:30 +02:00
Benjamin Woodruff 51d440520a [ci] Only install chromium-headless-shell and not chromium (#94882)
Because it's not sure which one you'll want, playwright installs TWO
copies of Chromium by default. A full copy and a stripped down headless
version.

Most of the install time is spent in `apt-get`/`dpkg`, but this at least
buys us a few seconds back.

Before:

![Screenshot 2026-06-16 at
6.02.44 PM.png](https://app.graphite.com/user-attachments/assets/1cb05dca-c36d-472d-8ffd-1e177f77fc10.png)

After:

<img width="1700" height="552" alt="Screenshot 2026-06-16 at 6 24 50 PM"
src="https://github.com/user-attachments/assets/d382cb8e-a875-4d67-92d6-32ff51c06488"
/>


Playwright also installs ffmpeg in case you want to perform a screen
recording (we don't), but it's much smaller (2.3 MiB), and there doesn't
appear to be a way to disable it.
2026-06-17 21:20:01 +00:00
Sebastian "Sebbie" Silbermann 47c8c6fc92 [cd] Continue release train if @next/swc-wasm-* fails to publish (#94912)
https://github.com/vercel/next.js/pull/94622 tried to be more strict
with when a release is considered healthy. However, `@next/swc-wasm-web`
is not enrolled in Trusted Publishing and blocks the release train.

This PR restores the behavior for `@next/swc-wasm-*` packages prior to
https://github.com/vercel/next.js/pull/94622 i.e. we continue the
release train even if any `@next/swc-wasm-*` fails. Other NAPI bindings
will continue to block the release train if they fail to publish.

The bail vs no-bail behavior is controlled with a repository variable so
that we can mor easily test if `@next/swc-wasm-web` is enrolled in
Trusted Publishing.
2026-06-17 20:49:57 +02:00
Sebastian "Sebbie" Silbermann 618957c166 [cd] More robust publish pipeline (#94622) 2026-06-17 19:44:59 +02:00
Benjamin Woodruff eb9b1dad10 [ci] Remove playwright stamp file logic (#94876)
This is left over from self-hosted runners. This should never be used in
gh hosted runners.
2026-06-17 09:08:41 -07:00
Luke Sandberg 723c06200d switch our test benchmark runs to release-with-assertions (#94538)
In ci when testing our benchmarks use our test profile
`release-with-assertions`

This avoids an expensive `lto` step and ensures that our tests run with
debug asserts.

I noticed that our workflow for 'test cargo benches' was very slow and a
lot of that time was the build presumably due to lto overheads across so
many benchmark binaries.


Compare:

* cargo benches for this pr:
https://github.com/vercel/next.js/runs/79974366863?pr=94538
   - build=4m42s
   - test=1m46s
* cargo benches before this pr:
https://github.com/vercel/next.js/actions/runs/27097792020/job/79973082715#logs
   - build=8m23s
   - test=6m56s

Of course doing this revealed a few things

* a birthday paradox panic in one of the persistence tests
* some 'top level read' errors to address in the benchmarks and in the
turbopack-cli server used for some benchmarks.

And finally, that the persistence tests are just extremely slow in test
mode due to their initialization overhead (populating >1GB dbs), so that
harness is rewritten to remove some variants and also to reduce max
sizes in test mode
2026-06-17 16:05:05 +00:00
Benjamin Woodruff b08fb8d922 [ci] Clean up references to self-hosted runners (#94827)
We're no longer using self-hosted runners. I had claude look for places
where we had references to self-hosted runners and I had it clean them
up.

Stats job for this PR:
https://github.com/vercel/next.js/actions/runs/27572281422/job/81511924690?pr=94827
2026-06-16 09:17:10 -07:00
Benjamin Woodruff 36a8f4c271 [ci] Use node-version-file when we already have a repository checkout and reduce hardcoded references to node versions (#94780)
I noticed the `node-version-file` option for `setup-node` while
reviewing https://github.com/vercel/nextjs-react-compiler/pull/2

We should use it in places where we're already checking out the
repository anyways. It should make it easier to keep node versions in
sync.
2026-06-16 00:48:22 +00:00
Luke Sandberg cd1a292c7b pass --locked to cargo binstall (#94834)
If `binstall` fails to download a precompiled artifact it falls back to
`cargo install` and many tools (like `nextest`) require the `--locked`
flag. So pass the `--locked` flag.
2026-06-15 17:18:44 -07:00
Cong-Cong Pan eacb749030 chore: upgrade next-rspack to rspack 2.0 (#92222)
## Summary
- upgrade `@rspack/core` to `2.0.0-rc.0`
- sync the in-tree next rspack Rust binding/toolchain with newer rspack
releases
- align Next server runtime selection so `NEXT_RSPACK` uses the
turbo-like app runtime path
- include missing compiled `@next/react-refresh-utils` output in
`ncc-compiled`

## What is done
- `@next/rspack` Rust binding builds locally
- `packages/next` builds locally
- rspack-related tests are running and have been reduced to deeper
runtime compatibility failures

## Rspack test investigation
Latest checked CI run: `build-and-test` run `27129243230` at head
`484e7bf1b30655a9f94d0855b9e00774b4b38cd0`.

Confirmed Rspack / webpack parity gaps:
-
`test/e2e/edge-runtime-configurable-guards/edge-runtime-configurable-guards.test.ts`:
Rspack does not expose the webpack parser hooks used by
`MiddlewarePlugin`. The current Rspack path falls back to SWC analysis
in `finishModules`, which can report diagnostics but cannot apply the
parser-time transforms that wrap `eval` / `new Function`, track
`InnerGraph` usage for used vs unused dynamic code, or apply
`unstable_allowDynamic` with webpack parity. Dev therefore misses the
expected dynamic-code runtime warnings and also reports false
`process.cwd` Edge warnings from Next internals; prod fails
allowed/unused dynamic-code cases.
-
`test/development/middleware-overrides-node.js-api/middleware-overrides-node.js-api.test.ts`:
same parser-hook limitation. Webpack can observe that `process.cwd` is
overwritten before use, while the Rspack SWC fallback statically flags
`process.cwd` as an unsupported Edge Node API.
- `test/production/css-features/css-compilation.test.ts`: the CSS is
minified and prefixed as expected, but the Rspack lightningcss path
currently does not expose/control source map generation the way this
test expects, so emitted CSS has no `sourceMappingURL` comment or `.map`
file to assert.
- `test/e2e/app-dir/server-source-maps/server-source-maps.test.ts`:
invalid source maps are not handled with the same graceful diagnostic as
webpack/Node source-map handling. Rspack logs the raw `webpack-internal`
frame for the damaged map case instead of surfacing the expected
`Invalid source map. Only conformant source maps...` message with the
cause.
-
`test/e2e/app-dir/parallel-routes-revalidation/parallel-routes-revalidation.test.ts`:
raw CI output observed a dev-mode timeout waiting for `networkidle`
after refresh/back/forward lazy fetching. This was not the final
structured failure in the latest run, but it remains a Rspack dev parity
follow-up around router cache lazy fetches and network settling.
- `test/e2e/middleware-src/middleware-src.test.ts`: after the test adds
root middleware files, Rspack dev still lets `src/middleware`
participate; the expected behavior is that only the root middleware
runs.
- `test/e2e/env-config/env-config.test.ts`: changing `.env` logs `Reload
env:` but the client keeps the previous `NEXT_PUBLIC_` value, pointing
at an Rspack dev env invalidation/HMR gap.
-
`test/e2e/app-dir/use-cache-without-experimental-flag/use-cache-without-experimental-flag.test.ts`:
after enabling the `useCache` flag, the dev server does not finish
restarting, pointing at build-error recovery/restart parity.
-
`test/development/app-dir/server-navigation-error/server-navigation-error.test.ts`:
middleware navigation-error cases hit `ERR_CONNECTION_REFUSED`,
consistent with the Rspack dev server exiting or restarting unexpectedly
during those error flows.
- `test/e2e/opentelemetry/instrumentation/opentelemetry.test.ts`: the
custom-server dev process exits before the SDK handle is initialized,
then cleanup fails on `shutdown`; this needs follow-up in Rspack
dev/custom-server startup.
- `test/e2e/next-image-new/app-dir/app-dir.test.ts`: after toggling
image source, `onLoadingComplete` still reports the previous image
dimensions/source, pointing at an Rspack dev image/HMR or asset
invalidation parity issue.
- `test/e2e/node-cli-args/node-cli-args.test.ts`: on Node `20.19.x`,
`node --experimental-network-inspection` resolves instead of rejecting.
This looks like a Node-version behavior change rather than an Rspack
compiler issue.

Not attributed to this Rspack upgrade:
-
`test/e2e/app-dir/instant-navigation-testing-api/instant-navigation-testing-api.test.ts`
was marked by `scripts/pr-status.js` as a known flaky test across
branches.
-
`test/production/app-dir/build-output-prerender/build-output-prerender.test.ts`
ran in the webpack prod job and only differs by prerender error ordering
in the inline snapshot.


<!-- NEXT_JS_LLM_PR -->

---------

Co-authored-by: Benjamin Woodruff <benjamin.woodruff@vercel.com>
2026-06-15 23:19:53 +00:00
Sebastian "Sebbie" Silbermann 069345bf55 [ci] Allow "rerun failed jobs" to work up until 5 days for e2e deploy tests (#94812) 2026-06-15 10:56:57 +00:00
Sebastian "Sebbie" Silbermann 902a7c3e5d [ci] Always upload canary tarballs from the canary branch (#94557) 2026-06-12 10:06:41 +02:00
Benjamin Woodruff b8d268d0da [ci] Download fnm directly from GitHub releases and validate checksum (#94579)
I determined that [`nvm` wasn't sufficient for our use-case since we
need to support
windows](https://github.com/vercel/next.js/pull/94175#issuecomment-4654622674),
so this doubles down on `fnm`.

This reduces risks of supply chain attacks with `fnm`.

This also cleans up some old stuff that was left over from self-hosted
runners and/or that was there for debugging, if it isn't useful anymore.
2026-06-10 14:23:29 -07:00
Benjamin Woodruff 3caee03f2a [ci] Reduce usage of turborepo cache in build_and_deploy.yml (#94319)
We're consolidating on `actions/cache` now that we got rid of
self-hosted runners. This doesn't remove all of the uses of turborepo's
cache (notably sccache), but this does eliminate the remote turborepo
cache for the native build cache and the docker image.

These build steps use docker so that we're building against an old
pinned glibc (2.31), and so that we can have access to both `aarch64`
and `x86_64` musl sysroots.

## Testing

**Local Build:** `node scripts/docker-native-build.js` still works (this
script just exists for being able to debug these builds locally)

**CI Build:**
- Run an automated-preview CI job, but cancel it before the native build
succeeds to test writing to the docker cache but not the native cache:
https://github.com/vercel/next.js/actions/runs/26986955366/job/79638633136?pr=94319
- Re-run the job with only the docker image cache, see that we get a
cache hit for the docker image:
https://github.com/vercel/next.js/actions/runs/26986955366/job/79639365126?pr=94319
- Re-run the job again and see that we hit the native build cache hit
and don't touch docker at all:
https://github.com/vercel/next.js/actions/runs/26986955366/job/79647324952?pr=94319
- Manually trigger the job to do a full preview build:
https://github.com/vercel/next.js/actions/runs/26989861549
2026-06-10 14:23:18 -07:00
Sebastian "Sebbie" Silbermann 9af81ed9a1 [cd] Ensure release can be triggered on old branches (#94596) 2026-06-09 10:25:17 -07:00
Benjamin Woodruff fc8edc4722 [ci] Remove dead playwright docker image creation logic (#94576)
We reverted the use of this docker image in
https://github.com/vercel/next.js/pull/94366

We're going to use GitHub actions custom runner images instead (which
don't use docker)
2026-06-09 10:15:47 -07:00