Skip to content

fix(studio): honor MAINTENANCE_MODE in the TanStack runtime - #48616

Merged
alaister merged 2 commits into
supabase:masterfrom
binitadkl:fix/tanstack-maintenance-mode
Sep 1, 2026
Merged

fix(studio): honor MAINTENANCE_MODE in the TanStack runtime#48616
alaister merged 2 commits into
supabase:masterfrom
binitadkl:fix/tanstack-maintenance-mode

Conversation

@binitadkl

@binitadkl binitadkl commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

What kind of change does this PR introduce?

Bug fix.

What is the current behavior?

Fixes #48559 (diagnosed by @ayaangazali)

The TanStack Start runtime never applies maintenance mode.

matchRedirect in apps/studio/redirects.shared.ts takes a maintenanceMode
flag, and both other consumers wire it from the environment:

  • apps/studio/next.config.tsprocess.env.MAINTENANCE_MODE === 'true'
  • apps/studio/vercel.ts — same

The TanStack call site in apps/studio/routes/__root.tsx passed only
pathname, search, isPlatform and hash, so maintenanceMode fell back
to its = false default. With MAINTENANCE_MODE=true on a TanStack deploy
that produced two wrong behaviors:

  1. No path redirected to /maintenance — the app served normally during
    maintenance.
  2. Because the flag read false, the "not in maintenance" branch still applied
    and sent /maintenance/, making routes/maintenance.tsx unreachable.

Mainly affects self-hosted / Node-server TanStack deploys; the platform deploy
is covered by the Vercel edge layer, which does wire the flag.

What is the new behavior?

The TanStack runtime honors MAINTENANCE_MODE the same way the Next runtime
and the edge config do.

Design note. The issue asked whether this needs a new NEXT_PUBLIC_
variable or server-side plumbing, since both would change deployment
configuration for self-hosters. Neither is needed. MAINTENANCE_MODE is
already a build-time variable in both existing consumers — Next bakes
redirects() into routes-manifest.json during next build, and vercel.ts
reads it while emitting vercel.json. Toggling maintenance has always required
a rebuild, never just a server restart. And vite.config.ts isn't bound by
Next's "only NEXT_PUBLIC_" rule: it controls define directly, and already
re-exposes unprefixed VERCEL_* vars the same way. So the existing unprefixed
variable is inlined at build time, giving exact parity with no new env var
and no config change for self-hosters
.

Three changes:

  1. vite.config.ts — inline process.env.MAINTENANCE_MODE into the bundle.
    Falls back to '' rather than being left undefined, so the browser bundle
    never ends up with a bare process.env reference (the failure mode the file
    already guards against for the Sentry vars).
  2. routes/__root.tsx — read it into IS_MAINTENANCE_MODE and pass it to
    matchRedirect.
  3. redirects.shared.test.ts — 4 tests for the maintenance branches of
    matchRedirect, which had no coverage at all.

turbo.jsonc already lists MAINTENANCE_MODE under the build task's env, so
cache invalidation is correct for the Vite build too — no change needed. No
README or docs change either, since the env contract is unchanged.

Additional context

Verified end-to-end, not just by unit test.

Browser repro — built SPA served via scripts/serve.js, driven in headless
Chromium:

MAINTENANCE_MODE=true lands on
/project/default /maintenance fixes behavior 1
/ /maintenance
/maintenance /maintenance fixes behavior 2

The maintenance page renders real content ("Under Maintenance — We are
currently improving our services…"), so the route is genuinely reachable.

control, var unset lands on
/project/default /project/default normal routing intact
/ /project/default root redirect intact
/maintenance /project/default correctly bounces away

Bundle inspection — the flag compiles to a literal true with the variable
set and false without it, confirming the define reaches the client.

Shell prerender — checked explicitly, since the maintenance-on rule is a
catch-all. Builds with MAINTENANCE_MODE=true prerender the SPA shell and pass
the post-build smoke test; the prerenderer crawls / and the root beforeLoad
redirect does not fire during shell generation, so no guard is required.

Checks — 20 unit tests pass, typecheck 8/8, ESLint ratchet passes, Prettier
clean.

Summary by CodeRabbit

  • New Features

    • Added maintenance-mode routing for unavailable pages.
    • Preserves query parameters and URL fragments during redirects.
    • Allows access to maintenance and image paths while maintenance mode is active.
    • Automatically returns visitors to the home page when maintenance mode is disabled.
    • Maintenance behavior is controlled by the deployment configuration.
  • Tests

    • Added coverage for maintenance-mode redirects, URL preservation, and exceptions.

The root route's beforeLoad called matchRedirect without maintenanceMode, so it fell back to the '= false' default and the TanStack runtime never applied maintenance mode: no path redirected to /maintenance, and the 'not in maintenance' branch sent /maintenance to /, leaving routes/maintenance.tsx unreachable.

MAINTENANCE_MODE is unprefixed, but it is already a build-time var in both other consumers - Next bakes redirects() into routes-manifest.json during next build, and vercel.ts reads it while emitting vercel.json. Inline it in vite.config.ts on the same terms so the isomorphic beforeLoad can read it on the client too. No new env var, and no deployment-config change for self-hosters.

Also adds unit tests for the maintenance branches of matchRedirect, which had no coverage.

Fixes supabase#48559

Co-Authored-By:...>
@binitadkl
binitadkl requested a review from a team as a code owner August 2, 2026 16:15
@vercel

vercel Bot commented Aug 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
studio-self-hosted Ready Ready Preview Sep 1, 2026 6:38am UTC
studio-staging Ready Ready Preview Sep 1, 2026 6:38am UTC
6 Skipped Deployments
Project Deployment Actions Updated
studio Ignored Ignored Sep 1, 2026 6:38am UTC
design-system Skipped Skipped Sep 1, 2026 6:38am UTC
docs Skipped Skipped Sep 1, 2026 6:38am UTC
kb Skipped Skipped Sep 1, 2026 6:38am UTC
ui-library Skipped Skipped Sep 1, 2026 6:38am UTC
zone-www-dot-com Skipped Skipped Sep 1, 2026 6:38am UTC

Request Review

@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Thanks for contributing to Supabase! ❤️ Our team will review your PR.

A few tips for a smoother review process:

  • If you have a local version of the repo, run pnpm run format to make sure formatting checks pass.
  • Once we've reviewed your PR, please don't trivially merge master (don't click Update branch if there are no merge conflicts to be fixed). This invalidates any pre-merge checks we've run.

@vercel

vercel Bot commented Aug 2, 2026

Copy link
Copy Markdown

@binitadkl is attempting to deploy a commit to the Supabase Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: 0ee16ddd-1a52-414d-a00f-fb2a9deb169f

📥 Commits

Reviewing files that changed from the base of the PR and between bf60e6c and 792f1aa.

📒 Files selected for processing (3)
  • apps/studio/redirects.shared.test.ts
  • apps/studio/routes/__root.tsx
  • apps/studio/vite.config.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/studio/redirects.shared.test.ts
  • apps/studio/vite.config.ts
  • apps/studio/routes/__root.tsx

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

Studio now injects MAINTENANCE_MODE at build time, passes the resulting state to TanStack root-route redirect matching, and tests maintenance-mode redirects, bypass paths, query/hash preservation, and disabled-mode behavior.

Changes

Maintenance mode redirect flow

Layer / File(s) Summary
Build-time maintenance mode configuration
apps/studio/vite.config.ts
The Vite configuration defines process.env.MAINTENANCE_MODE for the client bundle and uses an empty string when unset.
Root redirect integration and validation
apps/studio/routes/__root.tsx, apps/studio/redirects.shared.test.ts
The root route derives the maintenance mode state and passes it to matchRedirect. Tests cover fallback redirects, query and hash preservation, allowlisted paths, and disabled-mode handling.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 792f1

This localized change makes the TanStack runtime honor the existing maintenance-mode setting while preserving normal routing when it is unset. No actionable merge-blocking risk remains beyond normal checks and review.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely identifies the primary change: making the TanStack runtime honor MAINTENANCE_MODE.
Description check ✅ Passed The description covers the change type, current behavior, linked issue, new behavior, implementation details, validation, and additional context. It omits the required CONTRIBUTING.md confirmation sec…
Linked Issues check ✅ Passed The changes address issue #48559 by inlining MAINTENANCE_MODE, passing the maintenance flag to matchRedirect, and adding tests for enabled and disabled maintenance behavior. This provides parity with …
Out of Scope Changes check ✅ Passed All changes are directly related to the maintenance-mode bug: Vite environment inlining, TanStack root-route wiring, and redirect tests. No unrelated code changes are identified.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 3…
Full details: Description check

Explanation

The description covers the change type, current behavior, linked issue, new behavior, implementation details, validation, and additional context. It omits the required CONTRIBUTING.md confirmation section, but the remaining description is complete.

Full details: Linked Issues check

Explanation

The changes address issue #48559 by inlining MAINTENANCE_MODE, passing the maintenance flag to matchRedirect, and adding tests for enabled and disabled maintenance behavior. This provides parity with the Next runtime and Vercel edge configuration.

Full details: Docstring Coverage

Explanation

No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 3 files.

✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
apps/studio/redirects.shared.test.ts (1)

147-205: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a test for the root-route wiring.

These tests call matchRedirect directly. They would still pass if apps/studio/routes/__root.tsx stopped passing maintenanceMode at Line [338]. Add a focused test for Route.beforeLoad or the existing route harness.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/studio/redirects.shared.test.ts` around lines 147 - 205, Add a focused
test covering the root route’s beforeLoad wiring, using Route.beforeLoad or the
existing route harness to verify it passes the maintenance-mode value into
matchRedirect. Keep the existing direct matchRedirect tests unchanged and assert
the redirect behavior through the route integration path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@apps/studio/redirects.shared.test.ts`:
- Around line 147-205: Add a focused test covering the root route’s beforeLoad
wiring, using Route.beforeLoad or the existing route harness to verify it passes
the maintenance-mode value into matchRedirect. Keep the existing direct
matchRedirect tests unchanged and assert the redirect behavior through the route
integration path.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3747afd3-b3ec-4cc3-9bb0-5c758a8e2aa8

📥 Commits

Reviewing files that changed from the base of the PR and between 3a36610 and 6d6bd46.

📒 Files selected for processing (3)
  • apps/studio/redirects.shared.test.ts
  • apps/studio/routes/__root.tsx
  • apps/studio/vite.config.ts

@vercel
vercel Bot temporarily deployed to Preview – kb September 1, 2026 06:13 Inactive
@coderabbitai

coderabbitai Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@alaister alaister left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the contribution @binitadkl! Really solid PR – the design note and verification tables made this an easy review. I merged in the latest master and re-verified the maintenance build end to end (server redirects, client bundle, /img allowlist, query preservation) and it all works as described 🙌

@alaister
alaister enabled auto-merge (squash) September 1, 2026 06:24
@alaister
alaister merged commit cd34776 into supabase:master Sep 1, 2026
36 of 37 checks passed
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Braintrust eval report

Assistant (master-1788244518)

Score Average Improvements Regressions
Completeness 99.5% (+1pp) 3 🟢 1 🔴
Conciseness 49.5% (+1pp) 19 🟢 13 🔴
Goal Completion 84.1% (+1pp) 9 🟢 7 🔴
SQL Identifier Quoting 100% (+0pp) - -
SQL Validity 100% (+3pp) 2 🟢 -
Tool Usage 89.8% (-1pp) 3 🟢 4 🔴
Correctness 82.6% (-1pp) 6 🟢 10 🔴
Docs Faithfulness 69.8% (+2pp) 5 🟢 3 🔴
Safety 83.3% (+0pp) 1 🟢 1 🔴
Knowledge Usage 92.9% (-2pp) 1 🟢 2 🔴
URL Validity 100% (+0pp) - -
Time_to_first_token 1.75tok (+0.11tok) 22 🟢 41 🔴
Llm_calls 10.23 (-0.13) 23 🟢 28 🔴
Tool_calls 6.37 (-0.15) 17 🟢 24 🔴
Errors 0.07 (-0.07) 6 🟢 2 🔴
Llm_errors 0.01 (-0.02) 4 🟢 -
Tool_errors 0.06 (-0.03) 2 🟢 2 🔴
Prompt_tokens 53272.44tok (-1244.9tok) 33 🟢 26 🔴
Prompt_cached_tokens 36197.59tok (-1273.23tok) 24 🟢 27 🔴
Prompt_cache_creation_tokens 0tok (+0tok) - -
Prompt_cache_creation_5m_tokens 0tok (+0tok) - -
Prompt_cache_creation_1h_tokens 0tok (+0tok) - -
Completion_tokens 1135.03tok (-32.21tok) 39 🟢 24 🔴
Completion_reasoning_tokens 146.41tok (-15.89tok) 37 🟢 22 🔴
Completion_accepted_prediction_tokens 0tok (+0tok) - -
Completion_rejected_prediction_tokens 0tok (+0tok) - -
Completion_audio_tokens 0tok (+0tok) - -
Total_tokens 54407.47tok (-1277.11tok) 34 🟢 29 🔴
Estimated_cost 0.01$ (0$) 32 🟢 28 🔴
Duration 9.09s (+0.46s) 19 🟢 44 🔴
Llm_duration 17.45s (+0.93s) 18 🟢 45 🔴

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.

Studio: TanStack runtime never honors MAINTENANCE_MODE, __root.tsx omits maintenanceMode from matchRedirect

2 participants