Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Cursor rules for Netlify development with official integration.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 341% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 551% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 349% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 707% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 1559% | 0% |
Cursor rules for Netlify development with official integration.
Synced from https://github.com/PatrickJS/awesome-cursorrules/tree/main/rules/netlify-official-cursorrules-prompt-file.mdc.
<ProviderContextOverrides> // Developers can override the content as needed, but it should all be placed in this section.
</ProviderContextOverrides>
ANY RULES IN THE ProviderContextOverrides SECTION CAN OVERRULE SPECIFIC RULES IN ProviderContext
<ProviderContext version="1.0" provider="netlify"> ## General
.netlify folder is not for user code. It should be added to the .gitignore list@netlify/functions and never @netlify/functions@VERSION)netlify dev to start dev server unless another dev command is requested by the user# Guidelines
## Netlify compute
### Context object for serverless functions and edge functions
Below are the available fields/functions from the context argument to serverless and edge functions.
{ account: { id: string, // Unique ID of the Netlify team account associated with the site and function. }, cookies: { get: (name: string) => string | undefined, // Reads a cookie from the incoming request. set: (options: { name: string; value: string; path?: string; domain?: string; secure?: boolean; httpOnly?: boolean; expires?: Date }) => void, // Sets a cookie on the outgoing response following the CookieStore.set web standard. delete: (nameOrOptions: string | { name: string; path?: string; domain?: string }) => void, // Deletes a cookie on the outgoing response, following the CookieStore.delete web standard. }, deploy: { context: string, // The deploy context (e.g., production, deploy-preview). id: string, // Unique ID of the deploy the function belongs to. published: boolean, // Indicates whether the function belongs to the currently published deploy. }, geo: { city: string, // City name of the client location. country: { code: string, // ISO 3166 country code. name: string, // Full country name. }, latitude: number, // Latitude coordinate of the client location. longitude: number, // Longitude coordinate of the client location. subdivision: { code: string, // ISO 3166 subdivision code (e.g., state or province). name: string, // Subdivision name. }, timezone: string, // Timezone of the location. postalCode: string, // Postal code of the location in its regional format. ip: string, // Client IP address. }, params: Record<string, string>, // Object containing route parameters from the function path configuration. requestId: string, // Unique Netlify request ID. server: { region: string, // The region code where the deployment is running (e.g., us-east-1). }, site: { id: string, // Unique ID for the Netlify site. name: string, // The site's Netlify subdomain name. url: string, // The main address of the site, which could be a Netlify subdomain or a custom domain. }, }
### the Netlify global object
Netlify object is available in global scope.It has the following fields/functions:
{ context: object | null, // The Netlify-specific context object - same as function's second arg. Available only within function handlers or child scopes; otherwise, it returns null.
env: { delete: (name: string) => void, // Deletes an environment variable within the context of the invocation. get: (name: string) => string | undefined, // Retrieves the string value of an environment variable; returns undefined if not defined. has: (name: string) => boolean, // Checks if an environment variable exists; returns true if it does, otherwise false. set: (name: string, value: string) => void, // Sets an environment variable within the invocation context. toObject: () => Record<string, string>, // Returns an object containing all environment variables and their values. }, };
### Serverless Functions (aka Functions, aka Synchronous functions)
npm install @netlify/functionsNetlify object that is also accessible.Netlify.env.* for interacting with environment variables in code.YOUR_BASE_DIRECTORY/netlify/functions or a subdirectory.netlify.toml:toml [functions] directory = "my_functions"
netlify.toml settings override UI settings.index.mts or match the subdirectory name.netlify/functions/hello.mtsnetlify/functions/hello/index.mtsnetlify/functions/hello/hello.mts.mts enables modern ES module syntax#### Examples of the latest Serverless Function or Function structures
typescriptimport type { Context, Config } from "@netlify/functions";
export default async (req: Request, context: Context) => { // user code return new Response("Hello, world!") }
export const config: Config = { // use this path instead of /.netlify/functions/{fnName} path: "/hello-world" };
javascriptexport default async (req, context) => { // user code return new Response("Hello, world!") }
export const config = { // use this path instead of /.netlify/functions/{fnName} path: "/hello-world" }; #### In-code function config and routing for serverless functions
config object. This is the structure the config can have:/.netlify/functions/{function_name} path by default. { path: string | string[], // Defines the URL path(s) that trigger the function. Can be a single string or an array of paths. excludedPath?: string | string[], // Optional. Defines paths that should be excluded from triggering the function. preferStatic?: boolean, // Optional. If true, prevents the function from overriding existing static assets on the CDN. }
### Background Functions
#### Examples of the latest background function structures
typescriptimport { Context } from "@netlify/functions";
export default async (req: Request, context: Context) => { await someLongRunningTask();
console.log("Done"); };
javascriptexport default async (req, context) => { await someLongRunningTask();
console.log("Done"); };
### Scheduled Functions
next_run property. It represents the timestamp of the next scheduled invocation, as a string in the ISO-8601 format.netlify.toml. ONLY do this for consistency or if explicitly asked to keep all schedules in one place.toml [functions."test-scheduled-function"] schedule = "@hourly"
netlify functions:invoke command to trigger the scheduled function.example: bash netlify functions:invoke myfunction
#### Examples of the latest background function structures
typescriptimport type { Config } from "@netlify/functions"
export default async (req: Request) => { const { next_run } = await req.json()
console.log("Received event! Next invocation at:", next_run) }
export const config: Config = { schedule: "@hourly" }
javascriptexport default async (req) => { const { next_run } = await req.json()
console.log("Received event! Next invocation at:", next_run) }
export const config = { schedule: "@hourly" }
### Edge Functions
npm install @netlify/edge-functionsNetlify object that is also accessible.Netlify.env.* for interacting with environment variables in code.YOUR_BASE_DIRECTORY/netlify/edge-functions or a subdirectory.netlify.toml:toml [build] edge_functions = "my-custom-directory"
node: prefix (e.g., import { randomBytes } from "node:crypto").import React from "https://esm.sh/react" or an import map).npm install and import by package name (e.g., import _ from "lodash").deno.json).import_map.json):json { "imports": { "html-rewriter": "https://ghuc.cc/worker-tools/html-rewriter/index.ts" } }
netlify.toml:toml [functions] deno_import_map = "./path/to/your/import_map.json"
javascript import { HTMLRewriter } from "html-rewriter"; #### Examples of the latest Edge function structures
typescriptimport type { Context, Config } from "@netlify/edge-functions";
export default async (req: Request, context: Context) => { // user code return new Response("Hello, world!") }
export const config: Config = { path: "/hello-world" };
javascriptexport default async (req, context) => { // user code return new Response("Hello, world!") }
export const config = { path: "/hello-world" };
#### Extra properties on context argument for Edge Functions
{ ...ALL OTHER Context fields/methods,
next: (options?: { sendConditionalRequest?: boolean }) => Promise<Response>, // Invokes the next item in the request chain, optionally using conditional requests.
nextRequest: (request: Request, options?: { sendConditionalRequest?: boolean }) => Promise<Response>, // Same as next(), but requires an explicit Request object. }
#### Web APIs available in Edge Functions ONLY
#### In-code function config and routing for Edge functions
config object. This is the structure the config can have: { path?: string | string[], // URLPattern expression defining paths where the edge function should run. Must start with '/'. excludedPath?: string | string[], // Optional. Defines paths to exclude from execution. Must start with '/'. pattern?: RegExp | RegExp[], // Alternative to path. Uses regex for path matching. excludedPattern?: RegExp | RegExp[], // Optional. Defines regex patterns to exclude certain routes. method?: string | string[], // Optional. Specifies HTTP methods that should trigger the function (e.g., "GET", ["POST", "PUT"]). onError?: "continue" | "fail" | "fallback", // Optional. Controls how the function handles errors. cache?: 'manual', // Optional. Enables response caching if set to 'manual'. } = { path: "", // Default value; should be set per function. };
#### Configuring Edge Functions in netlify.toml
netlify.toml for precise function order control instead of inline declarations.netlify.toml if there is not edge function ordering requirements.netlify.toml:function: Name of the edge function.path: URL pattern to trigger the function (must start with /).excludedPath: Excludes specific routes from path (supports string or array).pattern: Regex-based path matching.excludedPattern: Excludes specific regex patterns (single or array).cache: Enables response caching (cached functions run after non-cached ones) set to 'manual' to opt in.toml edge_functions]] path = "/admin" function = "auth"
edge_functions]] path = "/admin" function = "injector" cache = "manual"
edge_functions]] path = "/blog/" function = "auth"
edge_functions]] path = "/blog/" function = "rewriter"
edge_functions]] pattern = "/products/(.)" excludedPattern = "/products/things/(.)" function = "highlight"
edge_functions]] path = "/" excludedPath = "/img/" function = "common"
netlify.toml) run first.netlify.toml functions.fetch() or URL() triggers a new request chain, re-running matching functions.context.next() to continue processing instead of re-triggering functions.#### Edge functions limitations
fetch() for external content)## Netlify Blobs
@netlify/blobs NPM module is installed### Netlify Blobs API
typescript export interface BlobMetadata { key: string]: any; }
export interface BlobData<T = string> { data: T | null; etag: string; metadata: BlobMetadata; }
export interface ListResult { blobs: { etag: string; key: string }]; directories?: string]; }
interface GetKeyOptions { type?: 'arrayBuffer' | 'blob' | 'json' | 'stream' | 'text' }
interface GetKeyAndMetadataOptions { type?: 'arrayBuffer' | 'blob' | 'json' | 'stream' | 'text', etag?: string; }
// THESE ARE THE ONLY STORE METHODS. DO NOT MAKE UP NEW ONES interface Store {
// Creates or overwrites a blob entry. // example: await store.set('key-name', 'contents-of key'); // - NEVER add metadata unless instructed to. set(key: string, value: ArrayBuffer | Blob | string, { metadata?: object }): Promise<void>;
// Stores a JSON-serializable object. // example: await store.setJSON('key-name', {version: 'a', someBoolean: true}); // - NEVER add metadata unless instructed to. setJSON(key: string, value: any, { metadata?: object }): Promise<void>;
// Retrieves a stored blob. // example: await store.get('key-name'); // - NEVER add the second arg unless you need an explicit type 'arrayBuffer' | 'blob' | 'json' | 'stream' | 'text'. // - Instead of using JSON.parse(blob), use store.get('key-name', {type: 'json'}) // - if the blob is missing, it will resolve the promise with a null value get(key: string, getOpt?: GetKeyOptions): Promise<any | null>;
// Retrieves a blob along with metadata // example: await store.getWithMetadata('key-name'); // - NEVER add the second getOpts arg unless you need an explicit type or have an etag to check against. // - AVOID adding it unless it's reliably available but IF an etag is provided, it will only return the blob if the etag is different that what's stored. // - if the blob is missing, it will resolve the promise with a null value getWithMetadata(key: string, getOpts?: GetKeyAndMetadataOptions): Promise<{ data: any, etag: string, metadata: object } | null>;
// Retrieves metadata of a blob WITHOUT downloading the data. // example: await store.getMetadata('key-name'); // - NEVER add the second getOpts arg unless you need an explicit type or have an etag to check against. // - AVOID adding it unless it's reliably available but IF an etag is provided, it will only return the blob if the etag is different that what's stored. // - if the blob is missing, it will resolve the promise with a null value getMetadata(key: string, getOpts?: GetKeyAndMetadataOptions): Promise<{ etag: string, metadata: object } | null>;
// Lists blobs in the store with optional hierarchical browsing. // example: // const { blobs } = await store.list() // // blobs === { etag: 'etag1', key: 'some-key' }, { etag: 'etag2', key: 'another-key' } ] // // - NEVER add the options arg unless you need an explicit reduce the searched data. // -- ONLY if you have to reduce searched data, use prefix: 'some-prefix' to pull blobs that start with that prefix value. Use directories: true to include the full directory path on the key // - By default, the list() method retrieves all pages, meaning you'll always get the full list of results. This can be slow or memory intensive. To paginate, pass the paginate: true in the options to turn the response into an AsyncIterator that allows you to for-of loop through the blobs in the store. // - if store path is empty, the blobs will resolve the promise with an empty array list(options?: { directories?: boolean, paginate?: boolean. prefix?: string }): Promise<{ blobs: BlobResult], directories: string] }> | AsyncIterable<{ blobs: BlobResult], directories: string] }>
// Deletes a blob. // example: await store.delete('key-name'); // - The return value is always resolves to undefined, regardless of whether or not there was an object to delete. delete(key: string): Promise<void>; }
interface GetDeployStoreOptions extends Partial<ClientOptions> { deployID?: string; name?: string; region?: Region; }
// Returns a store instance for managing blobs. This is global scoped data across all deploys. // example: const store = getStore('my-store'); // - ONLY add the options argument if the user needs strong consistency export function getStore(name: string, options?: { consistency?: 'strong' | 'eventual' }): Store;
// Returns a deploy-specific store instance for managing blobs tied to a deploy. // example: const store = getDeployStore('my-store'); // - ONLY add the options argument if the user needs strong consistency declare const getDeployStore: (input?: GetDeployStoreOptions | string) => Store; interface GetStoreOptions extends Partial<ClientOptions> { deployID?: string; name?: string; }
// Lists all stores available on a site. // example: // const { stores } = await listStores(); // // "beauty", "construction" ] // - By default, the listStores() method retrieves all pages, meaning you'll always get the full list of results. This can be slow or memory intensive. To paginate, pass the paginate: true in the options to turn the response into an AsyncIterator that allows you to for-of loop through the blobs in the store. // - DO NOT pass options unless paginating. declare function listStores(options?: { paginate?: boolean; }): Promise<ListStoresResponse> | AsyncIterable<ListStoresResponse>;
interface ListStoresResponse { stores: string]; next_cursor?: string; }
## File-Based Uploads With file-based uploads, write blobs to deploy-specific stores after the site build completes. Useful for frameworks and other tools integrating with Netlify as it does not require a build plugin.
Put files in .netlify/blobs/deploy/* for deploy specific .netlify/ ├─ blobs/ | ├─ deploy/ │ | ├─ beauty/ │ │ | └─ nails.jpg To attach metadata to a blob via file upload flows, include a JSON file that prefixes the corresponding blob filename with $ and has a .json extension. For example: ├─ blobs/ | ├─ deploy/ │ | ├─ beauty/ │ │ | ├─ nails.jpg │ │ | └─ $nails.jpg.json
## Blob consistency models
consistency field to 'strong' on the store instantiation.Example: javascript const store = getStore({ name: "animals", consistency: "strong" }); await store.set("dog", "dog"); const dog = await store.get("dog");
## Storage scopes
getDeployStore() is used to interact with deploy specific stores.getStore() is used for global scope.#### Examples of blob usage
javascript // basic writing to a deploy store import { getDeployStore } from "@netlify/blobs"; const store = getDeployStore("construction");
javascript // basic writing to a global store import { getStore } from "@netlify/blobs"; const store = getStore("construction");
javascript // using global store if in production, otherwise use deploy scope store import { getStore, getDeployStore } from "@netlify/blobs";
function getBlobStore(...storeOptions){
if((Netlify.context?.deploy.context === 'production'){ return getStore(...storeOptions); }
return getDeployStore(...storeOptions) }
const store = getBlobStore("construction");
---
## Netlify Image CDN
/.netlify/images route supported by their site without any additional enablement./.netlify/images.w (width) and h (height) in pixels.contain, cover, fill).top, bottom, left, right, center).avif, jpg, png, webp, gif, or blurhash.q, 1-100, default 75).### Example transformations html <!-- get an image hosted on this site and change its size and format --> <img src="/.netlify/images?url=/image.jpg&w=100&h=100&fit=cover&fm=webp&q=80" />
<!-- get an image hosted externally and change its size and format --> <img src="/.netlify/images?url=https://example.com/path/to/image&w=40&h=10&fm=jpg&q=80" />
### Caching & deployment behavior
netlify.toml.toml [images] remote_images = ["https://externalexample.com/.*"]
### Redirects & Rewrites
/.netlify/images path, a redirect or rewrite can be used to have a different url._redirects or netlify.toml files.toml [[redirects]] from = "/transform-my-images/*" to = "/.netlify/images?url=/:splat&w=50&h=50" status = 200
/transform-all/* /.netlify/images?url=/:splat&w=50&h=50 200
### Custom headers
toml [[headers]] for = "/source-images/*" [headers.values] Cache-Control = "public, max-age=604800, must-revalidate"
/source-images/* Cache-Control: public, max-age=604800, must-revalidate ### Image CDN framework support Netlify Image CDN integrates with frameworks for automatic optimizations:
NgOptimizedImage component will use Image CDN automatically<Image /> component will use Image CDN automaticallyNETLIFY_IMAGE_CDN=true and use the Contentful, Drupal, or WordPress source plugins.remotePatterns in next.config.jsnuxt/image module will use Image CDN automatically---
## Environment Variables
netlify.toml overrides UI/CLI/API variables, and site-specific variables take precedence over shared ones.### Creating Environment Variables Variables can be created and managed using:
netlify.toml): Defines variables at the repository level. ONLY use this for environment variables where the site is not linked yet and the values are not sensitive.### Netlify CLI Command
env:set for changes, env:unset to delete. env:import to import from a dotenv.env file.#### Example usage of env var CLI
sh netlify env:set API_KEY "not-a-secret"
sh netlify env:set API_KEY "secret-value" --secret
### Example netlify.toml Configuration
toml # Production context: all deploys from the Production branch # set in your site’s Branches settings in the UI will inherit # these settings. You can define environment variables # here but we recommend using the Netlify UI for sensitive # values to keep them out of your source repository. context.production] publish = "output/" command = "make publish" environment = { NODE_VERSION = "14.15.3" }
# Here is an example of how to define context-specific # environment variables. Be mindful when using this # option and avoid committing sensitive values to public # source repositories. context.deploy-preview.environment] NOT_PRIVATE_ITEM = "not so secret"
# Branch Deploy context: all deploys that are not from # a pull/merge request or from the Production branch # will inherit these settings. context.branch-deploy.environment] NODE_ENV = "development"
# Dev context: environment variables set here # are available for local development environments # run using Netlify Dev. These values can be # overwritten on branches that have a more specific # branch context configured. context.dev.environment] NODE_ENV = "development"
# Specific branch context: all deploys from # this specific branch will inherit these settings. context.staging.environment] # staging is a branch name NODE_ENV = "development"
### .env File Handling
.env files directly.env variables into Netlify using the UI or CLI (netlify env:import .env).env:list) only after confirming where the output will be stored..env by default.### Export .env Variables sh # list the production deploy context values in .env format netlify env:list --plain --context production
# only after explicit user confirmation: # 1. confirm .env.local is gitignored # 2. confirm the user wants a local production-context export # 3. remind the user not to commit the file netlify env:list --plain --context production > .env.local
---
# Creating new sites
# Initializing sites or linking them
PROJECT_FOLDER/.netlify/state.json file exists and it has a populated siteId value.netlify init to allow the user to set up the site with Netlify. If the user deploys manually, it will set up the site to use Netlify automatically. If the user decides to set up a repo, they might have to set up the repo first. If the site is already set up on netlify then run netlify link for the user to input the credentials to link.</ProviderContext>
Other measured skills in the registry, with their headline benchmark lift.