Intermediate
How to Set Up Netlify Functions on Netlify
Quick Answer
Create a netlify/functions directory with JavaScript handler files, configure netlify.toml with your functions path, and deploy via Git or CLI. Functions automatically deploy with your site and are accessible at /.netlify/functions/. Test locally using netlify dev before deploying to production.
Prerequisites
- Netlify account created at app.netlify.com
- Node.js (version 16+) and npm installed
- Netlify CLI installed globally via npm
- Git repository (GitHub, GitLab, or Bitbucket)
- Basic familiarity with JavaScript and command line
1
Install Netlify CLI and Initialize Your Project
Install the Netlify CLI globally on your machine using
npm install -g netlify-cli. Create a new project directory and navigate into it with mkdir my-netlify-functions && cd my-netlify-functions. Initialize npm in your project root with npm init -y to create a package.json file with default values. This sets up the foundation for your serverless functions project.Tip
Verify your Netlify CLI installation with netlify --version to ensure it's properly installed.
2
Create the Functions Directory Structure
Create the default functions directory at the project root using
mkdir netlify/functions. Netlify automatically detects this directory during builds without requiring additional configuration. If you prefer a custom directory name (e.g., functions instead of netlify/functions), you'll need to configure it in netlify.toml later. The directory structure should look like: my-netlify-functions/
├── netlify/
│ └── functions/
├── package.json
└── netlify.tomlTip
Use the default netlify/functions directory for zero-config deployment; custom paths require explicit configuration.
3
Write Your First Serverless Function
Create a new file in the functions directory named
hello.mjs (use .mjs for ES modules, which is the required syntax). Add the following handler code: export default async (request, context) => {
return new Response(`Hello, ${context?.identity?.context?.user?.email ?? 'world'}!`, {
headers: { 'Content-Type': 'text/plain' }
});
}; The handler function receives two arguments: request (a web platform Request object containing HTTP details) and context (Netlify metadata including user identity). Your function must export a default handler and return a Response object.Tip
Use .mjs for ES modules, .cjs for CommonJS, or .js if your package.json has type: module configured.
4
Configure netlify.toml for Custom Settings (Optional)
Create a
netlify.toml file in your project root to customize your build and function settings. Add the following configuration: [build]
functions = "netlify/functions"
command = "npm run build"
publish = "dist"
[[redirects]]
from = "/api/*"
to = "/.netlify/functions/:splat"
status = 200 The [build] section specifies your functions directory (change to functions if using a custom path), build command, and publish directory. The [[redirects]] section (optional) routes API requests to your functions. If using the default netlify/functions directory, this file is optional but recommended for clarity.Tip
Set NODE_VERSION = "18" in netlify.toml if your build requires a specific Node.js version.
5
Set Up Local Development Environment
Run
netlify dev (or ntl dev for short) in your project root to start the local development server. This command automatically detects your netlify.toml and package.json configuration. The server will start on http://localhost:8888 by default. Your functions will be accessible at http://localhost:8888/.netlify/functions/hello. Open this URL in your browser to test your function—it should return "Hello, world!" or your email if you're logged in.Tip
Use netlify dev instead of your app's dev server (e.g., npm run dev on port 3000) to avoid CORS issues when testing functions locally.
6
Add Environment Variables for Local Development
Create a
.env file in your project root to store sensitive configuration values like API keys. Add your variables in the format KEY=value, for example: SPOTIFY_CLIENT_ID=your_client_id
SPOTIFY_CLIENT_SECRET=your_secret These variables are automatically loaded into process.env when you run netlify dev. Access them in your functions using process.env.SPOTIFY_CLIENT_ID. Add .env to your .gitignore file to prevent committing secrets to version control.Tip
For production, set environment variables in the Netlify dashboard under Site Settings > Build & Deploy > Environment instead of using .env files.
7
Connect Your Git Repository to Netlify
Log in to your Netlify dashboard at app.netlify.com and click "Add new site" > "Import an existing project". Select your Git provider (GitHub, GitLab, or Bitbucket) and authorize Netlify to access your repositories. Choose the repository containing your functions project. Netlify will automatically detect your netlify.toml configuration and build settings. Review the build command and publish directory, then click "Deploy site". Netlify will now automatically build and deploy your site whenever you push changes to your repository.
Tip
Netlify automatically detects netlify.toml settings; ensure your build command matches your project setup (e.g., npm run build for most frameworks).
8
Deploy Functions and Test in Production
After connecting your Git repository, Netlify automatically builds and deploys your functions with every push to your main branch. Monitor the deployment progress in the Netlify dashboard under "Deploys". Once deployment completes, your functions are live at
https://your-site-name.netlify.app/.netlify/functions/hello. Test your production function by visiting this URL in your browser or using curl: curl https://your-site-name.netlify.app/.netlify/functions/hello Check the deploy logs in the dashboard if your function doesn't work as expected.Tip
View detailed deploy logs by clicking on a deployment in the Netlify dashboard to troubleshoot build or bundling errors.
9
Create Additional Functions and API Routes
Add more functions by creating additional files in your netlify/functions directory. Each file becomes a separate endpoint. For example, create
netlify/functions/users.mjs to handle user data at /.netlify/functions/users. You can handle different HTTP methods (GET, POST, PUT, DELETE) within a single function by checking request.method: export default async (request, context) => {
if (request.method === 'GET') {
return new Response('Get users');
} else if (request.method === 'POST') {
return new Response('Create user');
}
}; Use the optional netlify.toml redirects to create cleaner API routes (e.g., /api/users instead of /.netlify/functions/users).Tip
Function names must use only alphanumeric characters, hyphens, and underscores; avoid spaces and special characters.
10
Access Data Files and External APIs
Netlify Functions can access files within their own folder or subdirectories. If you need to use a JSON data file, place it in your functions directory or a subdirectory. For example, store
db.json in netlify/functions/data/db.json and import it in your function: import db from './data/db.json' assert { type: 'json' };
export default async (request, context) => {
return new Response(JSON.stringify(db), {
headers: { 'Content-Type': 'application/json' }
});
}; Functions cannot access files outside their folder (e.g., ../src/data.json will fail during deployment). For external APIs, use fetch within your function to call third-party services like Spotify or Firebase.Tip
JSON files in the functions directory are included during deployment; files outside the functions folder are not accessible to functions.
Troubleshooting
CORS errors when fetching functions from your frontend
Ensure you're testing with netlify dev on port 8888, not your app's dev server (e.g., port 3000). CORS issues occur when the frontend and functions run on different ports. In production, both are served from the same domain, so CORS is not an issue. Use netlify dev to test the production-like environment locally.
Function returns 404 or 'not found' error
Verify the function file exists in netlify/functions/ with the correct name and extension (.mjs, .cjs, or .js). Check that the filename matches your URL endpoint (e.g., hello.mjs creates /.netlify/functions/hello). Ensure netlify.toml correctly specifies the functions directory. Run netlify dev and check the terminal output for any build errors. If using a custom directory, confirm it's set in netlify.toml under [build] functions = "your-directory".
Environment variables are undefined in production but work locally
Environment variables set in .env only work locally with netlify dev. For production, set variables in the Netlify dashboard under Site Settings > Build & Deploy > Environment variables. Add each variable as a key-value pair. Redeploy your site after adding variables so they're available during the build. Verify variable names match exactly (they're case-sensitive).
Deploy fails with 'Could not resolve' or bundling errors
Check the deploy logs in the Netlify dashboard for specific error messages. Common causes include: importing files outside the functions directory (move them inside), using top-level await in CommonJS files (use .mjs or add type: module to package.json), or missing dependencies (add them to package.json). Ensure your build command in netlify.toml is correct and matches your project setup.
Function works locally but not after deployment
Compare your local environment (netlify dev) with production by checking: (1) Node.js version—set NODE_VERSION in netlify.toml if needed, (2) environment variables—confirm they're set in the dashboard, (3) file paths—ensure relative paths work in the deployed functions directory, (4) dependencies—verify all imports are in package.json. Check the deploy logs for build errors and redeploy after fixes.
Ready to get started with Netlify?
Put this tutorial into practice. Visit Netlify and follow the steps above.
Visit Netlify →