@netlify/agent-runner-cli 1.114.0-netlifydb.2 → 1.114.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin-local.js +50 -53
- package/dist/bin.js +55 -58
- package/dist/index.js +49 -52
- package/dist/skills/general-database/SKILL.md +34 -15
- package/dist/skills/netlify-blobs/SKILL.md +34 -9
- package/package.json +2 -2
- package/dist/skills/general-database/SKILL@netlifydb.md +0 -45
- package/dist/skills/netlify-blobs/SKILL@netlifydb.md +0 -421
- /package/dist/skills/{netlify-database@netlifydb → netlify-database}/SKILL.md +0 -0
|
@@ -1,26 +1,45 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: general-database
|
|
3
|
-
description:
|
|
3
|
+
description: Use this skill whenever the task involves storing, persisting, querying, or managing data — including CRUD operations, collections, records, user data, or any application state that needs to survive between requests. Covers both relational databases (Netlify Database) and object storage (Netlify Blobs).
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Data Storage
|
|
6
|
+
# Data Storage on Netlify
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
Prefer Netlify Database over Netlify Blobs for any application data — records, collections, lists, user-generated content,
|
|
9
|
+
or anything you would store as rows. Use Blobs only for files, binary assets (images, video), or cached responses.
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Application data: Netlify Database
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
- JSON documents
|
|
16
|
-
- Session data
|
|
17
|
-
- Cache storage
|
|
13
|
+
**Netlify Database** is the recommended solution for storing application data. It provides a fully managed Postgres database
|
|
14
|
+
with zero configuration — install the `@netlify/database` package, and a database is automatically provisioned for your site.
|
|
18
15
|
|
|
19
|
-
|
|
16
|
+
Use Netlify Database when you need to store:
|
|
20
17
|
|
|
21
|
-
|
|
18
|
+
- Records, collections, or lists
|
|
19
|
+
- User-generated content
|
|
20
|
+
- Any data you would naturally model as rows in a table
|
|
21
|
+
- Data requiring queries, filtering, or transactions
|
|
22
|
+
|
|
23
|
+
There are two recommended approaches:
|
|
24
|
+
|
|
25
|
+
- **Drizzle ORM** (recommended): Use Drizzle ORM with the native Netlify Database adapter for type-safe schema
|
|
26
|
+
definitions and a query builder. Install `@netlify/database`, `drizzle-orm@beta`, and `drizzle-kit@beta`. The
|
|
27
|
+
`@beta` dist-tag is required — the Netlify Database adapter only exists on the beta release line.
|
|
28
|
+
- **Native `@netlify/database` driver**: Use the `sql` tagged template literal for direct SQL queries. Install `@netlify/database`.
|
|
29
|
+
|
|
30
|
+
IMPORTANT: Any code that assumes a different database schema requires a corresponding migration file in
|
|
31
|
+
`netlify/database/migrations/`. Without a migration, the database schema will not change and the application will break.
|
|
32
|
+
|
|
33
|
+
See the **netlify-database** skill for complete setup instructions and usage examples.
|
|
22
34
|
|
|
23
|
-
##
|
|
35
|
+
## Files and binary assets: Netlify Blobs
|
|
24
36
|
|
|
25
|
-
Netlify
|
|
26
|
-
|
|
37
|
+
**Netlify Blobs** is the recommended solution for file and binary storage.
|
|
38
|
+
|
|
39
|
+
Use Netlify Blobs when you need:
|
|
40
|
+
|
|
41
|
+
- File and image storage
|
|
42
|
+
- Binary assets (images, video, PDFs)
|
|
43
|
+
- Cached responses
|
|
44
|
+
|
|
45
|
+
See the **netlify-blobs** skill for complete setup instructions and usage examples.
|
|
@@ -1,18 +1,42 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: netlify-blobs
|
|
3
|
-
description: Store and retrieve data using Netlify Blobs
|
|
3
|
+
description: Store and retrieve files and other unstructured data using Netlify Blobs object storage. Use for uploaded files, images, video, pre-rendered content, cached responses, or large JSON documents that do not need relational querying. For any database-like use cases (records, collections, queryable application state), use Netlify Database instead.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Netlify Blobs
|
|
7
7
|
|
|
8
|
-
Netlify Blobs is a zero-configuration
|
|
8
|
+
Netlify Blobs is a zero-configuration object store optimized for frequent reads and infrequent writes. It provides
|
|
9
9
|
persistent storage scoped to your site with automatic provisioning and access control. The API will be the same across
|
|
10
10
|
all compute types (serverless functions, edge functions, build plugins, etc.).
|
|
11
11
|
|
|
12
12
|
Requires Fetch API support (Node.js 18+ recommended).
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
## When to use Netlify Blobs
|
|
15
|
+
|
|
16
|
+
Use Netlify Blobs for **unstructured object data** — things that are naturally a file or a self-contained blob:
|
|
17
|
+
|
|
18
|
+
- Uploaded files (user uploads, documents, attachments)
|
|
19
|
+
- Images, video, audio, and other binary assets
|
|
20
|
+
- Pre-rendered pages, HTML snippets, or build artifacts tied to a deploy
|
|
21
|
+
- Cached responses from upstream APIs or expensive computations
|
|
22
|
+
- Large JSON documents that are read and written as a whole (e.g. a prerender manifest, a cached API payload)
|
|
23
|
+
|
|
24
|
+
## When NOT to use Netlify Blobs
|
|
25
|
+
|
|
26
|
+
For ANY database-like use cases, use **Netlify Database** (see the `netlify-database` skill) — not Blobs.
|
|
27
|
+
|
|
28
|
+
That includes:
|
|
29
|
+
|
|
30
|
+
- Records, rows, or collections of entities (users, posts, orders, sessions, comments, …)
|
|
31
|
+
- Data you need to query, filter, sort, join, or count
|
|
32
|
+
- Data with relationships between different kinds of entities (users who own posts, posts with comments, …)
|
|
33
|
+
- Application state that evolves over time and needs to be read and updated field-by-field
|
|
34
|
+
- Anything a developer would naturally model as a table with columns
|
|
35
|
+
|
|
36
|
+
Blobs is an **object store**, not a database. Treating it as one — for example, storing one blob per user keyed by
|
|
37
|
+
user ID — works for trivial cases but breaks down as soon as you need to query or relate data. Netlify Database is
|
|
38
|
+
the correct primitive for those use cases, is equally zero-configuration, and handles relational data, SQL queries,
|
|
39
|
+
transactions, and migrations out of the box.
|
|
16
40
|
|
|
17
41
|
## Quick Start
|
|
18
42
|
|
|
@@ -129,8 +153,8 @@ NEVER add metadata unless the user explicitly instructs you to.
|
|
|
129
153
|
Stores a JSON-serializable value. Automatically serializes with `JSON.stringify`.
|
|
130
154
|
|
|
131
155
|
```typescript
|
|
132
|
-
await store.setJSON('
|
|
133
|
-
await store.setJSON('
|
|
156
|
+
await store.setJSON('prerender-manifest', { routes: ['/', '/about'], generatedAt: Date.now() })
|
|
157
|
+
await store.setJSON('cache/weather-api', { city: 'Lisbon', temperature: 22, fetchedAt: Date.now() })
|
|
134
158
|
```
|
|
135
159
|
|
|
136
160
|
NEVER add metadata unless the user explicitly instructs you to.
|
|
@@ -202,7 +226,7 @@ Lists entries in the store. By default retrieves all pages. Use `paginate: true`
|
|
|
202
226
|
const { blobs } = await store.list()
|
|
203
227
|
|
|
204
228
|
// With prefix filter
|
|
205
|
-
const { blobs } = await store.list({ prefix: '
|
|
229
|
+
const { blobs } = await store.list({ prefix: 'uploads/' })
|
|
206
230
|
|
|
207
231
|
// With hierarchical browsing
|
|
208
232
|
const { blobs, directories } = await store.list({
|
|
@@ -247,8 +271,9 @@ await store.delete('my-key')
|
|
|
247
271
|
|
|
248
272
|
### Site-Level Stores (`getStore`)
|
|
249
273
|
|
|
250
|
-
Data persists across all deploys and is shared by all functions and builds for the site. Use for
|
|
251
|
-
|
|
274
|
+
Data persists across all deploys and is shared by all functions and builds for the site. Use for uploaded files,
|
|
275
|
+
cached responses, and other unstructured objects that should survive redeployments. (For structured application
|
|
276
|
+
state — records, collections, anything relational — use Netlify Database instead.)
|
|
252
277
|
|
|
253
278
|
```typescript
|
|
254
279
|
import { getStore } from '@netlify/blobs'
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/agent-runner-cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.114.0
|
|
4
|
+
"version": "1.114.0",
|
|
5
5
|
"description": "CLI tool for running Netlify agents",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"@google/gemini-cli": "0.38.2",
|
|
87
87
|
"@netlify/database-proxy": "^0.1.5",
|
|
88
88
|
"@netlify/otel": "^5.1.5",
|
|
89
|
-
"@netlify/ts-cli": "^1.
|
|
89
|
+
"@netlify/ts-cli": "^1.1.1",
|
|
90
90
|
"@openai/codex": "0.125.0",
|
|
91
91
|
"@opentelemetry/exporter-trace-otlp-grpc": "0.57.2",
|
|
92
92
|
"execa": "^9.6.1",
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: general-database
|
|
3
|
-
description: Use this skill whenever the task involves storing, persisting, querying, or managing data — including CRUD operations, collections, records, user data, or any application state that needs to survive between requests. Covers both relational databases (Netlify Database) and object storage (Netlify Blobs).
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Data Storage on Netlify
|
|
7
|
-
|
|
8
|
-
Prefer Netlify Database over Netlify Blobs for any application data — records, collections, lists, user-generated content,
|
|
9
|
-
or anything you would store as rows. Use Blobs only for files, binary assets (images, video), or cached responses.
|
|
10
|
-
|
|
11
|
-
## Application data: Netlify Database
|
|
12
|
-
|
|
13
|
-
**Netlify Database** is the recommended solution for storing application data. It provides a fully managed Postgres database
|
|
14
|
-
with zero configuration — install the `@netlify/database` package, and a database is automatically provisioned for your site.
|
|
15
|
-
|
|
16
|
-
Use Netlify Database when you need to store:
|
|
17
|
-
|
|
18
|
-
- Records, collections, or lists
|
|
19
|
-
- User-generated content
|
|
20
|
-
- Any data you would naturally model as rows in a table
|
|
21
|
-
- Data requiring queries, filtering, or transactions
|
|
22
|
-
|
|
23
|
-
There are two recommended approaches:
|
|
24
|
-
|
|
25
|
-
- **Drizzle ORM** (recommended): Use Drizzle ORM with the native Netlify Database adapter for type-safe schema
|
|
26
|
-
definitions and a query builder. Install `@netlify/database`, `drizzle-orm@beta`, and `drizzle-kit@beta`. The
|
|
27
|
-
`@beta` dist-tag is required — the Netlify Database adapter only exists on the beta release line.
|
|
28
|
-
- **Native `@netlify/database` driver**: Use the `sql` tagged template literal for direct SQL queries. Install `@netlify/database`.
|
|
29
|
-
|
|
30
|
-
IMPORTANT: Any code that assumes a different database schema requires a corresponding migration file in
|
|
31
|
-
`netlify/database/migrations/`. Without a migration, the database schema will not change and the application will break.
|
|
32
|
-
|
|
33
|
-
See the **netlify-database** skill for complete setup instructions and usage examples.
|
|
34
|
-
|
|
35
|
-
## Files and binary assets: Netlify Blobs
|
|
36
|
-
|
|
37
|
-
**Netlify Blobs** is the recommended solution for file and binary storage.
|
|
38
|
-
|
|
39
|
-
Use Netlify Blobs when you need:
|
|
40
|
-
|
|
41
|
-
- File and image storage
|
|
42
|
-
- Binary assets (images, video, PDFs)
|
|
43
|
-
- Cached responses
|
|
44
|
-
|
|
45
|
-
See the **netlify-blobs** skill for complete setup instructions and usage examples.
|
|
@@ -1,421 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: netlify-blobs
|
|
3
|
-
description: Store and retrieve files and other unstructured data using Netlify Blobs object storage. Use for uploaded files, images, video, pre-rendered content, cached responses, or large JSON documents that do not need relational querying. For any database-like use cases (records, collections, queryable application state), use Netlify Database instead.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Netlify Blobs
|
|
7
|
-
|
|
8
|
-
Netlify Blobs is a zero-configuration object store optimized for frequent reads and infrequent writes. It provides
|
|
9
|
-
persistent storage scoped to your site with automatic provisioning and access control. The API will be the same across
|
|
10
|
-
all compute types (serverless functions, edge functions, build plugins, etc.).
|
|
11
|
-
|
|
12
|
-
Requires Fetch API support (Node.js 18+ recommended).
|
|
13
|
-
|
|
14
|
-
## When to use Netlify Blobs
|
|
15
|
-
|
|
16
|
-
Use Netlify Blobs for **unstructured object data** — things that are naturally a file or a self-contained blob:
|
|
17
|
-
|
|
18
|
-
- Uploaded files (user uploads, documents, attachments)
|
|
19
|
-
- Images, video, audio, and other binary assets
|
|
20
|
-
- Pre-rendered pages, HTML snippets, or build artifacts tied to a deploy
|
|
21
|
-
- Cached responses from upstream APIs or expensive computations
|
|
22
|
-
- Large JSON documents that are read and written as a whole (e.g. a prerender manifest, a cached API payload)
|
|
23
|
-
|
|
24
|
-
## When NOT to use Netlify Blobs
|
|
25
|
-
|
|
26
|
-
For ANY database-like use cases, use **Netlify Database** (see the `netlify-database` skill) — not Blobs.
|
|
27
|
-
|
|
28
|
-
That includes:
|
|
29
|
-
|
|
30
|
-
- Records, rows, or collections of entities (users, posts, orders, sessions, comments, …)
|
|
31
|
-
- Data you need to query, filter, sort, join, or count
|
|
32
|
-
- Data with relationships between different kinds of entities (users who own posts, posts with comments, …)
|
|
33
|
-
- Application state that evolves over time and needs to be read and updated field-by-field
|
|
34
|
-
- Anything a developer would naturally model as a table with columns
|
|
35
|
-
|
|
36
|
-
Blobs is an **object store**, not a database. Treating it as one — for example, storing one blob per user keyed by
|
|
37
|
-
user ID — works for trivial cases but breaks down as soon as you need to query or relate data. Netlify Database is
|
|
38
|
-
the correct primitive for those use cases, is equally zero-configuration, and handles relational data, SQL queries,
|
|
39
|
-
transactions, and migrations out of the box.
|
|
40
|
-
|
|
41
|
-
## Quick Start
|
|
42
|
-
|
|
43
|
-
Install the package and use `getStore` to start storing data:
|
|
44
|
-
|
|
45
|
-
```bash
|
|
46
|
-
npm install @netlify/blobs
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
import { getStore } from '@netlify/blobs'
|
|
51
|
-
|
|
52
|
-
const store = getStore('my-store')
|
|
53
|
-
|
|
54
|
-
// Write
|
|
55
|
-
await store.set('greeting', 'Hello, world!')
|
|
56
|
-
await store.setJSON('config', { theme: 'dark', lang: 'en' })
|
|
57
|
-
|
|
58
|
-
// Read
|
|
59
|
-
const greeting = await store.get('greeting', { type: 'text' })
|
|
60
|
-
const config = await store.get('config', { type: 'json' })
|
|
61
|
-
|
|
62
|
-
// Delete
|
|
63
|
-
await store.delete('greeting')
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
## API Reference
|
|
67
|
-
|
|
68
|
-
### Global Functions
|
|
69
|
-
|
|
70
|
-
#### `getStore(name: string | StoreOptions): Store`
|
|
71
|
-
|
|
72
|
-
Returns a store instance for a site-level namespace. Data persists across deploys.
|
|
73
|
-
|
|
74
|
-
```typescript
|
|
75
|
-
import { getStore } from '@netlify/blobs'
|
|
76
|
-
|
|
77
|
-
// Simple usage
|
|
78
|
-
const store = getStore('my-store')
|
|
79
|
-
|
|
80
|
-
// With options
|
|
81
|
-
const store = getStore({
|
|
82
|
-
name: 'my-store',
|
|
83
|
-
consistency: 'strong',
|
|
84
|
-
})
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
**`StoreOptions`:**
|
|
88
|
-
|
|
89
|
-
| Property | Type | Description |
|
|
90
|
-
|----------|------|-------------|
|
|
91
|
-
| `name` | `string` | Store namespace (required) |
|
|
92
|
-
| `consistency` | `'strong' \| 'eventual'` | Consistency model (default: `'eventual'`) |
|
|
93
|
-
|
|
94
|
-
ONLY add the options argument if the user needs strong consistency.
|
|
95
|
-
|
|
96
|
-
#### `getDeployStore(options?: DeployStoreOptions): Store`
|
|
97
|
-
|
|
98
|
-
Returns a store scoped to a specific deploy. Data is isolated per deploy and immutable after deploy finishes.
|
|
99
|
-
|
|
100
|
-
```typescript
|
|
101
|
-
import { getDeployStore } from '@netlify/blobs'
|
|
102
|
-
|
|
103
|
-
const store = getDeployStore()
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
Use deploy stores for data that should be tied to a specific deploy snapshot (e.g., pre-rendered page data, build
|
|
107
|
-
artifacts). ONLY add the options argument if the user needs strong consistency.
|
|
108
|
-
|
|
109
|
-
#### `listStores(options?: ListStoresOptions): Promise<{ stores: string[] }>`
|
|
110
|
-
|
|
111
|
-
Lists all site-level store names. Supports pagination for sites with many stores.
|
|
112
|
-
|
|
113
|
-
```typescript
|
|
114
|
-
import { listStores } from '@netlify/blobs'
|
|
115
|
-
|
|
116
|
-
const { stores } = await listStores()
|
|
117
|
-
console.log(stores) // ['my-store', 'uploads', ...]
|
|
118
|
-
|
|
119
|
-
// Paginated iteration
|
|
120
|
-
for await (const page of listStores({ paginate: true })) {
|
|
121
|
-
console.log(page.stores)
|
|
122
|
-
}
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
DO NOT pass options unless paginating.
|
|
126
|
-
|
|
127
|
-
### Store Methods
|
|
128
|
-
|
|
129
|
-
THESE ARE THE ONLY STORE METHODS. DO NOT MAKE UP NEW ONES.
|
|
130
|
-
|
|
131
|
-
#### `set(key: string, value: string | ArrayBuffer | Blob, options?: SetOptions): Promise<void>`
|
|
132
|
-
|
|
133
|
-
Stores a value. Supports strings, binary data (ArrayBuffer), and Blob objects.
|
|
134
|
-
|
|
135
|
-
```typescript
|
|
136
|
-
await store.set('my-key', 'my-value')
|
|
137
|
-
await store.set('binary-key', new Uint8Array([1, 2, 3]))
|
|
138
|
-
await store.set('with-meta', 'value', {
|
|
139
|
-
metadata: { contentType: 'text/plain', author: 'system' },
|
|
140
|
-
})
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
**`SetOptions`:**
|
|
144
|
-
|
|
145
|
-
| Property | Type | Description |
|
|
146
|
-
|----------|------|-------------|
|
|
147
|
-
| `metadata` | `Record<string, string>` | Custom metadata (max 64 KB total) |
|
|
148
|
-
|
|
149
|
-
NEVER add metadata unless the user explicitly instructs you to.
|
|
150
|
-
|
|
151
|
-
#### `setJSON(key: string, value: any, options?: SetOptions): Promise<void>`
|
|
152
|
-
|
|
153
|
-
Stores a JSON-serializable value. Automatically serializes with `JSON.stringify`.
|
|
154
|
-
|
|
155
|
-
```typescript
|
|
156
|
-
await store.setJSON('prerender-manifest', { routes: ['/', '/about'], generatedAt: Date.now() })
|
|
157
|
-
await store.setJSON('cache/weather-api', { city: 'Lisbon', temperature: 22, fetchedAt: Date.now() })
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
NEVER add metadata unless the user explicitly instructs you to.
|
|
161
|
-
|
|
162
|
-
#### `get(key: string, options?: GetOptions): Promise<string | Blob | object | ArrayBuffer | null>`
|
|
163
|
-
|
|
164
|
-
Retrieves a value by key. Returns `null` if the key does not exist.
|
|
165
|
-
|
|
166
|
-
```typescript
|
|
167
|
-
// As text (default)
|
|
168
|
-
const text = await store.get('my-key', { type: 'text' })
|
|
169
|
-
|
|
170
|
-
// As JSON
|
|
171
|
-
const data = await store.get('config', { type: 'json' })
|
|
172
|
-
|
|
173
|
-
// As ArrayBuffer
|
|
174
|
-
const binary = await store.get('binary-key', { type: 'arrayBuffer' })
|
|
175
|
-
|
|
176
|
-
// As Blob
|
|
177
|
-
const blob = await store.get('image', { type: 'blob' })
|
|
178
|
-
|
|
179
|
-
// As ReadableStream
|
|
180
|
-
const stream = await store.get('large-file', { type: 'stream' })
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
**`GetOptions.type`:** `'text'` | `'json'` | `'arrayBuffer'` | `'blob'` | `'stream'`
|
|
184
|
-
|
|
185
|
-
ALWAYS use `store.get('key', { type: 'json' })` instead of `JSON.parse(await store.get('key'))`. NEVER add the options
|
|
186
|
-
argument unless you need a specific type.
|
|
187
|
-
|
|
188
|
-
#### `getWithMetadata(key: string, options?: GetOptions): Promise<{ data, metadata } | null>`
|
|
189
|
-
|
|
190
|
-
Retrieves a value along with its custom metadata.
|
|
191
|
-
|
|
192
|
-
```typescript
|
|
193
|
-
const result = await store.getWithMetadata('my-key', { type: 'text' })
|
|
194
|
-
if (result) {
|
|
195
|
-
console.log(result.data) // the value
|
|
196
|
-
console.log(result.metadata) // { contentType: '...', ... }
|
|
197
|
-
}
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
NEVER add the second getOpts arg unless you need an explicit type or have an etag to check against. AVOID adding it
|
|
201
|
-
unless it's reliably available but IF an etag is provided, it will only return the blob if the etag is different than
|
|
202
|
-
what's stored.
|
|
203
|
-
|
|
204
|
-
#### `getMetadata(key: string): Promise<{ metadata: Record<string, string> } | null>`
|
|
205
|
-
|
|
206
|
-
Retrieves only the metadata for a key, without downloading the value. Useful for checking existence or reading metadata
|
|
207
|
-
on large blobs.
|
|
208
|
-
|
|
209
|
-
```typescript
|
|
210
|
-
const result = await store.getMetadata('my-key')
|
|
211
|
-
if (result) {
|
|
212
|
-
console.log(result.metadata)
|
|
213
|
-
}
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
NEVER add the second getOpts arg unless you need an explicit type or have an etag to check against. AVOID adding it
|
|
217
|
-
unless it's reliably available but IF an etag is provided, it will only return the blob if the etag is different than
|
|
218
|
-
what's stored.
|
|
219
|
-
|
|
220
|
-
#### `list(options?: ListOptions): Promise<{ blobs: ListEntry[], directories: string[] }>`
|
|
221
|
-
|
|
222
|
-
Lists entries in the store. By default retrieves all pages. Use `paginate: true` for an `AsyncIterable`.
|
|
223
|
-
|
|
224
|
-
```typescript
|
|
225
|
-
// List all
|
|
226
|
-
const { blobs } = await store.list()
|
|
227
|
-
|
|
228
|
-
// With prefix filter
|
|
229
|
-
const { blobs } = await store.list({ prefix: 'uploads/' })
|
|
230
|
-
|
|
231
|
-
// With hierarchical browsing
|
|
232
|
-
const { blobs, directories } = await store.list({
|
|
233
|
-
prefix: 'uploads/',
|
|
234
|
-
directories: true,
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
// Paginated iteration
|
|
238
|
-
for await (const page of store.list({ paginate: true })) {
|
|
239
|
-
for (const blob of page.blobs) {
|
|
240
|
-
console.log(blob.key)
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
**`ListOptions`:**
|
|
246
|
-
|
|
247
|
-
| Property | Type | Description |
|
|
248
|
-
|----------|------|-------------|
|
|
249
|
-
| `prefix` | `string` | Filter keys by prefix |
|
|
250
|
-
| `directories` | `boolean` | Group by `/` delimiter |
|
|
251
|
-
| `paginate` | `boolean` | Return `AsyncIterable` for page-by-page iteration |
|
|
252
|
-
| `cursor` | `string` | Pagination cursor from previous response |
|
|
253
|
-
| `limit` | `number` | Max entries per page |
|
|
254
|
-
|
|
255
|
-
**`ListEntry`:**
|
|
256
|
-
|
|
257
|
-
| Property | Type | Description |
|
|
258
|
-
|----------|------|-------------|
|
|
259
|
-
| `key` | `string` | Blob key |
|
|
260
|
-
| `etag` | `string` | Content hash |
|
|
261
|
-
|
|
262
|
-
#### `delete(key: string): Promise<void>`
|
|
263
|
-
|
|
264
|
-
Deletes a single blob. No error if the key does not exist.
|
|
265
|
-
|
|
266
|
-
```typescript
|
|
267
|
-
await store.delete('my-key')
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
## Storage Scopes
|
|
271
|
-
|
|
272
|
-
### Site-Level Stores (`getStore`)
|
|
273
|
-
|
|
274
|
-
Data persists across all deploys and is shared by all functions and builds for the site. Use for uploaded files,
|
|
275
|
-
cached responses, and other unstructured objects that should survive redeployments. (For structured application
|
|
276
|
-
state — records, collections, anything relational — use Netlify Database instead.)
|
|
277
|
-
|
|
278
|
-
```typescript
|
|
279
|
-
import { getStore } from '@netlify/blobs'
|
|
280
|
-
|
|
281
|
-
const store = getStore('user-uploads')
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
### Deploy-Specific Stores (`getDeployStore`)
|
|
285
|
-
|
|
286
|
-
Data is scoped to a single deploy. Use for build-generated data, pre-rendered content, or data that should be
|
|
287
|
-
immutable after deploy. Build plugins and file-based uploads must write to deploy-specific stores.
|
|
288
|
-
|
|
289
|
-
```typescript
|
|
290
|
-
import { getDeployStore } from '@netlify/blobs'
|
|
291
|
-
|
|
292
|
-
const store = getDeployStore()
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
**Production isolation pattern:** Use a global store in production and deploy store otherwise to prevent non-production
|
|
296
|
-
data from polluting global stores:
|
|
297
|
-
|
|
298
|
-
```typescript
|
|
299
|
-
import { getStore, getDeployStore } from '@netlify/blobs'
|
|
300
|
-
|
|
301
|
-
function getBlobStore(...storeOptions) {
|
|
302
|
-
if (Netlify.context?.deploy.context === 'production') {
|
|
303
|
-
return getStore(...storeOptions)
|
|
304
|
-
}
|
|
305
|
-
return getDeployStore(...storeOptions)
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
const store = getBlobStore('app-data')
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
## Consistency Models
|
|
312
|
-
|
|
313
|
-
| Model | Default | Propagation | Use Case |
|
|
314
|
-
|-------|---------|-------------|----------|
|
|
315
|
-
| `eventual` | Yes | Up to 60 seconds | High-read workloads, caching |
|
|
316
|
-
| `strong` | No | Immediate | Critical data, counters |
|
|
317
|
-
|
|
318
|
-
Last-write-wins: concurrent writes to the same key result in the final write persisting. Add object-locking mechanisms
|
|
319
|
-
if you need concurrency guarantees.
|
|
320
|
-
|
|
321
|
-
```typescript
|
|
322
|
-
// Strong consistency when you need immediate read-after-write
|
|
323
|
-
const store = getStore({ name: 'counters', consistency: 'strong' })
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
## File-Based Uploads
|
|
327
|
-
|
|
328
|
-
Deploy blobs by placing files in the `.netlify/blobs/deploy/` directory at build time. These are written to a
|
|
329
|
-
deploy-specific store automatically.
|
|
330
|
-
|
|
331
|
-
```
|
|
332
|
-
.netlify/blobs/deploy/
|
|
333
|
-
my-key.txt # Value stored with key "my-key.txt"
|
|
334
|
-
$my-key.txt.json # Optional metadata for "my-key.txt"
|
|
335
|
-
nested/path/data.json # Key is "nested/path/data.json"
|
|
336
|
-
```
|
|
337
|
-
|
|
338
|
-
**Metadata pattern:** Create a `$filename.json` sibling file:
|
|
339
|
-
|
|
340
|
-
```json
|
|
341
|
-
{
|
|
342
|
-
"contentType": "text/plain",
|
|
343
|
-
"author": "build-pipeline"
|
|
344
|
-
}
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
Read file-based blobs in functions using `getDeployStore`:
|
|
348
|
-
|
|
349
|
-
```typescript
|
|
350
|
-
import { getDeployStore } from '@netlify/blobs'
|
|
351
|
-
|
|
352
|
-
const store = getDeployStore()
|
|
353
|
-
const data = await store.get('my-key.txt', { type: 'text' })
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
## Limits
|
|
357
|
-
|
|
358
|
-
| Resource | Limit |
|
|
359
|
-
|----------|-------|
|
|
360
|
-
| Store name | 64 bytes |
|
|
361
|
-
| Key | 600 bytes |
|
|
362
|
-
| Object size | 5 GB |
|
|
363
|
-
| Metadata per object | 64 KB |
|
|
364
|
-
| Stores per site | Unlimited |
|
|
365
|
-
| Objects per store | Unlimited |
|
|
366
|
-
|
|
367
|
-
## Common Errors & Solutions
|
|
368
|
-
|
|
369
|
-
### "Store not found" or empty reads
|
|
370
|
-
|
|
371
|
-
**Cause:** Store name mismatch or reading from wrong scope.
|
|
372
|
-
|
|
373
|
-
**Fix:**
|
|
374
|
-
|
|
375
|
-
1. Verify the store name matches exactly (case-sensitive)
|
|
376
|
-
2. Use `listStores()` to confirm the store exists
|
|
377
|
-
3. Ensure you're using `getStore` for site-level data and `getDeployStore` for deploy-scoped data
|
|
378
|
-
|
|
379
|
-
### "The environment has not been configured to use Netlify Blobs"
|
|
380
|
-
|
|
381
|
-
**Cause:** Missing Blobs environment configuration in local development.
|
|
382
|
-
|
|
383
|
-
**Fix:**
|
|
384
|
-
|
|
385
|
-
1. Install the framework plugin (`@netlify/vite-plugin`, `@netlify/nuxt`, or `@netlify/vite-plugin-tanstack-start`)
|
|
386
|
-
2. Deploy to Netlify or use the Vite plugin for local env configuration
|
|
387
|
-
3. Ensure the site has at least one production deploy
|
|
388
|
-
|
|
389
|
-
This does NOT apply to legacy V1 functions which require manual siteID/token configuration.
|
|
390
|
-
|
|
391
|
-
### "Unauthorized" or permission errors
|
|
392
|
-
|
|
393
|
-
**Cause:** Function is not running in a Netlify environment.
|
|
394
|
-
|
|
395
|
-
**Fix:**
|
|
396
|
-
|
|
397
|
-
1. Deploy to Netlify
|
|
398
|
-
2. Ensure the site has at least one production deploy
|
|
399
|
-
3. Confirm the function is deployed to Netlify (not a third-party host)
|
|
400
|
-
|
|
401
|
-
### Stale reads after writing
|
|
402
|
-
|
|
403
|
-
**Cause:** Default eventual consistency model (up to 60s propagation).
|
|
404
|
-
|
|
405
|
-
**Fix:**
|
|
406
|
-
|
|
407
|
-
1. Use strong consistency if immediate reads are required:
|
|
408
|
-
```typescript
|
|
409
|
-
const store = getStore({ name: 'my-store', consistency: 'strong' })
|
|
410
|
-
```
|
|
411
|
-
2. Note that strong consistency has higher latency
|
|
412
|
-
|
|
413
|
-
### Large object upload timeouts
|
|
414
|
-
|
|
415
|
-
**Cause:** Object exceeds function timeout or network limits.
|
|
416
|
-
|
|
417
|
-
**Fix:**
|
|
418
|
-
|
|
419
|
-
1. Verify object is under 5 GB
|
|
420
|
-
2. For large uploads, use file-based uploads via `.netlify/blobs/deploy/` at build time
|
|
421
|
-
3. For function uploads, ensure function timeout is sufficient (background functions have 15-min timeout)
|
|
File without changes
|