Utilizziamo i cookie per migliorare la tua esperienza sul sito
CodeWorlds
Torna alle collezioni
Guide17 min read

Netlify - Kompletny Przewodnik po Platformie Jamstack

Netlify is the leading platform for hosting and automating Jamstack sites. CI/CD from GitHub, serverless functions, edge computing, backend-free forms, deploy previews, and global CDN.

Netlify - complete guide to the Jamstack platform

Remember when deploying a website meant FTPing files to a server and praying nothing broke? Netlify made that ancient history. With a simple git push, your site builds automatically and deploys to a global CDN in seconds. No servers to manage, no complex CI/CD pipelines to configure, no DevOps degree required. Just push your code and watch it go live.

This guide covers everything from your first deployment to advanced patterns like edge functions, serverless APIs, and sophisticated A/B testing. Whether you're hosting a personal blog or building a production-grade SaaS application, you'll find the tools and techniques you need.

What is Netlify?

Netlify is a pioneering platform that revolutionized the way websites are built and hosted. Founded in 2014 by Mathias Biilmann and Christian Bach, Netlify introduced and popularized the "Jamstack" concept - an architecture based on JavaScript, APIs, and Markup that separates frontend from backend.

Netlify offers a complete ecosystem for building modern web applications: automatic CI/CD from GitHub/GitLab/Bitbucket, global CDN, serverless functions, edge computing, backend-free forms, user authentication, and much more. All of this is accessible from a single dashboard, without the need to manage servers.

The platform gained popularity thanks to its "developer experience first" philosophy - deploying a site is literally git push, and the new version is automatically built and published to the global CDN network. This simplicity has attracted millions of developers and hundreds of thousands of companies worldwide.

History and industry impact

Netlify was founded as an answer to the complexity of traditional web hosting. Mathias Biilmann, formerly CTO of BitBalloon, noticed that developers were spending too much time configuring servers instead of building products.

In 2015, Netlify introduced the term "Jamstack", promoting an architecture where sites are pre-rendered and served from CDN, while dynamic functionality is delivered through APIs and serverless functions. This philosophy changed how people think about web development.

Today, Netlify hosts millions of sites, including projects like React, Vue.js, Kubernetes, and many others. The company has raised over $200 million in funding and is recognized as a leader in the Jamstack platform category.

Why choose Netlify?

Key advantages

  1. Instant deploys - Site on CDN in seconds, atomic deploys
  2. Deploy Previews - Every PR gets a unique preview URL
  3. Serverless Functions - Backend without managing servers
  4. Edge Functions - Logic at the edge, minimal latency
  5. Netlify Forms - Forms without backend code
  6. Split Testing - Native A/B testing
  7. Rollbacks - One click to previous version
  8. Branch deploys - Every branch has its own URL

Netlify vs Vercel vs Cloudflare Pages

FeatureNetlifyVercelCloudflare Pages
Price (hobby)Free tierFree tierFree tier
CI/CD✅ Built-in✅ Built-in✅ Built-in
Serverless Functions✅ Workers
Edge Functions✅ (native)
Forms✅ Native
Identity/Auth✅ Native
Split Testing
Next.js support✅ Best
Build minutes (free)300/mo6000/moUnlimited
Bandwidth (free)100GB100GBUnlimited
Analytics✅ Paid✅ Paid✅ Free

Getting started

Method 1: deploy from Git (recommended)

Code
Bash
# 1. Connect repository
# Go to app.netlify.com → New site from Git → GitHub/GitLab/Bitbucket

# 2. Select repository and branch

# 3. Configure build
Build command: npm run build
Publish directory: dist (or build, out, .next, public)

# 4. Deploy!
# Every push automatically triggers a new deploy

Method 2: Netlify CLI

Code
Bash
# Installation
npm install -g netlify-cli

# Login
netlify login

# Initialize project (in project folder)
netlify init

# Production deploy
netlify deploy --prod

# Deploy preview (test)
netlify deploy

# Development server with Functions
netlify dev

Method 3: drag and drop

Code
Bash
# Simplest way:
# 1. Build site locally: npm run build
# 2. Drag build folder to app.netlify.com/drop
# 3. Done!

Project configuration

netlify.toml (main configuration file)

netlify.toml
TOML
# netlify.toml

# Basic build configuration
[build]
  command = "npm run build"
  publish = "dist"
  functions = "netlify/functions"
  edge_functions = "netlify/edge-functions"

# Environment variables
[build.environment]
  NODE_VERSION = "20"
  NPM_FLAGS = "--legacy-peer-deps"

# Production context
[context.production]
  command = "npm run build"
  environment = { NODE_ENV = "production" }

# Staging context (branch: staging)
[context.staging]
  command = "npm run build:staging"
  environment = { NODE_ENV = "staging" }

# Deploy-preview context (PRs)
[context.deploy-preview]
  command = "npm run build:preview"

# Branch-deploy context (other branches)
[context.branch-deploy]
  command = "npm run build:dev"

# HTTP Headers
[[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"

# Redirects
[[redirects]]
  from = "/old-page"
  to = "/new-page"
  status = 301

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

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

# Proxy to external API
[[redirects]]
  from = "/external-api/*"
  to = "https://api.external.com/:splat"
  status = 200
  force = true

# Edge Functions routing
[[edge_functions]]
  function = "geolocation"
  path = "/api/location"

[[edge_functions]]
  function = "auth"
  path = "/dashboard/*"

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

[[plugins]]
  package = "netlify-plugin-sitemap"

_redirects (alternative)

Code
TEXT
# Simpler syntax for redirects

# 301 Redirect
/old-path /new-path 301

# Redirect with wildcard
/blog/* /articles/:splat 301

# Proxy (preserves original URL)
/api/* /.netlify/functions/:splat 200

# SPA fallback
/* /index.html 200

# Conditional redirect (geo)
/pricing /pricing-us 200 Country=us
/pricing /pricing-eu 200 Country=de,fr,gb

# Conditional redirect (language)
/* /pl/:splat 200 Language=pl
/* /en/:splat 200 Language=en

Netlify Functions

Basic function

TSnetlify/functions/hello.ts
TypeScript
// netlify/functions/hello.ts
import type { Handler, HandlerEvent, HandlerContext } from '@netlify/functions'

export const handler: Handler = async (
  event: HandlerEvent,
  context: HandlerContext
) => {
  const { name = 'World' } = event.queryStringParameters || {}

  return {
    statusCode: 200,
    headers: {
      'Content-Type': 'application/json',
      'Access-Control-Allow-Origin': '*'
    },
    body: JSON.stringify({
      message: `Hello, ${name}!`,
      timestamp: new Date().toISOString()
    })
  }
}

// Call: /.netlify/functions/hello?name=John

POST request with body

TSnetlify/functions/create-user.ts
TypeScript
// netlify/functions/create-user.ts
import type { Handler } from '@netlify/functions'

interface CreateUserBody {
  email: string
  name: string
  password: string
}

export const handler: Handler = async (event) => {
  // Handle CORS preflight
  if (event.httpMethod === 'OPTIONS') {
    return {
      statusCode: 204,
      headers: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Methods': 'POST, OPTIONS',
        'Access-Control-Allow-Headers': 'Content-Type, Authorization'
      },
      body: ''
    }
  }

  if (event.httpMethod !== 'POST') {
    return {
      statusCode: 405,
      body: JSON.stringify({ error: 'Method not allowed' })
    }
  }

  try {
    const body: CreateUserBody = JSON.parse(event.body || '{}')

    // Validation
    if (!body.email || !body.name || !body.password) {
      return {
        statusCode: 400,
        body: JSON.stringify({ error: 'Missing required fields' })
      }
    }

    // User creation logic here
    // e.g., save to database, send email

    return {
      statusCode: 201,
      headers: {
        'Content-Type': 'application/json',
        'Access-Control-Allow-Origin': '*'
      },
      body: JSON.stringify({
        success: true,
        user: {
          id: 'user_' + Date.now(),
          email: body.email,
          name: body.name
        }
      })
    }
  } catch (error) {
    return {
      statusCode: 500,
      body: JSON.stringify({ error: 'Internal server error' })
    }
  }
}

Scheduled Functions (CRON)

TSnetlify/functions/daily-report.ts
TypeScript
// netlify/functions/daily-report.ts
import type { Handler } from '@netlify/functions'

export const handler: Handler = async (event, context) => {
  // Check if this is a scheduled invocation
  const isScheduled = event.headers['x-netlify-scheduled']

  if (!isScheduled) {
    return {
      statusCode: 403,
      body: 'This function can only be triggered by schedule'
    }
  }

  // Report logic
  console.log('Running daily report at', new Date().toISOString())

  // e.g., send email report
  await sendDailyReport()

  return {
    statusCode: 200,
    body: 'Daily report sent'
  }
}

// Configuration in netlify.toml:
// [functions."daily-report"]
//   schedule = "0 8 * * *"  # Daily at 8:00 UTC

Background Functions

TSnetlify/functions/process-webhook-background.ts
TypeScript
// netlify/functions/process-webhook-background.ts
import type { BackgroundHandler } from '@netlify/functions'

// Background functions can run up to 15 minutes
export const handler: BackgroundHandler = async (event, context) => {
  const payload = JSON.parse(event.body || '{}')

  // Long-running operation
  console.log('Processing webhook:', payload.id)

  // e.g., processing large file
  // e.g., sending many emails
  // e.g., syncing with external API

  for (let i = 0; i < payload.items.length; i++) {
    await processItem(payload.items[i])
    console.log(`Processed ${i + 1}/${payload.items.length}`)
  }

  // Background functions don't return a response
  // Caller immediately gets 202 Accepted
}

// Filename must end with -background.ts

Function with database

TSnetlify/functions/users.ts
TypeScript
// netlify/functions/users.ts
import type { Handler } from '@netlify/functions'
import { MongoClient } from 'mongodb'

const client = new MongoClient(process.env.MONGODB_URI!)

export const handler: Handler = async (event) => {
  try {
    await client.connect()
    const db = client.db('myapp')
    const users = db.collection('users')

    switch (event.httpMethod) {
      case 'GET': {
        const allUsers = await users.find({}).toArray()
        return {
          statusCode: 200,
          body: JSON.stringify(allUsers)
        }
      }

      case 'POST': {
        const body = JSON.parse(event.body || '{}')
        const result = await users.insertOne({
          ...body,
          createdAt: new Date()
        })
        return {
          statusCode: 201,
          body: JSON.stringify({ id: result.insertedId })
        }
      }

      default:
        return {
          statusCode: 405,
          body: 'Method not allowed'
        }
    }
  } catch (error) {
    return {
      statusCode: 500,
      body: JSON.stringify({ error: 'Database error' })
    }
  }
}

Edge Functions

Basic Edge Function

TSnetlify/edge-functions/hello.ts
TypeScript
// netlify/edge-functions/hello.ts
import type { Context } from "@netlify/edge-functions"

export default async (request: Request, context: Context) => {
  const url = new URL(request.url)
  const name = url.searchParams.get('name') || 'World'

  return new Response(`Hello from the Edge, ${name}!`, {
    headers: {
      'Content-Type': 'text/plain',
      'X-Edge-Location': context.geo.city || 'unknown'
    }
  })
}

// Configuration in netlify.toml:
// [[edge_functions]]
//   function = "hello"
//   path = "/api/hello"

Geolocation at the Edge

TSnetlify/edge-functions/geolocation.ts
TypeScript
// netlify/edge-functions/geolocation.ts
import type { Context } from "@netlify/edge-functions"

export default async (request: Request, context: Context) => {
  const { geo } = context

  return Response.json({
    city: geo.city,
    country: geo.country?.code,
    countryName: geo.country?.name,
    region: geo.subdivision?.code,
    timezone: geo.timezone,
    latitude: geo.latitude,
    longitude: geo.longitude
  })
}

Edge Function as Middleware

TSnetlify/edge-functions/auth-middleware.ts
TypeScript
// netlify/edge-functions/auth-middleware.ts
import type { Context } from "@netlify/edge-functions"

export default async (request: Request, context: Context) => {
  const authHeader = request.headers.get('Authorization')

  // Check token
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return new Response('Unauthorized', {
      status: 401,
      headers: { 'WWW-Authenticate': 'Bearer' }
    })
  }

  const token = authHeader.substring(7)

  try {
    // Token verification
    const isValid = await verifyToken(token)

    if (!isValid) {
      return new Response('Invalid token', { status: 401 })
    }

    // Continue to original page
    return context.next()
  } catch (error) {
    return new Response('Authentication error', { status: 500 })
  }
}

// Configuration in netlify.toml:
// [[edge_functions]]
//   function = "auth-middleware"
//   path = "/dashboard/*"

A/B Testing at the Edge

TSnetlify/edge-functions/ab-test.ts
TypeScript
// netlify/edge-functions/ab-test.ts
import type { Context } from "@netlify/edge-functions"

export default async (request: Request, context: Context) => {
  // Check if user already has an assigned version
  const cookies = request.headers.get('Cookie') || ''
  const existingVariant = cookies.match(/ab-variant=(\w+)/)?.[1]

  // Assign randomly if none
  const variant = existingVariant || (Math.random() < 0.5 ? 'A' : 'B')

  // Redirect to appropriate version
  const url = new URL(request.url)

  if (variant === 'B') {
    url.pathname = url.pathname.replace('/pricing', '/pricing-new')
  }

  const response = await context.rewrite(url.toString())

  // Set cookie if new user
  if (!existingVariant) {
    response.headers.set(
      'Set-Cookie',
      `ab-variant=${variant}; Path=/; Max-Age=2592000`
    )
  }

  // Add header for analytics
  response.headers.set('X-AB-Variant', variant)

  return response
}

Netlify Forms

Basic HTML form

Code
HTML
<!-- Form with data-netlify="true" -->
<form name="contact" method="POST" data-netlify="true">
  <input type="hidden" name="form-name" value="contact" />

  <label>
    Name:
    <input type="text" name="name" required />
  </label>

  <label>
    Email:
    <input type="email" name="email" required />
  </label>

  <label>
    Message:
    <textarea name="message" required></textarea>
  </label>

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

Form with AJAX (React)

TScomponents/ContactForm.tsx
TypeScript
// components/ContactForm.tsx
import { useState } from 'react'

export function ContactForm() {
  const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle')

  const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault()
    setStatus('loading')

    const form = e.currentTarget
    const formData = new FormData(form)

    try {
      const response = await fetch('/', {
        method: 'POST',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        body: new URLSearchParams(formData as any).toString()
      })

      if (response.ok) {
        setStatus('success')
        form.reset()
      } else {
        setStatus('error')
      }
    } catch (error) {
      setStatus('error')
    }
  }

  return (
    <form
      name="contact"
      method="POST"
      data-netlify="true"
      onSubmit={handleSubmit}
    >
      <input type="hidden" name="form-name" value="contact" />

      <input type="text" name="name" placeholder="Name" required />
      <input type="email" name="email" placeholder="Email" required />
      <textarea name="message" placeholder="Message" required />

      <button type="submit" disabled={status === 'loading'}>
        {status === 'loading' ? 'Sending...' : 'Send'}
      </button>

      {status === 'success' && <p>Thank you for your message!</p>}
      {status === 'error' && <p>An error occurred. Please try again.</p>}
    </form>
  )
}

Form with honeypot (spam protection)

Code
HTML
<form name="contact" method="POST" data-netlify="true" data-netlify-honeypot="bot-field">
  <input type="hidden" name="form-name" value="contact" />

  <!-- Honeypot - hidden field for bots -->
  <p style="display: none;">
    <label>
      Don't fill this out:
      <input name="bot-field" />
    </label>
  </p>

  <input type="text" name="name" required />
  <input type="email" name="email" required />
  <textarea name="message" required></textarea>

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

Netlify Identity

Configuration

Code
JavaScript
// Install Netlify Identity Widget
// npm install netlify-identity-widget

import netlifyIdentity from 'netlify-identity-widget'

// Initialize
netlifyIdentity.init()

// Open login modal
function openLogin() {
  netlifyIdentity.open('login')
}

// Open signup modal
function openSignup() {
  netlifyIdentity.open('signup')
}

// Logout
function logout() {
  netlifyIdentity.logout()
}

// Listen to events
netlifyIdentity.on('login', (user) => {
  console.log('User logged in:', user)
  netlifyIdentity.close()
})

netlifyIdentity.on('logout', () => {
  console.log('User logged out')
})

// Get current user
const user = netlifyIdentity.currentUser()

React Hook for Identity

TShooks/useAuth.ts
TypeScript
// hooks/useAuth.ts
import { useState, useEffect, createContext, useContext } from 'react'
import netlifyIdentity from 'netlify-identity-widget'

interface User {
  id: string
  email: string
  user_metadata: {
    full_name?: string
    avatar_url?: string
  }
  app_metadata: {
    roles?: string[]
  }
  token: {
    access_token: string
    expires_at: number
  }
}

interface AuthContextType {
  user: User | null
  login: () => void
  logout: () => void
  signup: () => void
  isAuthenticated: boolean
}

const AuthContext = createContext<AuthContextType | undefined>(undefined)

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const [user, setUser] = useState<User | null>(null)

  useEffect(() => {
    netlifyIdentity.init()

    netlifyIdentity.on('login', (user) => {
      setUser(user as User)
      netlifyIdentity.close()
    })

    netlifyIdentity.on('logout', () => {
      setUser(null)
    })

    // Check if already logged in
    const currentUser = netlifyIdentity.currentUser()
    if (currentUser) {
      setUser(currentUser as User)
    }
  }, [])

  return (
    <AuthContext.Provider
      value={{
        user,
        login: () => netlifyIdentity.open('login'),
        logout: () => netlifyIdentity.logout(),
        signup: () => netlifyIdentity.open('signup'),
        isAuthenticated: !!user
      }}
    >
      {children}
    </AuthContext.Provider>
  )
}

export function useAuth() {
  const context = useContext(AuthContext)
  if (!context) {
    throw new Error('useAuth must be used within AuthProvider')
  }
  return context
}

Netlify CLI

Installation and setup

Code
Bash
# Global installation
npm install -g netlify-cli

# Login
netlify login

# Status
netlify status

# Link existing site
netlify link

# Create new site
netlify sites:create

Local development

Code
Bash
# Development server with Functions and Edge Functions
netlify dev

# With specific port
netlify dev --port 8888

# With live reload
netlify dev --live

# Functions only
netlify functions:serve

# Test single function
netlify functions:invoke hello --payload '{"name": "John"}'

Deploy commands

Code
Bash
# Deploy preview (draft)
netlify deploy

# Production deploy
netlify deploy --prod

# Deploy from specific folder
netlify deploy --dir=build --prod

# Deploy with message
netlify deploy --prod --message "Release v1.2.3"

# Deploy and open in browser
netlify deploy --prod --open

Environment variables

Code
Bash
# List variables
netlify env:list

# Set variable
netlify env:set API_KEY "secret-key"

# Remove variable
netlify env:unset API_KEY

# Import from .env file
netlify env:import .env

Build Plugins

Popular plugins

netlify.toml
TOML
# netlify.toml

# Next.js support
[[plugins]]
  package = "@netlify/plugin-nextjs"

# Sitemap generator
[[plugins]]
  package = "netlify-plugin-sitemap"
  [plugins.inputs]
    buildDir = "dist"

# Lighthouse CI
[[plugins]]
  package = "@netlify/plugin-lighthouse"
  [plugins.inputs]
    fail_on_grade = "B"

# Cache dependencies
[[plugins]]
  package = "netlify-plugin-cache"
  [plugins.inputs]
    paths = [
      "node_modules",
      ".cache"
    ]

Framework integrations

Next.js

Code
Bash
# Automatic configuration
# Netlify detects Next.js and configures automatically

# netlify.toml
[build]
  command = "npm run build"
  publish = ".next"

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

Astro

Code
Bash
# Install adapter
npm install @astrojs/netlify

# astro.config.mjs
import { defineConfig } from 'astro/config'
import netlify from '@astrojs/netlify'

export default defineConfig({
  output: 'server',  // or 'hybrid'
  adapter: netlify()
})

SvelteKit

Code
Bash
# Install adapter
npm install -D @sveltejs/adapter-netlify

# svelte.config.js
import adapter from '@sveltejs/adapter-netlify'

export default {
  kit: {
    adapter: adapter()
  }
}

Pricing

Free Tier

ResourceLimit
Bandwidth100GB/month
Build minutes300/month
Concurrent builds1
Serverless Functions125K invocations/month
Edge Functions3M invocations/month
Forms100 submissions/month
Identity1000 users
SitesUnlimited

Pro ($19/month per member)

ResourceLimit
Bandwidth1TB/month
Build minutes25,000/month
Concurrent builds3
Serverless Functions125K (included), then $25/1M
Forms1000 submissions/month
AnalyticsIncluded
Background FunctionsIncluded
Priority supportIncluded

Business ($99/month per member)

ResourceLimit
Bandwidth1.5TB/month
Build minutes30,000/month
Concurrent builds5
SAML SSOIncluded
Audit logsIncluded
99.99% SLAIncluded

FAQ - frequently asked questions

Is Netlify free?

Yes, Netlify offers a generous free plan with 100GB bandwidth, 300 build minutes, and basic features. For most hobby projects and small business sites, the Free tier is sufficient.

How do I configure a custom domain?

In the Netlify dashboard: Site settings → Domain management → Add custom domain. Netlify automatically configures SSL certificate (Let's Encrypt). You need to add DNS records at your registrar pointing to Netlify.

How do Serverless Functions vs Edge Functions differ?

Serverless Functions run in AWS Lambda, have access to Node.js, timeout up to 26 seconds (background: 15 min), ideal for APIs and integrations.

Edge Functions run on Deno in the global edge network, have minimal latency (<50ms), 50ms timeout, ideal for personalization, A/B tests, and middleware.

Can I use Netlify for WordPress?

Not directly. Netlify is for static/Jamstack sites. However, you can use WordPress as a headless CMS and generate a static site (e.g., Gatsby, Next.js) deployed to Netlify.

How do I debug Netlify Functions?

  1. Locally: netlify dev runs functions with hot reload
  2. Logs: Functions → Function logs in Netlify dashboard
  3. netlify functions:invoke to test from CLI
  4. Add console.log() - everything goes to logs

Does Netlify support server-side rendering (SSR)?

Yes, through Next.js (with @netlify/plugin-nextjs), Nuxt, SvelteKit, and other frameworks. SSR runs through Serverless Functions. For better performance, consider Edge SSR.

How do I migrate from Vercel to Netlify?

  1. Check vercel.json → convert to netlify.toml
  2. API routes → Netlify Functions
  3. Middleware → Edge Functions
  4. Connect repo to Netlify
  5. Update environment variables
  6. Redirect domain

Summary

Netlify is the pioneering Jamstack platform that revolutionized web development. It offers a complete ecosystem: automatic CI/CD, global CDN, Serverless and Edge Functions, forms, authentication, and much more - all from a single dashboard.

Main advantages of Netlify:

  • Instant deploys - site on CDN in seconds
  • Deploy Previews - every PR has its own URL
  • Zero config - automatic framework detection
  • Edge computing - personalization close to the user
  • Forms & Identity - backend without backend
  • Generous free tier - 100GB bandwidth, 300 build minutes

Whether for a portfolio, business site, SaaS, or enterprise application - Netlify provides reliable infrastructure and excellent developer experience.