You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
<UButtonv-for="button of item.buttons":key="button.to"v-bind="button"color="gray"size="xs"variant="link"trailing-icon="i-lucide-arrow-up-right"target="_blank" />
Copy file name to clipboardexpand all lines: docs/content/1.docs/2.features/ai.md
+4
Original file line number
Diff line number
Diff line change
@@ -226,3 +226,7 @@ Learn more about the [`useChat()` Vue composable](https://sdk.vercel.ai/docs/ref
226
226
::callout
227
227
Check out our [`pages/ai.vue` full example](https://github.com/nuxt-hub/core/blob/main/playground/app/pages/ai.vue) with Nuxt UI & [Nuxt MDC](https://github.com/nuxt-modules/mdc).
Copy file name to clipboardexpand all lines: docs/content/1.docs/2.features/cache.md
+57-3
Original file line number
Diff line number
Diff line change
@@ -4,6 +4,8 @@ navigation.title: Cache
4
4
description: Learn how to cache Nuxt pages, API routes and functions in with NuxtHub cache storage.
5
5
---
6
6
7
+
NuxtHub Cache is powered by [Nitro's cache storage](https://nitro.unjs.io/guide/cache#customize-cache-storage) and uses [Cloudflare Workers KV](https://developers.cloudflare.com/kv) as the cache storage. It allows you to cache API routes, server functions, and pages in your application.
8
+
7
9
## Getting Started
8
10
9
11
Enable the cache storage in your NuxtHub project by adding the `cache` property to the `hub` object in your `nuxt.config.ts` file.
@@ -81,6 +83,27 @@ It is important to note that the `event` argument should always be the first arg
81
83
[Read more about this in the Nitro docs](https://nitro.unjs.io/guide/cache#edge-workers).
82
84
::
83
85
86
+
## Routes Caching
87
+
88
+
You can enable route caching in your `nuxt.config.ts` file.
89
+
90
+
```ts [nuxt.config.ts]
91
+
exportdefaultdefineNuxtConfig({
92
+
routeRules: {
93
+
'/blog/**': {
94
+
cache: {
95
+
maxAge: 60*60,
96
+
// other options like name, group, swr...
97
+
}
98
+
}
99
+
}
100
+
})
101
+
```
102
+
103
+
::note
104
+
Read more about [Nuxt's route rules](https://nuxt.com/docs/guide/concepts/rendering#hybrid-rendering).
105
+
::
106
+
84
107
## Cache Invalidation
85
108
86
109
When using the `defineCachedFunction` or `defineCachedEventHandler` functions, the cache key is generated using the following pattern:
@@ -91,15 +114,15 @@ When using the `defineCachedFunction` or `defineCachedEventHandler` functions, t
91
114
92
115
The defaults are:
93
116
-`group`: `'nitro'`
94
-
-`name`: `'handlers'` for api routes and`'functions'` for server functions
117
+
-`name`: `'handlers'` for API routes, `'functions'` for server functions, or `'routes'` for route handlers
You can use the `group` and `name` options to invalidate multiple cache entries based on their prefixes.
144
+
145
+
```ts
146
+
// Gets all keys that start with nitro:handlers
147
+
awaituseStorage('cache').clear('nitro:handlers')
148
+
```
149
+
150
+
120
151
::note{to="https://nitro.unjs.io/guide/cache"}
121
152
Read more about Nitro Cache.
122
153
::
@@ -125,6 +156,29 @@ Read more about Nitro Cache.
125
156
126
157
As NuxtHub leverages Cloudflare Workers KV to store your cache entries, we leverage the [`expiration` property](https://developers.cloudflare.com/kv/api/write-key-value-pairs/#expiring-keys) of the KV binding to handle the cache expiration.
127
158
159
+
By default, `stale-while-revalidate` behavior is enabled. If an expired cache entry is requested, the stale value will be served while the cache is asynchronously refreshed. This also means that all cache entries will remain in your KV namespace until they are manually invalidated/deleted.
160
+
161
+
To disable this behavior, set `swr` to `false` when defining a cache rule. This will delete the cache entry once `maxAge` is reached.
162
+
163
+
```ts [nuxt.config.ts]
164
+
exportdefaultdefineNuxtConfig({
165
+
nitro: {
166
+
routeRules: {
167
+
'/blog/**': {
168
+
cache: {
169
+
maxAge: 60*60,
170
+
swr: false
171
+
// other options like name and group...
172
+
}
173
+
}
174
+
}
175
+
})
176
+
```
177
+
128
178
::note
129
179
If you set an expiration (`maxAge`) lower than `60` seconds, NuxtHub will set the KV entry expiration to `60` seconds in the future (Cloudflare KV limitation) so it can be removed automatically.
Copy file name to clipboardexpand all lines: docs/content/1.docs/2.features/database.md
+95-10
Original file line number
Diff line number
Diff line change
@@ -4,6 +4,8 @@ navigation.title: Database
4
4
description: Access a SQL database in your Nuxt application to store and retrieve relational data.
5
5
---
6
6
7
+
NuxtHub Database uses [Cloudflare D1](https://developers.cloudflare.com/d1/), a managed, serverless database built on SQLite to store and retrieve relational data.
8
+
7
9
## Getting Started
8
10
9
11
Enable the database in your NuxtHub project by adding the `database` property to the `hub` object in your `nuxt.config.ts` file.
@@ -24,6 +26,8 @@ This option will use Cloudflare platform proxy in development and automatically
24
26
Checkout our [Drizzle ORM recipe](/docs/recipes/drizzle) to get started with the database by providing a schema and migrations.
25
27
::
26
28
29
+
During local development, you can view and edit your database in the Nuxt DevTools. Once your project is deployed, you can inspect the database in the NuxtHub Admin Dashboard.
@@ -59,22 +63,35 @@ Best practice is to use prepared statements which are precompiled objects used b
59
63
60
64
### `bind()`
61
65
62
-
Binds parameters to a prepared statement.
66
+
Binds parameters to a prepared statement, allowing you to pass dynamic values to the query.
63
67
64
68
```ts
65
69
const stmt =db.prepare('SELECT * FROM users WHERE name = ?1')
66
70
67
71
stmt.bind('Evan You')
72
+
73
+
// SELECT * FROM users WHERE name = 'Evan You'
68
74
```
69
75
70
-
::note
71
-
The `?` character followed by a number (1-999) represents an ordered parameter. The number represents the position of the parameter when calling `.bind(...params)`.
72
-
::
76
+
The `?` character followed by a number (1-999) represents an ordered parameter. The number represents the position of the parameter when calling `.bind(...params)`.
73
77
74
78
```ts
75
79
const stmt =db
76
80
.prepare('SELECT * FROM users WHERE name = ?2 AND age = ?1')
77
81
.bind(3, 'Leo Chopin')
82
+
// SELECT * FROM users WHERE name = 'Leo Chopin' AND age = 3
83
+
```
84
+
85
+
If you instead use anonymous parameters (without a number), the values passed to `bind` will be assigned in order to the `?` placeholders in the query.
86
+
87
+
It's recommended to use ordered parameters to improve maintainable and ensure that removing or reordering parameters will not break your queries.
88
+
89
+
```ts
90
+
const stmt =db
91
+
.prepare('SELECT * FROM users WHERE name = ? AND age = ?')
92
+
.bind('Leo Chopin', 3)
93
+
94
+
// SELECT * FROM users WHERE name = 'Leo Chopin' AND age = 3
78
95
```
79
96
80
97
### `all()`
@@ -190,7 +207,9 @@ console.log(result)
190
207
191
208
### `batch()`
192
209
193
-
Sends multiple SQL statements inside a single call to the database. This can have a huge performance impact as it reduces latency from network round trips to the database. Each statement in the list will execute and commit, sequentially, non-concurrently and return the results in the same order.
210
+
Sends multiple SQL statements inside a single call to the database. This can have a huge performance impact by reducing latency caused by multiple network round trips to the database. Each statement in the list will execute/commit sequentially and non-concurrently before returning the results in the same order.
211
+
212
+
`batch` acts as a SQL transaction, meaning that if any statement fails, the entire transaction is aborted and rolled back.
194
213
195
214
```ts
196
215
const [info1, info2] =awaitdb.batch([
@@ -222,7 +241,7 @@ The object returned is the same as the [`.all()`](#all) method.
222
241
223
242
Executes one or more queries directly without prepared statements or parameters binding. The input can be one or multiple queries separated by \n.
224
243
225
-
If an error occurs, an exception is thrown with the query and error messages, execution stops and further statements are not executed.
244
+
If an error occurs, an exception is thrown with the query and error messages, execution stops, and further queries are not executed.
226
245
227
246
```ts
228
247
const result =awaithubDatabase().exec(`CREATE TABLE IF NOT EXISTS frameworks (id INTEGER PRIMARY KEY, name TEXT NOT NULL, year INTEGER NOT NULL DEFAULT 0)`)
@@ -236,9 +255,52 @@ console.log(result)
236
255
```
237
256
238
257
::callout
239
-
This method can have poorer performance (prepared statements can be reused in some cases) and, more importantly, is less safe. Only use this method for maintenance and one-shot tasks (for example, migration jobs). The input can be one or multiple queries separated by \n.
258
+
This method can have poorer performance (prepared statements can be reused in some cases) and, more importantly, is less safe. Only use this method for maintenance and one-shot tasks (for example, migration jobs).
259
+
::
260
+
261
+
## Working with JSON
262
+
263
+
Cloudflare D1 supports querying and parsing JSON data. This can improve performance by reducing the number of round trips to your database. Instead of querying a JSON column, extracting the data you need, and using that data to make another query, you can do all of this work in a single query by using JSON functions.
264
+
265
+
JSON columns are stored as `TEXT` columns in your database.
266
+
267
+
```ts
268
+
const framework = {
269
+
name: 'Nuxt',
270
+
year: 2016,
271
+
projects: [
272
+
'NuxtHub',
273
+
'Nuxt UI'
274
+
]
275
+
}
276
+
277
+
awaithubDatabase()
278
+
.prepare('INSERT INTO frameworks (info) VALUES (?1)')
279
+
.bind(JSON.stringify(framework))
280
+
.run()
281
+
```
282
+
283
+
Then, using D1's [JSON functions](https://developers.cloudflare.com/d1/sql-api/query-json/), which are built on the [SQLite JSON extension](https://www.sqlite.org/json1.html), you can make queries using the data in your JSON column.
284
+
285
+
```ts
286
+
const framework =awaitdb.prepare('SELECT * FROM frameworks WHERE (json_extract(info, "$.name") = "Nuxt")').first()
For an in-depth guide on querying JSON and a list of all supported functions, see [Cloudlare's Query JSON documentation](https://developers.cloudflare.com/d1/sql-api/query-json/#generated-columns).
240
298
::
241
299
300
+
## Using an ORM
301
+
302
+
Instead of using `hubDatabase()` to make interact with your database, you can use an ORM like [Drizzle ORM](/docs/recipes/drizzle). This can improve the developer experience by providing a type-safe API, migrations, and more.
303
+
242
304
## Database Migrations
243
305
244
306
Database migrations provide version control for your database schema. They track changes and ensure consistent schema evolution across all environments through incremental updates. NuxtHub supports SQL migration files (`.sql`).
Migration names must only contain alphanumeric characters and `-` (spaces are converted to `-`).
319
381
::
320
382
321
-
Migration files are created in `server/database/migrations/`.
383
+
Migration files are created in `server/database/migrations/` and are prefixed by an auto-incrementing sequence number. This migration number is used to determine the order in which migrations are run.
✔ Created ./server/database/migrations/0001_create-todos.sql
326
388
```
327
389
328
-
After creation, add your SQL queries to modify the database schema.
390
+
After creation, add your SQL queries to modify the database schema. For example, migrations should be used to create tables, add/delete/modify columns, and add/remove indexes.
With [Drizzle ORM](/docs/recipes/drizzle), migrations are automatically created when you run `npx drizzle-kit generate`.
@@ -417,7 +491,7 @@ These queries run after all migrations are applied but are not tracked in the `_
417
491
418
492
### Foreign Key Constraints
419
493
420
-
If you are using [Drizzle ORM](/docs/recipes/drizzle) to generate your database migrations, note that is uses `PRAGMA foreign_keys = ON | OFF;` in the generated migration files. This is not supported by Cloudflare D1 as they support instead[defer foreign key constraints](https://developers.cloudflare.com/d1/sql-api/foreign-keys/#defer-foreign-key-constraints).
494
+
If you are using [Drizzle ORM](/docs/recipes/drizzle) to generate your database migrations, your generated migration files will use `PRAGMA foreign_keys = ON | OFF;`. This is not supported by Cloudflare D1. Instead, they support [defer foreign key constraints](https://developers.cloudflare.com/d1/sql-api/foreign-keys/#defer-foreign-key-constraints).
421
495
422
496
You need to update your migration file to use `PRAGMA defer_foreign_keys = on|off;` instead:
423
497
@@ -430,3 +504,14 @@ ALTER TABLE ...
430
504
-PRAGMA foreign_keys = ON;
431
505
+PRAGMA defer_foreign_keys = off;
432
506
```
507
+
508
+
## Limits
509
+
510
+
- The maximum database size is 10 GB
511
+
- The maximum number of columns per table is 100
512
+
513
+
See all of the [D1 Limits](https://developers.cloudflare.com/d1/platform/limits/)
0 commit comments