Netlify
The modern web development platform for deploying and hosting websites.
Quick Start
Install CLI:
bash
1npm install -g netlify-cli
Login:
Deploy:
Deploy to production:
bash
1netlify 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
toml
1[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:
bash
1netlify env:set MY_VAR "value"
2netlify env:list
3netlify env:get MY_VAR
4netlify env:unset MY_VAR
Context-Specific Variables
toml
1# 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
javascript
1// 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
javascript
1// 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
typescript
1// 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
typescript
1// 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
javascript
1// 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
typescript
1// 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
typescript
1// 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
toml
1# 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
toml
1[[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"] }
html
1<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>
tsx
1function 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}
Configure in Dashboard: Forms > [Form Name] > Settings > Notifications
Identity (Auth)
Setup
html
1<!-- Add to HTML -->
2<script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
JavaScript API
javascript
1import 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();
bash
1# Install
2netlify lm:install
3
4# Setup
5netlify lm:setup
6
7# Track files
8git lfs track "*.jpg" "*.png" "*.gif"
Blobs (Storage)
typescript
1// 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
bash
1# 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