Netlify
The modern web development platform for deploying and hosting websites.
Quick Start
Install CLI:
bash1npm install -g netlify-cli
Login:
bash1netlify login
Deploy:
bash1netlify deploy
Deploy to production:
bash1netlify deploy --prod
Project Setup
Connect Git Repository
- Go to app.netlify.com
- Add new site > Import from Git
- Select repository
- Configure build settings
- Deploy
Drag and Drop
Visit https://app.netlify.com/drop and drag your build folder.
netlify.toml Configuration
toml1[build] 2 command = "npm run build" 3 publish = "dist" 4 functions = "netlify/functions" 5 6[build.environment] 7 NODE_VERSION = "18" 8 9# Production context 10[context.production] 11 command = "npm run build:prod" 12 13# Preview context (branch deploys) 14[context.deploy-preview] 15 command = "npm run build:preview" 16 17# Branch-specific 18[context.staging] 19 command = "npm run build:staging" 20 21# Dev settings 22[dev] 23 command = "npm run dev" 24 port = 3000 25 targetPort = 5173 26 27# Headers 28[[headers]] 29 for = "/*" 30 [headers.values] 31 X-Frame-Options = "DENY" 32 X-XSS-Protection = "1; mode=block" 33 34# Redirects 35[[redirects]] 36 from = "/api/*" 37 to = "/.netlify/functions/:splat" 38 status = 200 39 40[[redirects]] 41 from = "/*" 42 to = "/index.html" 43 status = 200
Environment Variables
Setting Variables
Via Dashboard: Site settings > Environment variables > Add variable
Via CLI:
bash1netlify env:set MY_VAR "value" 2netlify env:list 3netlify env:get MY_VAR 4netlify env:unset MY_VAR
Context-Specific Variables
toml1# netlify.toml 2[context.production.environment] 3 API_URL = "https://api.example.com" 4 5[context.deploy-preview.environment] 6 API_URL = "https://staging-api.example.com" 7 8[context.branch-deploy.environment] 9 API_URL = "https://dev-api.example.com"
Using Variables
javascript1// In build process 2const apiUrl = process.env.API_URL; 3 4// In functions 5export async function handler(event, context) { 6 const secret = process.env.API_SECRET; 7}
Serverless Functions
Basic Function
javascript1// netlify/functions/hello.js 2export async function handler(event, context) { 3 return { 4 statusCode: 200, 5 body: JSON.stringify({ message: 'Hello, World!' }), 6 }; 7}
TypeScript Function
typescript1// netlify/functions/users.ts 2import type { Handler, HandlerEvent, HandlerContext } from '@netlify/functions'; 3 4interface User { 5 id: string; 6 name: string; 7} 8 9const handler: Handler = async (event: HandlerEvent, context: HandlerContext) => { 10 const { httpMethod, body, queryStringParameters } = event; 11 12 if (httpMethod === 'GET') { 13 const users: User[] = await getUsers(); 14 return { 15 statusCode: 200, 16 headers: { 'Content-Type': 'application/json' }, 17 body: JSON.stringify(users), 18 }; 19 } 20 21 if (httpMethod === 'POST') { 22 const data = JSON.parse(body || '{}'); 23 const user = await createUser(data); 24 return { 25 statusCode: 201, 26 body: JSON.stringify(user), 27 }; 28 } 29 30 return { 31 statusCode: 405, 32 body: 'Method Not Allowed', 33 }; 34}; 35 36export { handler };
Scheduled Functions
typescript1// netlify/functions/scheduled.ts 2import { schedule } from '@netlify/functions'; 3 4const handler = async () => { 5 console.log('Running scheduled task'); 6 await runTask(); 7 return { statusCode: 200 }; 8}; 9 10// Run every day at midnight 11export const handler = schedule('0 0 * * *', handler);
Background Functions
javascript1// netlify/functions/background-task-background.js 2// Suffix with -background for async processing 3export async function handler(event, context) { 4 // Long-running task (up to 15 minutes) 5 await processLargeDataset(); 6 7 return { 8 statusCode: 200, 9 }; 10}
Edge Functions
Basic Edge Function
typescript1// netlify/edge-functions/geo.ts 2import type { Context } from '@netlify/edge-functions'; 3 4export default async (request: Request, context: Context) => { 5 const country = context.geo.country?.code ?? 'Unknown'; 6 const city = context.geo.city ?? 'Unknown'; 7 8 return new Response( 9 JSON.stringify({ 10 message: `Hello from ${city}, ${country}!`, 11 }), 12 { 13 headers: { 'Content-Type': 'application/json' }, 14 } 15 ); 16}; 17 18export const config = { path: '/api/geo' };
Edge Function with Middleware Pattern
typescript1// netlify/edge-functions/auth.ts 2import type { Context } from '@netlify/edge-functions'; 3 4export default async (request: Request, context: Context) => { 5 const token = request.headers.get('Authorization'); 6 7 if (!token) { 8 return new Response('Unauthorized', { status: 401 }); 9 } 10 11 // Validate token 12 const user = await validateToken(token); 13 14 if (!user) { 15 return new Response('Invalid token', { status: 403 }); 16 } 17 18 // Continue to origin 19 return context.next(); 20}; 21 22export const config = { path: '/api/*' };
Edge Function Declaration
toml1# netlify.toml 2[[edge_functions]] 3 path = "/api/geo" 4 function = "geo" 5 6[[edge_functions]] 7 path = "/api/*" 8 function = "auth"
Redirects & Rewrites
_redirects File
# Simple redirect
/old-page /new-page 301
# Wildcard redirect
/blog/* /posts/:splat 301
# Rewrite (proxy)
/api/* /.netlify/functions/:splat 200
# SPA fallback
/* /index.html 200
# Conditional redirect
/country/* /us/:splat 200 Country=us
/country/* /uk/:splat 200 Country=gb
netlify.toml Redirects
toml1[[redirects]] 2 from = "/old" 3 to = "/new" 4 status = 301 5 6[[redirects]] 7 from = "/api/*" 8 to = "https://api.example.com/:splat" 9 status = 200 10 force = true 11 12[[redirects]] 13 from = "/*" 14 to = "/index.html" 15 status = 200 16 conditions = { Role = ["admin"] }
Forms
HTML Form
html1<form name="contact" method="POST" data-netlify="true"> 2 <input type="hidden" name="form-name" value="contact" /> 3 <input type="text" name="name" required /> 4 <input type="email" name="email" required /> 5 <textarea name="message" required></textarea> 6 <button type="submit">Send</button> 7</form>
React Form
tsx1function ContactForm() { 2 const [status, setStatus] = useState(''); 3 4 const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => { 5 e.preventDefault(); 6 const form = e.currentTarget; 7 const formData = new FormData(form); 8 9 try { 10 await fetch('/', { 11 method: 'POST', 12 headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, 13 body: new URLSearchParams(formData as any).toString(), 14 }); 15 setStatus('success'); 16 } catch (error) { 17 setStatus('error'); 18 } 19 }; 20 21 return ( 22 <form 23 name="contact" 24 method="POST" 25 data-netlify="true" 26 onSubmit={handleSubmit} 27 > 28 <input type="hidden" name="form-name" value="contact" /> 29 <input type="text" name="name" required /> 30 <input type="email" name="email" required /> 31 <button type="submit">Send</button> 32 </form> 33 ); 34}
Form Notifications
Configure in Dashboard: Forms > [Form Name] > Settings > Notifications
Identity (Auth)
Setup
html1<!-- Add to HTML --> 2<script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
JavaScript API
javascript1import netlifyIdentity from 'netlify-identity-widget'; 2 3netlifyIdentity.init(); 4 5// Open modal 6netlifyIdentity.open(); 7 8// Login 9netlifyIdentity.on('login', user => { 10 console.log('Logged in:', user); 11}); 12 13// Logout 14netlifyIdentity.on('logout', () => { 15 console.log('Logged out'); 16}); 17 18// Get current user 19const user = netlifyIdentity.currentUser();
Large Media (Git LFS)
bash1# Install 2netlify lm:install 3 4# Setup 5netlify lm:setup 6 7# Track files 8git lfs track "*.jpg" "*.png" "*.gif"
Blobs (Storage)
typescript1// netlify/functions/upload.ts 2import { getStore } from '@netlify/blobs'; 3 4export async function handler(event) { 5 const store = getStore('uploads'); 6 7 // Store blob 8 await store.set('file-key', event.body, { 9 metadata: { contentType: 'image/png' }, 10 }); 11 12 // Get blob 13 const blob = await store.get('file-key'); 14 15 // Delete blob 16 await store.delete('file-key'); 17 18 return { statusCode: 200 }; 19}
Local Development
bash1# Start dev server 2netlify dev 3 4# Start with specific port 5netlify dev --port 3000 6 7# Link to site 8netlify link 9 10# Pull environment variables 11netlify env:pull
Best Practices
- Use netlify.toml - Version control your config
- Set up branch deploys - Preview before production
- Use context-specific vars - Different values per environment
- Enable form spam filtering - Protect forms
- Use edge functions - For low-latency operations
Common Mistakes
| Mistake | Fix |
|---|---|
| Missing form-name input | Add hidden input with form name |
| Wrong publish directory | Check framework output folder |
| Functions not found | Use netlify/functions directory |
| Redirects not working | Check order (first match wins) |
| Build failures | Check build logs, Node version |
Reference Files
- references/functions.md - Function patterns
- references/forms.md - Form handling
- references/edge.md - Edge functions