Skip to content

Commit 741b6a1

Browse files
committed
Stabilize unstable_instant
This API has experimental modes for build validation but the dev validation is going to be stable in the next release.
1 parent d3d619c commit 741b6a1

406 files changed

Lines changed: 1072 additions & 1091 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/skills/insight-error-page/SKILL.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,17 +132,17 @@ kind: insight
132132
- `use cache` directive (not `"use cache"` in prose)
133133
- Cache Components (capitalized)
134134
- static shell (link to `/docs/app/glossary#static-shell`)
135-
- `unstable_instant` (not `instant`)
135+
- `instant` (not `instant`)
136136
- `cacheLife` / `cacheTag` / `revalidateTag` / `updateTag` — use published names exactly
137137
- `connection()` from `next/server`
138138
- Client Component / Server Component (capitalized)
139139
- [prerendering](/docs/app/glossary#prerendering) — always linked on first use
140140

141141
### Allow blocking route section (canonical pattern)
142142

143-
When the framework card set includes `unstable_instant = false` (group `block`), use the canonical `## Allow blocking route` section shape. All pages with this fix must match. Cross-page consistency matters — diverging from this shape produces a page that reads like an outlier.
143+
When the framework card set includes `instant = false` (group `block`), use the canonical `## Allow blocking route` section shape. All pages with this fix must match. Cross-page consistency matters — diverging from this shape produces a page that reads like an outlier.
144144

145-
**Intro**: One paragraph explaining what setting `unstable_instant` to `false` does and what the trade-off is. Optional second paragraph noting when this is _rarely_ the right answer (for example, on client-hook or cache fixes where a Suspense boundary is almost always feasible). Phrase the rarity directly. Do not write `Confirm with the user` in body prose — that phrasing belongs in `prompt={...}` agent strings, not in the page the user reads.
145+
**Intro**: One paragraph explaining what setting `instant` to `false` does and what the trade-off is. Optional second paragraph noting when this is _rarely_ the right answer (for example, on client-hook or cache fixes where a Suspense boundary is almost always feasible). Phrase the rarity directly. Do not write `Confirm with the user` in body prose — that phrasing belongs in `prompt={...}` agent strings, not in the page the user reads.
146146

147147
**Patterns**: For page-body errors (runtime data, uncached data, client hooks), use both `#### Opt the page out` and `#### Opt the layout out`. For viewport errors, use only `#### Opt the layout out` (viewport always lives on a layout). Each pattern has:
148148

@@ -171,8 +171,8 @@ Every insight page ends (just before `## Useful links`) with the canonical opt-o
171171

172172
Instant-navigation validation runs by default in [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents) apps and is what surfaces this error.
173173

174-
- **One segment**: add [`export const unstable_instant = false`](/docs/app/api-reference/file-conventions/route-segment-config/instant) to the page or layout file. The segment is exempted from validation.
175-
- **Entire app**: set [`experimental.instantInsights.validationLevel`](/docs/app/api-reference/file-conventions/route-segment-config/instant#configuring-validation-defaults) to `'manual-warning'` in `next.config`. Validation runs only on segments that explicitly export `unstable_instant`.
174+
- **One segment**: add [`export const instant = false`](/docs/app/api-reference/file-conventions/route-segment-config/instant) to the page or layout file. The segment is exempted from validation.
175+
- **Entire app**: set [`experimental.instantInsights.validationLevel`](/docs/app/api-reference/file-conventions/route-segment-config/instant#configuring-validation-defaults) to `'manual-warning'` in `next.config`. Validation runs only on segments that explicitly export `instant`.
176176

177177
See [Ensuring instant navigations](/docs/app/guides/instant-navigation) for the full model.
178178
```

crates/next-core/src/segment_config.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ pub struct NextSegmentConfig {
119119
pub generate_static_params: Option<Span>,
120120
#[turbo_tasks(trace_ignore)]
121121
#[bincode(with_serde)]
122-
pub unstable_instant: Option<Span>,
122+
pub instant: Option<Span>,
123123
#[turbo_tasks(trace_ignore)]
124124
#[bincode(with_serde)]
125125
pub prefetch: Option<Span>,
@@ -534,15 +534,15 @@ pub async fn parse_segment_config_from_source(
534534
.await?;
535535
}
536536

537-
if let Some(span) = config.unstable_instant {
537+
if let Some(span) = config.instant {
538538
invalid_config(
539539
source,
540-
"unstable_instant",
540+
"instant",
541541
span,
542542
rcstr!(
543-
"\"unstable_instant\" is a route segment config and can only be used when the \
544-
segment is a Server Component module. Remove the \"use client\" directive to \
545-
use this API."
543+
"\"instant\" is a route segment config and can only be used when the segment \
544+
is a Server Component module. Remove the \"use client\" directive to use \
545+
this API."
546546
),
547547
None,
548548
IssueSeverity::Error,
@@ -984,8 +984,8 @@ async fn parse_config_value(
984984
"generateStaticParams" => {
985985
config.generate_static_params = Some(span);
986986
}
987-
"unstable_instant" => {
988-
config.unstable_instant = Some(span);
987+
"instant" => {
988+
config.instant = Some(span);
989989
}
990990
"prefetch" => {
991991
config.prefetch = Some(span);

crates/next-custom-transforms/src/transforms/debug_instant_stack.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,21 +53,21 @@ struct DebugInstantStackPass {
5353
}
5454

5555
/// Given an export specifier, returns `Some((exported_name, local_name))` if
56-
/// the exported name is `unstable_instant`.
56+
/// the exported name is `instant`.
5757
fn get_instant_specifier_names(specifier: &ExportSpecifier) -> Option<(&Ident, &Ident)> {
5858
match specifier {
59-
// `export { orig as unstable_instant }`
59+
// `export { orig as instant }`
6060
ExportSpecifier::Named(ExportNamedSpecifier {
6161
exported: Some(ModuleExportName::Ident(exported)),
6262
orig: ModuleExportName::Ident(orig),
6363
..
64-
}) if exported.sym == "unstable_instant" => Some((exported, orig)),
65-
// `export { unstable_instant }`
64+
}) if exported.sym == "instant" => Some((exported, orig)),
65+
// `export { instant }`
6666
ExportSpecifier::Named(ExportNamedSpecifier {
6767
exported: None,
6868
orig: ModuleExportName::Ident(orig),
6969
..
70-
}) if orig.sym == "unstable_instant" => Some((orig, orig)),
70+
}) if orig.sym == "instant" => Some((orig, orig)),
7171
_ => None,
7272
}
7373
}
@@ -106,26 +106,26 @@ impl VisitMut for DebugInstantStackPass {
106106

107107
for item in items.iter() {
108108
match item {
109-
// `export const unstable_instant = ...`
109+
// `export const instant = ...`
110110
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(export_decl)) => {
111111
if let Decl::Var(var_decl) = &export_decl.decl {
112112
for decl in &var_decl.decls {
113113
if let Pat::Ident(ident) = &decl.name
114-
&& ident.id.sym == "unstable_instant"
114+
&& ident.id.sym == "instant"
115115
&& let Some(init) = &decl.init
116116
{
117117
self.instant_export_span = Some(init.span());
118118
}
119119
}
120120
}
121121
}
122-
// `export { unstable_instant }` or `export { x as unstable_instant }`
122+
// `export { instant }` or `export { x as instant }`
123123
// with or without `from '...'`
124124
ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(named)) => {
125125
for specifier in &named.specifiers {
126126
if let Some((_exported, orig)) = get_instant_specifier_names(specifier) {
127127
if named.src.is_some() {
128-
// Re-export: `export { unstable_instant } from './config'`
128+
// Re-export: `export { instant } from './config'`
129129
// Point at the export specifier itself
130130
self.instant_export_span = Some(specifier.span());
131131
} else {
@@ -156,7 +156,7 @@ impl VisitMut for DebugInstantStackPass {
156156
}
157157

158158
let mut cons = quote!(
159-
"function unstable_instant() {
159+
"function instant() {
160160
const error = $new_error
161161
error.name = 'Instant Validation'
162162
return error
@@ -165,7 +165,7 @@ impl VisitMut for DebugInstantStackPass {
165165
);
166166

167167
// Patch source_span onto the Function
168-
// for sourcemap mapping back to the unstable_instant config value
168+
// for sourcemap mapping back to the instant config value
169169
if let Expr::Fn(f) = &mut cons {
170170
f.function.span = source_span;
171171
}

crates/next-custom-transforms/src/transforms/react_server_components.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -956,7 +956,7 @@ impl ReactServerComponentValidator {
956956
),
957957
);
958958
}
959-
"unstable_instant" if !self.cache_components_enabled => {
959+
"instant" if !self.cache_components_enabled => {
960960
possibly_invalid_exports.insert(
961961
export_name.clone(),
962962
(

crates/next-custom-transforms/tests/errors/react-server-components/server-graph/cache-components/instant-with-cache-components/output.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export const unstable_instant = {
1+
export const instant = {
22
prefetch: 'static'
33
};
44
export default function Page() {

crates/next-custom-transforms/tests/errors/react-server-components/server-graph/cache-components/instant-with-cache-components/page.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export const unstable_instant = { prefetch: 'static' }
1+
export const instant = { prefetch: 'static' }
22

33
export default function Page() {
44
return <div>Hello</div>

crates/next-custom-transforms/tests/errors/react-server-components/server-graph/instant-requires-cache-components/output.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export const unstable_instant = {
1+
export const instant = {
22
prefetch: 'static'
33
};
44
export default function Page() {
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
x Route segment config "unstable_instant" requires `nextConfig.cacheComponents` to be enabled.
1+
x Route segment config "instant" requires `nextConfig.cacheComponents` to be enabled.
22
,-[input.js:1:1]
3-
1 | export const unstable_instant = { prefetch: 'static' }
4-
: ^^^^^^^^^^^^^^^^
3+
1 | export const instant = { prefetch: 'static' }
4+
: ^^^^^^^
55
`----

crates/next-custom-transforms/tests/errors/react-server-components/server-graph/instant-requires-cache-components/page.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export const unstable_instant = { prefetch: 'static' }
1+
export const instant = { prefetch: 'static' }
22

33
export default function Page() {
44
return <div>Hello</div>

crates/next-custom-transforms/tests/fixture/debug-instant-stack/with-aliased-export/input.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
const instant = { prefetch: 'static' }
2-
export { instant as unstable_instant }
1+
const instantConfig = { prefetch: 'static' }
2+
export { instantConfig as instant }
33

44
export default function Page() {
55
return <div>Hello</div>

0 commit comments

Comments
 (0)