Skip to content

fix(nextjs): match standalone server copy patterns to build output la…#2887

Merged
acozzette merged 1 commit into
aspect-build:mainfrom
imanmalekian31:fix/nextjs-standalone-server-app-dir-prefix
Jun 15, 2026
Merged

fix(nextjs): match standalone server copy patterns to build output la…#2887
acozzette merged 1 commit into
aspect-build:mainfrom
imanmalekian31:fix/nextjs-standalone-server-app-dir-prefix

Conversation

@imanmalekian31

@imanmalekian31 imanmalekian31 commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Fix nextjs_standalone_server producing a js_binary that fails at runtime because server.js is never copied into the assembled standalone directory.

Symptom

An OCI image (or bazel run) built from nextjs_standalone_build + nextjs_standalone_server fails to start:

FATAL: aspect_rules_js[js_binary]: the entry_point
'.../next_server.runfiles/_main/<pkg>/next_server/standalone/<pkg>/server.js' not found

The build succeeds — the failure only appears at runtime, because the server's js_binary entry point points at a server.js that was never assembled into the standalone output.

Root cause

nextjs_standalone_server's internal copy_to_directory uses include_srcs_patterns / replace_prefixes prefixed with .next/:

include_srcs_patterns = [
    "public/**",
    "{}/static/**".format(_next_build_out),     # ".next/static/**"
    "{}/standalone/**".format(_next_build_out),  # ".next/standalone/**"
],

But the app tree (the nextjs_standalone_build output) does not expose its files under a .next/ prefix. nextjs_standalone_build runs next build (which writes to .next) and then copies that tree into a directory named after the build target via _copy_exec_to_bin — it cannot reuse .next, since that path is already owned by the build action. So a build target :foo yields paths like foo/standalone/... and foo/static/....

Since copy_to_directory matches paths relative to the package (default root_paths = ["."]), the .next/-prefixed patterns match nothing — only public/** is copied. server.js and .next/static never make it into the standalone directory, and the binary dies at runtime.

Empirically confirmed (build target named next, package displayads/panel/frontend):

  • .next/standalone/** → matches nothing
  • standalone/** → matches nothing
  • next/standalone/** → matches (the prefix is the build target's directory name)

This is a regression from #2879, which flattened the .next wrapper in nextjs_standalone_build's output layout without updating nextjs_standalone_server's patterns to match.

Fix

Derive the prefix from the app label (app.split(":")[-1].split("/")[-1]) and use it in include_srcs_patterns / replace_prefixes instead of the hardcoded .next, matching the actual flattened layout. This mirrors the existing label-parsing the macro already does for the config basename, and is independent of the Next.js version.

Reproduction

  1. nextjs_standalone_build(name = "next", ...) then nextjs_standalone_server(name = "next_server", app = ":next").
  2. bazel build //path:_next_server.standalone.
  3. Inspect the output: only public/ is present; no server.js, no .next/static.
  4. Running the resulting js_binaryentry_point ... server.js not found.

Changes are visible to end-users: yes

  • Searched for relevant documentation and updated as needed: no
  • Breaking change (forces users to change their own code or config): no
  • Suggested release notes appear below: yes

nextjs_standalone_server: fix the assembled standalone directory missing server.js and .next/static, which caused the server js_binary to fail at runtime with "entry_point ... server.js not found". Regression from #2879.

Test plan

  • Manual testing; to reproduce:
    1. nextjs_standalone_build(name = "next", ...) + nextjs_standalone_server(name = "next_server", app = ":next").
    2. bazel build //path:_next_server.standalone and inspect the output — standalone/<pkg>/server.js and standalone/<pkg>/.next/static are now present.
    3. bazel run //path:next_server starts successfully instead of failing with the missing-entry-point error.

@CLAassistant

CLAassistant commented Jun 12, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 534e9fa080

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread contrib/nextjs/defs.bzl Outdated
@imanmalekian31 imanmalekian31 force-pushed the fix/nextjs-standalone-server-app-dir-prefix branch from 534e9fa to e3da294 Compare June 12, 2026 06:02
@jbedard jbedard requested a review from acozzette June 12, 2026 06:03
@acozzette

Copy link
Copy Markdown
Contributor

@imanmalekian31 Thank you for this fix and the detailed description! Would you be ok with signing the CLA?

@imanmalekian31

Copy link
Copy Markdown
Contributor Author

@acozzette Thanks, I've signed it.

@acozzette acozzette merged commit 35d2106 into aspect-build:main Jun 15, 2026
154 checks passed
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.

3 participants