Netlify Lambda Functions Tutorial
By Flavio Copes
Learn how to create a modern Netlify Function with TypeScript, Web Request and Response APIs, custom routing, local testing, and environment variables.
Netlify Functions add server-side endpoints to a site without you managing a server.
A modern function receives a standard Web API Request, gets Netlify-specific information from a Context, and returns a Response.
The old callback-based exports.handler syntax still appears in many tutorials, but new functions should use a default export.
Create the project
Start in an existing site or create a small project:
npm init -y
npm install @netlify/functions
npm install --save-dev netlify-cli
Netlify’s default functions directory is netlify/functions/.
Create netlify/functions/hello.mts:
import type { Config, Context } from '@netlify/functions'
export default async (request: Request, context: Context) => {
const name = new URL(request.url).searchParams.get('name') ?? 'friend'
return Response.json({
message: `Hello, ${name}!`,
requestId: context.requestId
})
}
export const config: Config = {
path: '/api/hello',
method: 'GET'
}
The config export gives the function a clean route. Without a custom path, a function named hello is available at /.netlify/functions/hello.
The functions overview documents the current handler and routing APIs.
Run the function locally
Start Netlify’s local development environment:
npx netlify dev
Call the function from a browser or another terminal:
curl "http://localhost:8888/api/hello?name=Flavio"
The port can differ if it is already in use. Use the URL printed by Netlify CLI.
Read request data
The handler receives a standard Request, so you use familiar Web APIs.
Read the HTTP method:
request.method
Read a header:
request.headers.get('authorization')
Parse JSON from a request body:
const data = await request.json()
Read query parameters:
const url = new URL(request.url)
const page = url.searchParams.get('page')
Validate untrusted input before using it. Return a clear 400 response when the request is invalid.
Return responses
Return plain text:
return new Response('Created', {
status: 201
})
Return JSON:
return Response.json(
{ error: 'Not found' },
{ status: 404 }
)
Return a method error and advertise the supported method:
return new Response('Method not allowed', {
status: 405,
headers: {
Allow: 'POST'
}
})
The method field in the function config can restrict which methods route to the handler, but your application should still return intentional responses for the methods it supports.
Use path parameters
Configure a dynamic path:
import type { Config, Context } from '@netlify/functions'
export default async (request: Request, context: Context) => {
return Response.json({
id: context.params.id
})
}
export const config: Config = {
path: '/api/items/:id',
method: 'GET'
}
A request to /api/items/42 sets context.params.id to 42.
Store secrets as environment variables
Set a secret through the Netlify UI or CLI:
npx netlify env:set API_KEY "your-secret-value" \
--secret \
--scope functions
Read it only in server-side code:
const apiKey = process.env.API_KEY
The value passed on the command line may remain in shell history. For sensitive production values, prefer the Netlify UI or another approved secret-management workflow.
Do not commit .env files containing secrets. Do not return secrets to the browser or expose them through environment-variable prefixes intended for client-side code.
Netlify documents function scopes and configuration in its environment variable guide.
Deploy the function
Commit the function with the rest of the site. A Git-connected Netlify project bundles and deploys it during the normal deploy.
For a manual draft deploy:
npx netlify deploy
Publish only after testing the draft:
npx netlify deploy --prod
Open the deploy summary to verify that Netlify detected the function.
When to write a raw Netlify Function
Write a function directly when you need a standalone API endpoint, webhook, scheduled task, or background task.
Frameworks such as Next.js, Astro, Nuxt, and SvelteKit often generate functions through their Netlify adapters. In that case, use the framework’s route APIs for normal application pages and endpoints instead of duplicating the routing layer.
Start with Netlify’s function setup guide and check the current runtime limits before designing long-running or large-payload work.
Related posts about services: