Stack · Vercel

Vercel è il flusso di deploy per cui Next.js è stato progettato, configurato per restare prevedibile

Preview URL su ogni PR, edge runtime dove paga, revalidation on-demand che svuota la cache esattamente quando il contenuto cambia. Progettiamo il deploy Vercel così la fattura è qualcosa su cui pianifichi, non qualcosa che scopri.

Perché questo stack

01

Il deploy è git push, non un rituale di CI

Un merge su main innesca una build, le build emettono deploy immutabili, il deploy precedente resta vivo finché quello nuovo non è pronto. Niente script CI da mantenere, niente immagine Docker da pushare, niente panico di rollback alle 11 di sera. Un deploy sbagliato è un click indietro al commit precedente.

02

I preview URL per PR sono la feature decisiva per la review del cliente

Ogni PR riceve una URL unica con l'app intera che gira su una copia del database dove la punti. Gli stakeholder cliccano un link e vedono la modifica prima del merge, i designer confrontano fianco a fianco, lo scambio che prima richiedeva cinque email diventa un thread di commenti sulla PR.

03

Edge runtime dove conta, Node dove ha senso

Auth check, rewrite di locale, rate limit e personalizzazione girano in edge per un first byte sotto i 100ms. I webhook Stripe, gli upload di file e tutto ciò che ha bisogno della API Node completa restano sul runtime Node. La scelta è per route, non per app.

04

ISR con revalidation on-demand

Le pagine vengono renderizzate una volta, servite dalla cache in edge, rigenerate quando il contenuto cambia davvero. Un webhook dal tuo CMS chiama `revalidatePath` per la route esatta; la cache cade, la prossima richiesta ricostruisce. Niente rebuild notturno via cron, niente tentativi di invalidazione cache.

05

Il costo è prevedibile quando lo progetti

La famosa fattura Vercel è quello che succede quando un team la tratta come una scatola magica. Progettiamo il deploy così il costo vive in tre posti (esecuzione delle funzioni, banda, ottimizzazione immagini), con una soglia di alert su ciascuno. La fattura diventa una voce di budget, non una sorpresa trimestrale.

Cosa sviluppiamo con questa tecnologia

Setup del progetto Vercel

Environment (production, preview, development), env var sincronizzate, configurazione domini, redirect e header di sicurezza in `vercel.json`.

Workflow dei preview URL

Integrazione GitHub con branch protection, commenti di preview sulle PR, deploy summary postati su Slack o Linear dove lavora il team.

Configurazione edge runtime per route

Le route che colpiscono API esterne e leggono il database girano su Node; quelle che personalizzano solo gli header o fanno rewrite semplici girano in edge.

ISR + revalidation on-demand

Cache TTL lunghi sulle pagine di contenuto, revalidation innescata da webhook collegati al CMS o a Supabase, `revalidatePath` e `revalidateTag` nelle Server Action.

Ottimizzazione immagini collegata bene

`next/image` con `sizes` espliciti, `deviceSizes` e `imageSizes` tarati, allowlist dei pattern remoti, AVIF dove paga.

Edge Config per i feature flag

Letture sub-millisecondo dei feature flag da qualunque punto dell'app, niente servizio extra da gestire, pattern di rollout graduale collegati.

Cron job

Task schedulati definiti in `vercel.json` con handler che deduplica, timeout settati per job, alerting sui fallimenti.

Log Drain verso lo stack di observability

Log delle funzioni in stream verso Datadog, Axiom o destinazione scelta, logging strutturato dall'applicazione che emette JSON, request ID tracciati dall'inizio alla fine.

Analytics + Speed Insights

Vercel Analytics per le page view, Speed Insights per i Core Web Vitals per route, entrambi collegati ad alert quando una release peggiora.

Domini custom, redirect, header

Setup multi-dominio per multi-locale, redirect 301 dalle vecchie URL, header CSP e HSTS configurati in `vercel.json`.

Monitoring costi + alerting

API di usage di Vercel interrogata ogni giorno, alert per categoria (esecuzione funzioni, banda, ottimizzazione immagini), report di trend mensili.

Migrazione da Netlify, Heroku, AWS

Deploy esistenti mappati agli equivalenti Vercel, env var migrate, pipeline CI/CD semplificate, vecchia infrastruttura dismessa con piano di cutover.

Una config di deploy Vercel-native con edge, ISR e revalidation in un unico progetto

Un `vercel.json` che definisce header, redirect e cron; un `next.config.ts` con strategia immagini e cache; un route handler che gira in edge per l'auth; una Server Action che chiama `revalidatePath` quando il contenuto cambia. Quattro file; copre il deploy in produzione senza segreti.

La maggior parte delle guide "deploy su Vercel" si ferma a premere il pulsante. Il Vercel in produzione è una config che progetti. I quattro file qui sotto sono quello che rilasciamo: un vercel.json con header, redirect e cron; un next.config.ts con la strategia di cache scritta nero su bianco; una route in edge che fa auth in meno di 50ms di first byte; e una Server Action che fa revalidate della path giusta quando il contenuto cambia.

1. La config vercel.json

La config di produzione vive nel source control. Header, redirect, cron e rewrite sono rivedibili, diff-abili e legati al commit che li ha introdotti.

// vercel.json
{
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        {
          "key": "Strict-Transport-Security",
          "value": "max-age=63072000; includeSubDomains; preload"
        },
        {
          "key": "X-Content-Type-Options",
          "value": "nosniff"
        },
        {
          "key": "Referrer-Policy",
          "value": "strict-origin-when-cross-origin"
        }
      ]
    },
    {
      "source": "/_next/static/(.*)",
      "headers": [
        {
          "key": "Cache-Control",
          "value": "public, max-age=31536000, immutable"
        }
      ]
    }
  ],
  "redirects": [
    {
      "source": "/blog/old-slug",
      "destination": "/blog/new-slug",
      "permanent": true
    }
  ],
  "crons": [
    {
      "path": "/api/cron/reconcile-stripe",
      "schedule": "0 3 * * *"
    },
    {
      "path": "/api/cron/refresh-sitemap",
      "schedule": "0 4 * * *"
    }
  ]
}

2. La strategia di cache di Next.js

Il next.config.ts rende esplicita la strategia di cache: ISR per le pagine di contenuto, nessuna cache per le route autenticate, ottimizzazione immagini tarata sui breakpoint reali che il design system usa.

// next.config.ts
import type { NextConfig } from 'next'

const config: NextConfig = {
  images: {
    formats: ['image/avif', 'image/webp'],
    deviceSizes: [360, 640, 768, 1024, 1280, 1536, 1920],
    imageSizes: [16, 32, 48, 64, 96, 128, 256],
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'images.example.com',
        pathname: '/uploads/**',
      },
    ],
  },
  experimental: {
    // Cache ISR di lunga durata per il blog; flush on-demand via webhook.
    isrFlushToDisk: true,
  },
  async headers() {
    return [
      {
        source: '/api/:path*',
        headers: [{ key: 'Cache-Control', value: 'no-store' }],
      },
    ]
  },
}

export default config

3. La route in edge

L'auth check gira in edge in millisecondi. La route legge il cookie di sessione, lo valida contro una chiave pubblica JWT (niente round-trip al database) e o rewrite verso l'applicazione o redirect a login.

// app/api/auth/check/route.ts
import { NextResponse } from 'next/server'
import { jwtVerify } from 'jose'

export const runtime = 'edge'

const PUBLIC_KEY = process.env.SESSION_PUBLIC_KEY!

export async function GET(request: Request) {
  const cookie = request.headers.get('cookie')
  const token = cookie?.match(/session=([^;]+)/)?.[1]
  if (!token) return NextResponse.json({ ok: false }, { status: 401 })

  try {
    const { payload } = await jwtVerify(
      token,
      new TextEncoder().encode(PUBLIC_KEY),
    )
    return NextResponse.json({ ok: true, userId: payload.sub })
  } catch {
    return NextResponse.json({ ok: false }, { status: 401 })
  }
}

4. Revalidation on-demand da una Server Action

Quando un editor di contenuti pubblica un post, la Server Action scrive nel database e chiama revalidatePath per la route esatta. La versione in cache cade; la prossima richiesta ricostruisce e ri-mette in cache. Niente rebuild notturno.

// app/admin/posts/actions.ts
'use server'

import { revalidatePath } from 'next/cache'
import { createServerClient } from '@/lib/supabase/server'

export async function publishPost(postId: string): Promise<{ ok: true } | { ok: false; error: string }> {
  const supabase = await createServerClient()

  const { data, error } = await supabase
    .from('posts')
    .update({ status: 'published', published_at: new Date().toISOString() })
    .eq('id', postId)
    .select('slug, locale')
    .single()

  if (error) return { ok: false, error: error.message }

  // Droppa la cache per questo post esatto e per l'indice del locale.
  revalidatePath(`/${data.locale}/blog/${data.slug}`)
  revalidatePath(`/${data.locale}/blog`)

  return { ok: true }
}

5. Cosa ti compra questo

Il deploy è un git push. La preview è una URL che salta fuori sulla PR. L'auth check risponde in 30 millisecondi. La cache del blog si rigenera nel momento in cui un editor preme publish, non in un cron notturno. La fattura atterra dove te l'aspetti perché ogni decisione di cache vive nel source control dove puoi verificarla.

Il Vercel che si prende la cattiva reputazione è quello configurato per caso. Il Vercel che merita il suo posto è quello progettato, con intenzione, tre o quattro file alla volta.

Domande frequenti

Vercel o Node self-hosted?

Vercel di default per l'esperienza di deploy, l'edge runtime, i preview URL e la feature parity con Next.js. Self-hosted su Node quando l'ambiente di procurement richiede on-premise, quando i costi di egress dominerebbero, o quando c'è un team ops interno con capacità. Il codice applicativo resta portabile; cambia solo il target di deploy.

Come tenete la fattura Vercel prevedibile?

Tre punti di disciplina. Esecuzione funzioni: tieni i Server Component veloci, evita lavoro pesante nel request path, manda i task lenti su job in background. Banda: cache aggressiva sulle pagine, ottimizza le immagini, usa una CDN per gli asset statici grandi. Ottimizzazione immagini: `sizes` espliciti ovunque, AVIF dove paga, allowlist dei pattern remoti stretta.

Il free tier va bene per la produzione?

Per un side project e una SaaS piccola, spesso sì. Per qualunque cosa con traffico vero, il piano Pro si ripaga in postazioni, banda e ottimizzazione immagini incluse. Modelliamo il costo nella fase di scoping basandoci sul traffico atteso, non sull'ottimismo.

E la banda a scala?

Il pricing della banda di Vercel è lineare; la trappola sono gli asset non ottimizzati. Accoppiamo Vercel con Cloudflare R2 per i file statici grandi, taratura corretta di `next/image`, cache su tutto quello che è cacheabile. La banda diventa una voce più piccola dell'esecuzione funzioni in molti progetti.

Quanto è ampia la rete edge?

L'edge di Vercel gira su più regioni nel mondo. Per la maggior parte dei progetti è più che sufficiente. Per ragioni specifiche di compliance (data residency UE su ogni richiesta) impostiamo regioni esplicite e documentiamo il trade-off.

Quando ricorrete a infrastruttura custom?

Quando il workload è davvero incompatibile col serverless: job in background di lunga durata, connessioni WebSocket persistenti che vivono oltre una funzione, uso pesante di memoria o GPU. In quei casi mettiamo il workload su un host dedicato e teniamo l'applicazione Next.js su Vercel.

Quanto dura la migrazione da Netlify o Heroku?

Una-due settimane per un'applicazione media. Il cutover in sé è un giorno con prep DNS prima. Il lavoro più grosso è riscrivere le pipeline CI/CD (spesso più semplici su Vercel), riorganizzare l'inventario delle env var e ricontrollare redirect e header. Lo facciamo come singolo ingaggio a scope fisso.

Raccontaci il tuo deploy Vercel

Una call di scoping, un numero concreto nella prima risposta, niente recite da agenzia. Nuovi deploy e migrazioni da Netlify, Heroku o AWS entrambi benvenuti.