Build1 distinct publisher3 min readUpdated
Request-scoped values became promises, but pages that read them synchronously still render. A warning that does not break the build is a warning that ships.
The Engineer · Build desk
Compiled by The EngineerSomething wrong?How this is made
Next.js 15 made a set of request-scoped values asynchronous, and code that still reads them synchronously frequently renders anyway while the terminal repeats a complaint [4][3]. Output that looks correct plus a log line is the least actionable signal a framework can send, and that is exactly why this migration is being postponed rather than done.
The message is specific. It names the route and the property: `Route "/blog/[slug]" used params.slug. params should be awaited before using its properties` [1]. The same class of warning turns up for `searchParams`, and for `cookies()` and `headers()` [2]. According to a dev.to walkthrough of the error, five request-dependent APIs are asynchronous in Next.js 15 and later: `params`, `searchParams`, `cookies()`, `headers()` and `draftMode()` [12][4]. That is five distinct call sites to audit, not one [5]. What they share is that their values change per request: which route was opened, what query string came with it, which cookies and headers arrived, whether draft mode is on [10].
The repair is small, which is part of the problem. Two edits: make the component `async`, then await the whole object before reading off it, as in `const { slug } = await params` [6]. The near miss that looks like a fix is `const slug = await params.slug`, which still reaches for `.slug` before `params` has resolved [7]. And a component cannot await anything until it is declared `async`; JavaScript rejects the rest [8].
Two things make this spread further than a single page file. First, the supply of examples: code written for Next.js 13 or 14 can start emitting warnings or errors immediately after an upgrade [9], so anyone following an older App Router tutorial reproduces the broken shape on a current framework. Second, the walkthrough notes that this shows up often on blog-style sites because the page component is not the only place a route reads `params` [11]. One route can hold several reads, and the compiler will not enumerate them for you.
Treat the current behaviour for what it is: a compatibility shim that renders your synchronous access and files a note. Nothing in that arrangement forces a decision. The build passes, the page paints, the warning scrolls past in a dev server nobody is reading, and the diff that would have cost ten minutes per route becomes a latent failure spread across every dynamic segment, metadata function and cookie read in the app. The terminal is the only inventory the framework hands over, and it is an inventory that disappears when you clear the console.
What to watch is the gap between warning and enforcement. The walkthrough does not state a version at which the message stops being a warning [13], which means the deadline is unknown rather than absent. The practical measure of exposure is not how many routes use dynamic segments but how many separate places each route reads request data [11]; that count is the size of the migration, and it only grows while the framework keeps being polite about it.
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
The Next.js error text reads: Route "/blog/[slug]" used params.slug. params should be awaited before using its properties.
The same warning sometimes appears with searchParams, and sometimes with cookies() or headers().
Sometimes the page still seems to work while the terminal keeps emitting the warning.
In Next.js 15+, the Dynamic APIs params, searchParams, cookies(), headers() and draftMode() are asynchronous and should be awaited before their properties are read.
The fix is to make the page component async and destructure after awaiting, for example: export default async function BlogPostPage({ params }) { const { slug } = await params; }
Writing const slug = await params.slug is not the correct fix, because it still accesses .slug before params is awaited; the whole params object must be awaited first.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Single beginner tutorial, verifiable code but no primary docs
Everything rests on one self-published dev.to walkthrough. Its technical content is internally consistent and independently checkable by running the snippets -- the error string, the five Dynamic APIs, the async component plus awaited destructure, and the generateMetadata second read site are all concretely specified. But there is no official Next.js documentation, release note, changelog, or second publisher in the cluster to corroborate the framework behaviour or the migration guidance.
No adoption signal in supplied sources
The cluster contains no release, deployment, benchmark, usage disclosure, or incident data. Nothing indicates how many projects hit the warning, how many have migrated, or how widely Next.js 15+ is deployed. The tutorial's remark that developers upgrading from 13/14 encounter this is anecdotal framing, not a measurable adoption observation, so no value is assigned.
Fix is stated conservatively; the urgency framing outruns the evidence
The technical claims are modest and match their demonstration: the source shows the failing pattern, the fix, and the common near-miss, and it explicitly concedes the page often still works. The mild overstatement lies in the surrounding urgency -- the implication that deferred fixes are shipping toward a cliff -- because no source names a version where the warning becomes a hard failure and there is no adoption data on how widespread the unfixed pattern is. Small positive rather than large, since nothing in the source is exaggerated on its own terms.
Low-stakes developer self-publishing; audience-building incentive only
The single source is an individually authored beginner tutorial on a developer publishing platform. The visible incentive is reach and reputation from ranking on a common error message, which encourages restating a well-trodden fix rather than distorting it; no vendor sponsorship, product being sold, pricing, or commercial relationship is disclosed or evident in the supplied material.
Fix mechanics credible, surrounding significance unestablished
Confidence is moderate-low. The narrow how-to content is reproducible and likely correct, and the five named Dynamic APIs are stated unambiguously. But with one publisher, no primary framework documentation, no deprecation timeline, and zero adoption evidence, the broader thesis about deferred migrations shipping widely cannot be verified from this cluster.
build
The third answer: a dead-code tool allowed to say "not traced yet"1 distinct publisher
build
Allow-list the closed set, block-list the open one: 193 thin geo pages, one gate1 distinct publisher
build
Pin `formats` before you take the next/image v4 bump1 distinct publisher
build
A 20-digit ID went into a JSON repair tool and a different number came out1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 19, 2026