Netlify Deployment Samples

Netlify deployment configuration examples including netlify.toml, edge functions, and form handling

Key Facts

Category
Deployment
Items
4
Format Families
sample

Sample Overview

Netlify deployment configuration examples including netlify.toml, edge functions, and form handling This sample set belongs to Deployment and can be used to test related workflows inside Elysia Tools.

💻 Netlify Basic Configuration toml

🟢 simple

Basic Netlify configuration with build settings, redirects, and headers

⏱️ 10 min 🏷️ netlify, configuration, deployment
Prerequisites: Netlify basics, TOML syntax, Static site concepts
[build]
  publish = "build"
  command = "npm run build"
  functions = "functions"

[build.environment]
  NODE_VERSION = "18"
  NPM_VERSION = "9"

[[redirects]]
  from = "/api/*"
  to = "/.netlify/functions/:splat"
  status = 200

[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200

[[headers]]
  for = "/*"
  [headers.values]
    X-Frame-Options = "DENY"
    X-XSS-Protection = "1; mode=block"
    X-Content-Type-Options = "nosniff"
    Referrer-Policy = "strict-origin-when-cross-origin"

[[headers]]
  for = "/static/*"
  [headers.values]
    Cache-Control = "public, max-age=31536000, immutable"

[context.production]
  command = "npm run build:prod"

[context.deploy-preview]
  command = "npm run build:preview"

💻 Netlify Next.js Configuration toml

🟡 intermediate ⭐⭐⭐

Optimized Netlify configuration for Next.js applications with ISR and edge functions

⏱️ 20 min 🏷️ netlify, next.js, framework
Prerequisites: Next.js, Netlify plugin system, Edge functions
[build]
  publish = ".next"
  command = "npm run build"
  environment = { NODE_VERSION = "18" }

[[plugins]]
  package = "@netlify/plugin-nextjs"

[[redirects]]
  from = "/_next/static/*"
  to = "/_next/static/:splat"
  status = 200
  force = true

[[redirects]]
  from = "/api/*"
  to = "/.netlify/functions/:splat"
  status = 200

[[redirects]]
  from = "/_next/data/*/blog/*.json"
  to = "/.netlify/functions/__ isr-blog?slug=:splat&:splat"
  status = 200

[[redirects]]
  from = "/blog/*"
  to = "/.netlify/functions/__ isr-blog?slug=:splat"
  status = 200

[[headers]]
  for = "/api/*"
  [headers.values]
    Access-Control-Allow-Origin = "*"
    Access-Control-Allow-Methods = "GET, POST, PUT, DELETE, OPTIONS"
    Access-Control-Allow-Headers = "Content-Type, Authorization"

[[headers]]
  for = "/_next/static/*"
  [headers.values]
    Cache-Control = "public, max-age=31536000, immutable"

[[headers]]
  for = "/_next/image/*"
  [headers.values]
    Cache-Control = "public, max-age=86400, must-revalidate"

[context.production.environment]
  NEXT_PUBLIC_API_URL = "https://api.example.com"
  NEXT_PUBLIC_SITE_URL = "https://example.com"

[context.branch-deploy.environment]
  NEXT_PUBLIC_API_URL = "https://dev-api.example.com"
  NEXT_PUBLIC_SITE_URL = "https://dev--example.netlify.app"

[context.deploy-preview.environment]
  NEXT_PUBLIC_API_URL = "https://preview-api.example.com"
  NEXT_PUBLIC_SITE_URL = "https://deploy-preview-1--example.netlify.app"

[functions]
  node_version = "18"

[[functions]]
  directory = "functions"
  node_bundler = "esbuild"

[[edge_functions]]
  function = "geo-redirect"
  path = "/geo-check"

💻 Netlify Edge Functions javascript

🟡 intermediate ⭐⭐⭐⭐

Edge functions examples for geolocation, A/B testing, and custom middleware

⏱️ 30 min 🏷️ netlify, edge functions, middleware
Prerequisites: JavaScript, Edge computing concepts, Netlify edge functions
// Netlify Edge Functions Examples

// 1. Geolocation-based redirect
// edge-functions/geo-redirect.js
export const geoRedirectEdgeFunction = async (request, context) => {
  const url = new URL(request.url);
  const country = request.geo?.country?.code?.toLowerCase();

  // Redirect based on country
  if (country === 'us') {
    const usUrl = new URL('/us', url);
    return Response.redirect(usUrl, 302);
  } else if (country === 'uk') {
    const ukUrl = new URL('/uk', url);
    return Response.redirect(ukUrl, 302);
  } else if (country === 'de') {
    const deUrl = new URL('/de', url);
    return Response.redirect(deUrl, 302);
  }

  // Add country data to headers
  const response = await context.next();
  response.headers.set('x-user-country', country || 'unknown');

  return response;
};

// 2. A/B testing edge function
// edge-functions/ab-test.js
export const abTestEdgeFunction = async (request, context) => {
  const url = new URL(request.url);

  // Skip A/B test for API routes
  if (url.pathname.startsWith('/api/')) {
    return context.next();
  }

  // Check for existing A/B test variant
  const variant = request.headers.get('x-ab-variant') ||
                  Math.random() < 0.5 ? 'A' : 'B';

  // Redirect to variant-specific path
  if (variant === 'B' && !url.pathname.includes('/variant-b')) {
    const variantUrl = new URL('/variant-b' + url.pathname, url);
    const response = Response.redirect(variantUrl, 302);
    response.headers.set('x-ab-variant', variant);
    return response;
  }

  const response = await context.next();
  response.headers.set('x-ab-variant', variant);

  return response;
};

// 3. Authentication middleware
// edge-functions/auth.js
export const authEdgeFunction = async (request, context) => {
  const url = new URL(request.url);

  // Skip auth for public routes
  const publicPaths = ['/login', '/signup', '/forgot-password', '/api/auth'];
  if (publicPaths.some(path => url.pathname.startsWith(path))) {
    return context.next();
  }

  // Check for authentication token
  const authCookie = request.headers.get('cookie')?.split(';')
    ?.find(cookie => cookie.trim().startsWith('auth_token='))
    ?.split('=')[1];

  if (!authCookie) {
    // Redirect to login
    const loginUrl = new URL('/login', url);
    loginUrl.searchParams.set('redirect', url.pathname);
    return Response.redirect(loginUrl, 302);
  }

  // Validate token (mock validation)
  try {
    const isValid = await validateToken(authCookie);
    if (!isValid) {
      throw new Error('Invalid token');
    }

    // Add user info to headers for downstream functions
    const response = await context.next();
    response.headers.set('x-user-authenticated', 'true');
    return response;

  } catch (error) {
    const loginUrl = new URL('/login', url);
    loginUrl.searchParams.set('error', 'invalid_token');
    loginUrl.searchParams.set('redirect', url.pathname);
    return Response.redirect(loginUrl, 302);
  }
};

async function validateToken(token) {
  // Mock validation - replace with real token validation
  return token.length > 10;
}

// 4. Rate limiting edge function
// edge-functions/rate-limit.js
export const rateLimitEdgeFunction = async (request, context) => {
  const url = new URL(request.url);
  const clientIP = request.headers.get('x-nf-client-connection-ip') ||
                  request.headers.get('x-forwarded-for') ||
                  'unknown';

  // Simple rate limiting logic (in production, use Redis or similar)
  const RATE_LIMIT = 100; // requests per minute
  const key = `rate-limit-${clientIP}`;

  // This is a mock implementation
  // In production, you'd use a proper rate limiting store
  const now = Date.now();
  const windowStart = now - 60000; // 1 minute ago

  // Check rate limit (mock logic)
  const requestCount = await getRequestCount(key, windowStart);

  if (requestCount >= RATE_LIMIT) {
    return new Response('Rate limit exceeded', {
      status: 429,
      headers: {
        'Retry-After': '60',
        'Content-Type': 'text/plain'
      }
    });
  }

  // Increment request count
  await incrementRequestCount(key);

  const response = await context.next();
  response.headers.set('x-rate-limit-remaining', String(RATE_LIMIT - requestCount));

  return response;
};

// Mock functions for rate limiting (replace with real implementation)
async function getRequestCount(key, windowStart) {
  // Mock implementation
  return Math.floor(Math.random() * 150);
}

async function incrementRequestCount(key) {
  // Mock implementation
  return Promise.resolve();
}

// 5. Content personalization edge function
// edge-functions/personalize.js
export const personalizeEdgeFunction = async (request, context) => {
  const url = new URL(request.url);

  // Skip personalization for API routes
  if (url.pathname.startsWith('/api/')) {
    return context.next();
  }

  // Get user preferences from cookie or headers
  const preferences = getUserPreferences(request);

  const response = await context.next();

  // Inject personalization script
  const personalizationScript = `
    <script>
      window.userPreferences = ${JSON.stringify(preferences)};
      // Trigger personalization
      window.dispatchEvent(new CustomEvent('userPreferencesLoaded', {
        detail: window.userPreferences
      }));
    </script>
  `;

  // Insert script before closing body tag
  const html = await response.text();
  const personalizedHtml = html.replace(
    '</body>',
    personalizationScript + '</body>'
  );

  return new Response(personalizedHtml, {
    headers: response.headers
  });
};

function getUserPreferences(request) {
  const cookieHeader = request.headers.get('cookie') || '';

  // Parse preferences from cookies
  const preferences = {
    theme: 'light',
    language: 'en',
    region: 'us'
  };

  cookieHeader.split(';').forEach(cookie => {
    const [name, value] = cookie.trim().split('=');
    if (name === 'theme') preferences.theme = value || 'light';
    if (name === 'language') preferences.language = value || 'en';
    if (name === 'region') preferences.region = value || 'us';
  });

  // Override with geo data if available
  if (request.geo?.country?.code) {
    preferences.region = request.geo.country.code.toLowerCase();
  }

  return preferences;
}

// 6. Content security policy edge function
// edge-functions/csp.js
export const geoRedirectWithATesting = async (request, context) => {
  const response = await context.next();

  // Set Content Security Policy headers
  const csp = [
    "default-src 'self'",
    "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net https://vercel.live",
    "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
    "font-src 'self' https://fonts.gstatic.com",
    "img-src 'self' data: https: blob:",
    "connect-src 'self' https://api.example.com",
    "frame-ancestors 'none'",
    "base-uri 'self'",
    "form-action 'self'"
  ].join('; ');

  response.headers.set('Content-Security-Policy', csp);
  response.headers.set('X-Content-Type-Options', 'nosniff');
  response.headers.set('X-Frame-Options', 'DENY');
  response.headers.set('X-XSS-Protection', '1; mode=block');
  response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');

  return response;
};

💻 Netlify Forms and Analytics html

🔴 complex ⭐⭐⭐⭐

Complete forms handling, analytics tracking, and automation workflows

⏱️ 40 min 🏷️ netlify, forms, analytics, frontend
Prerequisites: HTML, JavaScript, Netlify forms, Analytics
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Netlify Forms & Analytics Example</title>
    <style>
        .form-container {
            max-width: 600px;
            margin: 2rem auto;
            padding: 2rem;
            border: 1px solid #ddd;
            border-radius: 8px;
        }
        .form-group {
            margin-bottom: 1rem;
        }
        label {
            display: block;
            margin-bottom: 0.5rem;
            font-weight: bold;
        }
        input, textarea, select {
            width: 100%;
            padding: 0.5rem;
            border: 1px solid #ccc;
            border-radius: 4px;
        }
        button {
            background: #007cba;
            color: white;
            padding: 0.75rem 1.5rem;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }
        button:hover {
            background: #005a87;
        }
        .form-netlify {
            display: none;
        }
        .analytics-data {
            background: #f5f5f5;
            padding: 1rem;
            border-radius: 4px;
            margin: 2rem 0;
        }
    </style>
</head>
<body>
    <!-- 1. Contact Form with Netlify Forms -->
    <div class="form-container">
        <h2>Contact Form</h2>
        <form name="contact" method="POST" data-netlify="true" netlify-honeypot="bot-field">
            <!-- Hidden field for spam protection -->
            <input type="hidden" name="form-name" value="contact">
            <div class="form-netlify">
                <label>Don't fill this out if you're human: <input name="bot-field" /></label>
            </div>

            <div class="form-group">
                <label for="name">Name *</label>
                <input type="text" id="name" name="name" required>
            </div>

            <div class="form-group">
                <label for="email">Email *</label>
                <input type="email" id="email" name="email" required>
            </div>

            <div class="form-group">
                <label for="subject">Subject</label>
                <input type="text" id="subject" name="subject">
            </div>

            <div class="form-group">
                <label for="message">Message *</label>
                <textarea id="message" name="message" rows="5" required></textarea>
            </div>

            <div class="form-group">
                <label for="interest">Area of Interest</label>
                <select id="interest" name="interest">
                    <option value="">Select an option</option>
                    <option value="web-development">Web Development</option>
                    <option value="mobile-apps">Mobile Apps</option>
                    <option value="consulting">Consulting</option>
                    <option value="other">Other</option>
                </select>
            </div>

            <div class="form-group">
                <label>
                    <input type="checkbox" name="newsletter" value="yes">
                    Subscribe to newsletter
                </label>
            </div>

            <button type="submit">Send Message</button>
        </form>
    </div>

    <!-- 2. File Upload Form -->
    <div class="form-container">
        <h2>File Upload Form</h2>
        <form name="upload" method="POST" data-netlify="true" enctype="multipart/form-data">
            <input type="hidden" name="form-name" value="upload">

            <div class="form-group">
                <label for="file-name">Name</label>
                <input type="text" id="file-name" name="name" required>
            </div>

            <div class="form-group">
                <label for="file-email">Email</label>
                <input type="email" id="file-email" name="email" required>
            </div>

            <div class="form-group">
                <label for="file">Upload File (max 2MB)</label>
                <input type="file" id="file" name="file" accept=".pdf,.doc,.docx,.txt" required>
            </div>

            <div class="form-group">
                <label for="description">Description</label>
                <textarea id="description" name="description" rows="3"></textarea>
            </div>

            <button type="submit">Upload File</button>
        </form>
    </div>

    <!-- 3. Multi-step Form with Progressive Enhancement -->
    <div class="form-container">
        <h2>Multi-step Registration Form</h2>
        <form name="registration" method="POST" data-netlify="true">
            <input type="hidden" name="form-name" value="registration">

            <!-- Step 1: Basic Information -->
            <div id="step-1" class="form-step">
                <h3>Step 1: Basic Information</h3>
                <div class="form-group">
                    <label for="reg-name">Full Name *</label>
                    <input type="text" id="reg-name" name="full_name" required>
                </div>

                <div class="form-group">
                    <label for="reg-email">Email Address *</label>
                    <input type="email" id="reg-email" name="email_address" required>
                </div>

                <div class="form-group">
                    <label for="reg-phone">Phone Number</label>
                    <input type="tel" id="reg-phone" name="phone_number">
                </div>

                <button type="button" onclick="nextStep(2)">Next</button>
            </div>

            <!-- Step 2: Professional Information -->
            <div id="step-2" class="form-step" style="display: none;">
                <h3>Step 2: Professional Information</h3>
                <div class="form-group">
                    <label for="company">Company</label>
                    <input type="text" id="company" name="company">
                </div>

                <div class="form-group">
                    <label for="position">Position</label>
                    <input type="text" id="position" name="position">
                </div>

                <div class="form-group">
                    <label for="experience">Years of Experience</label>
                    <select id="experience" name="experience">
                        <option value="0-1">0-1 years</option>
                        <option value="2-5">2-5 years</option>
                        <option value="6-10">6-10 years</option>
                        <option value="10+">10+ years</option>
                    </select>
                </div>

                <button type="button" onclick="nextStep(1)">Previous</button>
                <button type="button" onclick="nextStep(3)">Next</button>
            </div>

            <!-- Step 3: Preferences -->
            <div id="step-3" class="form-step" style="display: none;">
                <h3>Step 3: Preferences</h3>
                <div class="form-group">
                    <label for="interests">Areas of Interest</label>
                    <div>
                        <label>
                            <input type="checkbox" name="interests" value="design"> Design
                        </label>
                        <label>
                            <input type="checkbox" name="interests" value="development"> Development
                        </label>
                        <label>
                            <input type="checkbox" name="interests" value="marketing"> Marketing
                        </label>
                    </div>
                </div>

                <div class="form-group">
                    <label for="hear-about">How did you hear about us?</label>
                    <select id="hear-about" name="hear_about">
                        <option value="">Select an option</option>
                        <option value="search">Search Engine</option>
                        <option value="social">Social Media</option>
                        <option value="referral">Referral</option>
                        <option value="advertisement">Advertisement</option>
                        <option value="other">Other</option>
                    </select>
                </div>

                <div class="form-group">
                    <label for="comments">Additional Comments</label>
                    <textarea id="comments" name="comments" rows="4"></textarea>
                </div>

                <button type="button" onclick="nextStep(2)">Previous</button>
                <button type="submit">Submit Registration</button>
            </div>
        </form>
    </div>

    <!-- 4. Analytics Data Display -->
    <div class="analytics-data">
        <h3>Real-time Analytics Data</h3>
        <div id="visitor-info">
            <p><strong>Location:</strong> <span id="location">Loading...</span></p>
            <p><strong>Device:</strong> <span id="device">Loading...</span></p>
            <p><strong>Browser:</strong> <span id="browser">Loading...</span></p>
            <p><strong>Session ID:</strong> <span id="session-id">Loading...</span></p>
        </div>
    </div>

    <!-- Netlify Analytics Script -->
    <script>
        // Initialize Netlify Analytics
        if (typeof netlifyAnalytics !== 'undefined') {
            netlifyAnalytics.on('routeChange', ({ path }) => {
                console.log('Route changed to:', path);
            });
        }
    </script>

    <!-- 5. Form Handling Script -->
    <script>
        // Multi-step form logic
        function nextStep(stepNumber) {
            // Hide all steps
            document.querySelectorAll('.form-step').forEach(step => {
                step.style.display = 'none';
            });

            // Show selected step
            document.getElementById(`step-${stepNumber}`).style.display = 'block';
        }

        // Form submission handling
        document.querySelectorAll('form').forEach(form => {
            form.addEventListener('submit', function(e) {
                // Show loading state
                const submitBtn = this.querySelector('button[type="submit"]');
                const originalText = submitBtn.textContent;
                submitBtn.textContent = 'Submitting...';
                submitBtn.disabled = true;

                // Track form submission
                if (typeof netlifyAnalytics !== 'undefined') {
                    netlifyAnalytics.track({
                        eventName: 'form_submission',
                        data: {
                            formName: this.getAttribute('name'),
                            timestamp: new Date().toISOString()
                        }
                    });
                }

                // Let the form submit normally to Netlify
                setTimeout(() => {
                    submitBtn.textContent = originalText;
                    submitBtn.disabled = false;
                }, 3000);
            });
        });

        // Load visitor information
        async function loadVisitorInfo() {
            try {
                // Simulate visitor data (in real app, this would come from Netlify Functions)
                const visitorData = {
                    location: await getLocation(),
                    device: getDeviceInfo(),
                    browser: getBrowserInfo(),
                    sessionId: getSessionId()
                };

                document.getElementById('location').textContent = visitorData.location;
                document.getElementById('device').textContent = visitorData.device;
                document.getElementById('browser').textContent = visitorData.browser;
                document.getElementById('session-id').textContent = visitorData.sessionId;
            } catch (error) {
                console.error('Error loading visitor info:', error);
            }
        }

        async function getLocation() {
            // In production, you'd use Netlify Functions to get geo data
            // For now, return a mock location
            return 'San Francisco, CA, USA';
        }

        function getDeviceInfo() {
            const userAgent = navigator.userAgent;
            if (/Mobile|Android|iPhone|iPad/.test(userAgent)) {
                return 'Mobile';
            } else if (/Tablet/.test(userAgent)) {
                return 'Tablet';
            } else {
                return 'Desktop';
            }
        }

        function getBrowserInfo() {
            const userAgent = navigator.userAgent;
            if (userAgent.includes('Chrome')) return 'Chrome';
            if (userAgent.includes('Firefox')) return 'Firefox';
            if (userAgent.includes('Safari')) return 'Safari';
            if (userAgent.includes('Edge')) return 'Edge';
            return 'Unknown';
        }

        function getSessionId() {
            // Get or create session ID from local storage
            let sessionId = localStorage.getItem('netlify_session_id');
            if (!sessionId) {
                sessionId = 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
                localStorage.setItem('netlify_session_id', sessionId);
            }
            return sessionId;
        }

        // Load visitor info when page loads
        document.addEventListener('DOMContentLoaded', loadVisitorInfo);

        // Track page view
        if (typeof netlifyAnalytics !== 'undefined') {
            netlifyAnalytics.track({
                eventName: 'page_view',
                data: {
                    path: window.location.pathname,
                    title: document.title,
                    timestamp: new Date().toISOString()
                }
            });
        }

        // Track form interactions
        document.querySelectorAll('input, textarea, select').forEach(field => {
            field.addEventListener('focus', function() {
                if (typeof netlifyAnalytics !== 'undefined') {
                    netlifyAnalytics.track({
                        eventName: 'form_field_focus',
                        data: {
                            fieldName: this.name,
                            fieldType: this.type,
                            timestamp: new Date().toISOString()
                        }
                    });
                }
            });
        });
    </script>
</body>
</html>