mirror of
https://github.com/hanzoai/next.js.git
synced 2026-09-24 17:00:51 +00:00
docs: native db drivers with sync queries (#92572)
Closes: https://github.com/vercel/next.js/issues/86379 A native db driver, or sync db driver, won't be detected as external data, rather, as sync I/O. Main motivation is that better-sqlit3 is popular, and Node.js has introduced a native sql driver module. Given no other uncached data, or runtime data access, these queries would be included in the static shell. Wrapping with Suspense is not sufficient.
This commit is contained in:
@@ -126,9 +126,11 @@ export default function Page() {
|
||||
|
||||
The fallback (`<p>Loading posts...</p>`) is included in the static shell, while the component's content streams in at request time.
|
||||
|
||||
`<Suspense>` provides a fallback UI while async work completes, but it does not itself opt a component into dynamic rendering. If a component only performs synchronous work, it will complete during prerendering regardless of whether it is wrapped in `<Suspense>`.
|
||||
|
||||
## Working with runtime APIs
|
||||
|
||||
Request-time APIs require information that is only available when a user makes a request. These include:
|
||||
Runtime APIs require information that is only available when a user makes a request. These include:
|
||||
|
||||
- [`cookies`](/docs/app/api-reference/functions/cookies) - User's cookie data
|
||||
- [`headers`](/docs/app/api-reference/functions/headers) - Request headers
|
||||
@@ -254,6 +256,8 @@ export default async function Page() {
|
||||
}
|
||||
```
|
||||
|
||||
> **Good to know:** This includes queries to embedded databases with synchronous APIs, such as `better-sqlite3` or Node.js's built-in [`node:sqlite`](https://nodejs.org/api/sqlite.html). If you need per-request data from a synchronous source, call [`connection()`](/docs/app/api-reference/functions/connection) before the query.
|
||||
|
||||
## How rendering works
|
||||
|
||||
At build time, Next.js renders your route's component tree. How each component is handled depends on the APIs it uses:
|
||||
|
||||
@@ -5,14 +5,14 @@ description: API Reference for the connection function.
|
||||
|
||||
The `connection()` function allows you to indicate rendering should wait for an incoming user request before continuing.
|
||||
|
||||
It's useful when a component doesn't use [Request-time APIs](/docs/app/glossary#request-time-apis), but you want it to be rendered at runtime and not prerendered at build time. This usually occurs when you access external information that you intentionally want to change the result of a render, such as `Math.random()` or `new Date()`.
|
||||
It's useful when a component doesn't use [Request-time APIs](/docs/app/glossary#request-time-apis) like `cookies` or `headers`, but still needs to produce different output per request, such as `Math.random()` or `new Date()`.
|
||||
|
||||
```ts filename="app/page.tsx" switcher
|
||||
import { connection } from 'next/server'
|
||||
|
||||
export default async function Page() {
|
||||
await connection()
|
||||
// Everything below will be excluded from prerendering
|
||||
await connection() // prerendering stops here
|
||||
// the following code only runs at request time
|
||||
const rand = Math.random()
|
||||
return <span>{rand}</span>
|
||||
}
|
||||
@@ -22,13 +22,45 @@ export default async function Page() {
|
||||
import { connection } from 'next/server'
|
||||
|
||||
export default async function Page() {
|
||||
await connection()
|
||||
// Everything below will be excluded from prerendering
|
||||
await connection() // prerendering stops here
|
||||
// the following code only runs at request time
|
||||
const rand = Math.random()
|
||||
return <span>{rand}</span>
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Synchronous database drivers
|
||||
|
||||
Queries from synchronous database drivers like `better-sqlite3` complete during prerendering. If you are not already using Request-time APIs, call `connection()` before your query to exclude them from prerendering:
|
||||
|
||||
```ts filename="app/lib/data.ts" switcher
|
||||
import { connection } from 'next/server'
|
||||
import Database from 'better-sqlite3'
|
||||
|
||||
const db = new Database('app.db')
|
||||
|
||||
export async function getVisitorCount() {
|
||||
await connection()
|
||||
return db.prepare('SELECT value FROM counters WHERE name = ?').get('visitors')
|
||||
}
|
||||
```
|
||||
|
||||
```js filename="app/lib/data.js" switcher
|
||||
import { connection } from 'next/server'
|
||||
import Database from 'better-sqlite3'
|
||||
|
||||
const db = new Database('app.db')
|
||||
|
||||
export async function getVisitorCount() {
|
||||
await connection()
|
||||
return db.prepare('SELECT value FROM counters WHERE name = ?').get('visitors')
|
||||
}
|
||||
```
|
||||
|
||||
Now any component that calls `getVisitorCount()` will be excluded from prerendering, along with the rest of its output.
|
||||
|
||||
## Reference
|
||||
|
||||
### Type
|
||||
|
||||
Reference in New Issue
Block a user