From netlify-skills
Guides writing Netlify serverless functions with modern TypeScript syntax, path/method routing, background processing, scheduled tasks, and streaming for API endpoints and server-side logic.
npx claudepluginhub netlify/context-and-tools --plugin netlify-skillsThis skill uses the workspace's default tool permissions.
Always use the modern default export + Config pattern. Never use the legacy `exports.handler` or named `handler` export.
Guides Netlify Edge Functions for middleware with context.next(), geolocation, request/response manipulation, auth checks, A/B testing, and low-latency compute using Deno runtime.
Builds and deploys serverless APIs, full-stack web apps, edge functions, background jobs, and real-time applications using Cloudflare Workers. Supports JavaScript, TypeScript, Python, Rust with Wrangler CLI.
Provides expert guidance on Vercel Serverless Functions, Edge Functions, Fluid Compute, streaming, Cron Jobs, and runtime configuration. Use for configuring, debugging, or optimizing server-side code on Vercel.
Share bugs, ideas, or general feedback.
Always use the modern default export + Config pattern. Never use the legacy exports.handler or named handler export.
import type { Context, Config } from "@netlify/functions";
export default async (req: Request, context: Context) => {
return new Response("Hello, world!");
};
export const config: Config = {
path: "/api/hello",
};
The handler receives a standard Web API Request and returns a Response. The second argument is a Netlify Context object.
Place functions in netlify/functions/:
netlify/functions/
_shared/ # Non-function shared code (underscore prefix)
auth.ts
db.ts
items.ts # -> /.netlify/functions/items (or custom path via config)
users/index.ts # -> /.netlify/functions/users
Use .ts or .mts extensions. If both .ts and .js exist with the same name, the .js file takes precedence.
Define custom paths via the config export:
export const config: Config = {
path: "/api/items", // Static path
// path: "/api/items/:id", // Path parameter
// path: ["/api/items", "/api/items/:id"], // Multiple paths
// excludedPath: "/api/items/special", // Excluded paths
// preferStatic: true, // Don't override static files
};
Without a path config, functions are available at /.netlify/functions/{name}. Setting a path makes the function available only at that path.
Access path parameters via context.params:
// config: { path: "/api/items/:id" }
export default async (req: Request, context: Context) => {
const { id } = context.params;
// ...
};
export default async (req: Request, context: Context) => {
switch (req.method) {
case "GET": return handleGet(context.params.id);
case "POST": return handlePost(await req.json());
case "DELETE": return handleDelete(context.params.id);
default: return new Response("Method not allowed", { status: 405 });
}
};
export const config: Config = {
path: "/api/items/:id",
method: ["GET", "POST", "DELETE"],
};
For long-running tasks (up to 15 minutes). The client receives an immediate 202 response; return values are ignored.
Name the file with a -background suffix:
netlify/functions/process-background.ts
Store results externally (Netlify Blobs, database) for later retrieval.
Run on a cron schedule (UTC timezone):
export default async (req: Request) => {
const { next_run } = await req.json();
console.log("Next invocation at:", next_run);
};
export const config: Config = {
schedule: "@hourly", // or cron: "0 * * * *"
};
Shortcuts: @yearly, @monthly, @weekly, @daily, @hourly. Scheduled functions have a 30-second timeout and only run on published deploys.
Return a ReadableStream body for streamed responses (up to 20 MB):
export default async (req: Request) => {
const stream = new ReadableStream({ /* ... */ });
return new Response(stream, {
headers: { "Content-Type": "text/event-stream" },
});
};
| Property | Description |
|---|---|
context.params | Path parameters from config |
context.geo | { city, country: {code, name}, latitude, longitude, subdivision, timezone, postalCode } |
context.ip | Client IP address |
context.cookies | .get(), .set(), .delete() |
context.deploy | { context, id, published } |
context.site | { id, name, url } |
context.account.id | Team account ID |
context.requestId | Unique request ID |
context.waitUntil(promise) | Extend execution after response is sent |
Use Netlify.env (not process.env) inside functions:
const apiKey = Netlify.env.get("API_KEY");
| Resource | Limit |
|---|---|
| Synchronous timeout | 60 seconds |
| Background timeout | 15 minutes |
| Scheduled timeout | 30 seconds |
| Memory | 1024 MB |
| Buffered payload | 6 MB |
| Streamed payload | 20 MB |
Frameworks with server-side capabilities (Astro, Next.js, Nuxt, SvelteKit, TanStack Start) typically generate their own serverless functions via adapters. You usually do not write raw Netlify Functions in these projects — the framework adapter handles server-side rendering and API routes. Write Netlify Functions directly when:
See the netlify-frameworks skill for adapter setup.