Tutoriel Polar.sh 2026 : Construire un SaaS avec facturation en tant que marchand officiel dans Next.js

AI Bot
Par AI Bot ·

Chargement du lecteur de synthèse vocale...

Si vous avez déjà tenté de lancer un SaaS mondial en tant que fondateur solo, vous connaissez le piège. Le produit prend deux week-ends, mais la facturation prend trois mois. Stripe gère les cartes, mais vous devez quand même vous enregistrer à la TVA dans quinze juridictions, déposer la taxe de vente trimestrielle en Californie et au Texas, envoyer les 1099-K à l'IRS et garder un avocat fiscaliste en numérotation rapide. Polar.sh renverse complètement la situation. Au lieu d'être un processeur de paiement, Polar agit comme marchand officiel pour vos ventes. Ils sont le vendeur légal. Ils encaissent l'argent, prélèvent la bonne taxe dans chaque pays, la reversent au bon gouvernement et vous paient un montant net dans votre devise locale. Votre seul travail est de livrer le produit.

Dans ce tutoriel, vous allez intégrer Polar.sh dans un SaaS Next.js 15 à partir de zéro. Vous construirez une page de tarification avec trois niveaux, un checkout hébergé, un portail client, une barrière d'abonnement utilisant le middleware, des gestionnaires de webhook soutenus par une base Postgres, du comptage à l'usage pour les appels API et un flux de clé de licence pour les plans auto-hébergés. À la fin, vous aurez une couche de facturation qui passe de votre premier client à Tunis à votre centième client à Tokyo sans jamais déposer une déclaration fiscale étrangère.

Prérequis

Avant de commencer, assurez-vous d'avoir :

  • Node.js 20 ou plus récent installé
  • Un projet Next.js 15 utilisant l'App Router (ou suivez l'étape de configuration ci-dessous)
  • Un compte Polar.sh sur polar.sh (gratuit, environ trois minutes)
  • Une base de données Postgres (Neon, Supabase ou Docker local)
  • Une connaissance de base de TypeScript, des React Server Components et des webhooks
  • Optionnel : ngrok ou un tunnel similaire pour tester les webhooks localement

Ce que vous allez construire

À la fin de ce tutoriel, vous aurez :

  1. Une organisation Polar.sh avec trois produits d'abonnement et un compteur de paiement à l'usage
  2. Une application Next.js 15 avec une page de tarification utilisant Polar Checkout pour les mises à niveau
  3. Un endpoint webhook qui synchronise les abonnements et les commandes avec votre propre base de données
  4. Une route de portail client permettant aux utilisateurs de mettre à jour les méthodes de paiement et d'annuler
  5. Un middleware qui protège les routes premium en fonction du statut d'abonnement
  6. Un flux de facturation à l'usage qui mesure les appels API et facture par unité
  7. Un système de clés de licence pour les clients achetant un plan à vie auto-hébergé

Commençons par comprendre pourquoi le marchand officiel est important avant d'écrire une seule ligne de code.

Pourquoi le marchand officiel bat le DIY Stripe pour la plupart des SaaS

Lorsque vous prenez les paiements directement via Stripe, vous êtes le vendeur. Cela signifie que les obligations légales et fiscales reposent sur vous. Dans l'UE, vous devez la TVA sur chaque vente B2C et vous devez déposer une déclaration OSS trimestrielle. Aux États-Unis, vous devez la taxe de vente dans chaque État où vous avez un nexus économique, qui se déclenche à seulement cent transactions dans certains États. Au Royaume-Uni, en Australie, en Inde et au Japon, il existe des règles équivalentes. La plupart des fondateurs solos ignorent tout cela jusqu'à ce qu'un avis fiscal arrive deux ans plus tard, moment où les pénalités dépassent largement les revenus.

Un marchand officiel comme Polar prend en charge cette responsabilité. Ils s'enregistrent dans chaque juridiction, calculent le bon taux par panier, facturent le client, reversent à l'autorité fiscale et absorbent les rétrofacturations. Vous vendez à Polar. Polar vend à votre client. Vous obtenez un seul 1099 d'une seule entité américaine et un paiement net. Le compromis est sur les frais : Polar facture environ quatre pour cent plus quarante centimes, contre environ trois pour cent pour Stripe. Pour la plupart des micro-SaaS, cette majoration est moins chère qu'une heure de comptable.

Polar cible spécifiquement les développeurs. L'API est open source, les pages de tarification sont basées sur des composants, et l'ensemble du produit est construit sur Stripe en arrière-plan, donc la fiabilité est identique. Ils prennent en charge les abonnements, les produits uniques, le comptage à l'usage, les clés de licence et les téléchargements numériques d'origine. Si vous êtes en dessous de deux millions de dollars par an et que vous lancez un SaaS ou un produit numérique, Polar est presque toujours le bon choix.

Étape 1 : Initialiser un projet Next.js 15

Si vous avez déjà un projet Next.js, passez à la suite. Sinon, créez-en un nouveau avec TypeScript, Tailwind et l'App Router.

npx create-next-app@latest polar-saas \
  --typescript --tailwind --app --src-dir --import-alias "@/*"
cd polar-saas

Installez les dépendances dont vous aurez besoin tout au long du tutoriel. Le SDK Polar est le client TypeScript officiel, Drizzle est un ORM léger qui correspond à ce style de schéma piloté par webhook, et pg est le pilote Postgres.

npm install @polar-sh/sdk @polar-sh/nextjs zod
npm install drizzle-orm pg
npm install --save-dev drizzle-kit @types/pg tsx

Créez un fichier .env.local à la racine avec des espaces réservés. Vous les remplirez à l'étape suivante.

POLAR_ACCESS_TOKEN=
POLAR_ORGANIZATION_ID=
POLAR_WEBHOOK_SECRET=
POLAR_ENVIRONMENT=sandbox
DATABASE_URL=postgres://user:pass@localhost:5432/polar_saas
NEXT_PUBLIC_BASE_URL=http://localhost:3000

Le drapeau POLAR_ENVIRONMENT est important. Polar exécute un sandbox complet sur sandbox.polar.sh qui reflète la production. Développez toujours contre le sandbox jusqu'à ce que votre flux soit solide, puis basculez la variable sur production.

Étape 2 : Configurer votre organisation Polar

Inscrivez-vous sur polar.sh et cliquez sur Create Organization. Choisissez un identifiant comme your-company ; il apparaît dans votre URL de checkout. Passez en mode développeur dans les paramètres, puis allez sur Sandbox à sandbox.polar.sh et créez la même organisation là-bas. Vous travaillerez dans le sandbox pour le reste du tutoriel.

Dans Sandbox, naviguez vers Settings, puis Tokens, et créez un nouveau Personal Access Token avec les portées products:read, products:write, subscriptions:read, orders:read, customers:read, customer_sessions:write et webhooks:write. Copiez le token dans POLAR_ACCESS_TOKEN. Récupérez l'ID de l'organisation depuis la barre d'URL (l'UUID après /dashboard/) et collez-le dans POLAR_ORGANIZATION_ID.

Maintenant créez trois produits d'abonnement. Allez dans Products, cliquez sur New, et ajoutez :

  1. Starter à neuf dollars par mois, récurrent
  2. Pro à vingt-neuf dollars par mois, récurrent, avec une variante annuelle à vingt-cinq pour cent de réduction
  3. Lifetime à quatre cent quatre-vingt-dix-neuf dollars, paiement unique, marqué comme licence auto-hébergée

Pour chaque produit, cliquez sur l'onglet API à l'intérieur de la page du produit et copiez l'ID du produit. Vous référencerez ces ID dans votre code plutôt que de coder en dur les prix, ce qui vous garde flexible si vous changez de tarification plus tard.

Étape 3 : Mettre en place le schéma de base de données

Créez src/db/schema.ts. L'objectif est de refléter les parties de Polar dont votre application se soucie : clients, abonnements et une table d'usage pour le comptage. Vous n'avez pas besoin de refléter les produits, car ils sont lus directement depuis Polar via le SDK.

import { pgTable, text, timestamp, integer, jsonb } from "drizzle-orm/pg-core";
 
export const customers = pgTable("customers", {
  id: text("id").primaryKey(),
  polarCustomerId: text("polar_customer_id").notNull().unique(),
  email: text("email").notNull(),
  createdAt: timestamp("created_at").defaultNow().notNull(),
});
 
export const subscriptions = pgTable("subscriptions", {
  id: text("id").primaryKey(),
  customerId: text("customer_id").references(() => customers.id).notNull(),
  productId: text("product_id").notNull(),
  status: text("status").notNull(),
  currentPeriodEnd: timestamp("current_period_end").notNull(),
  metadata: jsonb("metadata"),
});
 
export const usageEvents = pgTable("usage_events", {
  id: text("id").primaryKey(),
  customerId: text("customer_id").notNull(),
  meterId: text("meter_id").notNull(),
  units: integer("units").notNull(),
  ingestedAt: timestamp("ingested_at").defaultNow().notNull(),
});
 
export const licenseKeys = pgTable("license_keys", {
  id: text("id").primaryKey(),
  key: text("key").notNull().unique(),
  customerId: text("customer_id").notNull(),
  productId: text("product_id").notNull(),
  activations: integer("activations").default(0).notNull(),
  maxActivations: integer("max_activations").default(3).notNull(),
});

Connectez le client Drizzle dans src/db/index.ts afin que les server components et les route handlers puissent importer une instance unique.

import { drizzle } from "drizzle-orm/node-postgres";
import { Pool } from "pg";
import * as schema from "./schema";
 
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
export const db = drizzle(pool, { schema });

Ajoutez une configuration Drizzle à la racine du projet et exécutez la migration initiale.

npx drizzle-kit push --dialect postgresql --schema ./src/db/schema.ts

Étape 4 : Construire la page de tarification

Les pages de tarification sont la plus grande fuite dans la plupart des entonnoirs SaaS, donc cela vaut la peine de bien le faire. Le motif ci-dessous récupère les produits en direct depuis Polar au moment de la requête, ce qui signifie qu'un changement de prix dans le tableau de bord est livré instantanément sans redéploiement.

Créez src/lib/polar.ts pour centraliser le client Polar.

import { Polar } from "@polar-sh/sdk";
 
export const polar = new Polar({
  accessToken: process.env.POLAR_ACCESS_TOKEN!,
  server: process.env.POLAR_ENVIRONMENT === "production" ? "production" : "sandbox",
});

Maintenant, construisez la page de tarification en tant que Server Component dans src/app/pricing/page.tsx. L'endpoint de liste des produits pagine, alors passez toujours un ID d'organisation et une limite pour garder la réponse rapide.

import { polar } from "@/lib/polar";
import { CheckoutButton } from "./checkout-button";
 
export default async function PricingPage() {
  const { result } = await polar.products.list({
    organizationId: process.env.POLAR_ORGANIZATION_ID!,
    isArchived: false,
    limit: 20,
  });
 
  return (
    <main className="mx-auto max-w-5xl px-6 py-16">
      <h1 className="text-4xl font-semibold mb-12 text-center">Pricing</h1>
      <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
        {result.items.map((product) => (
          <div key={product.id} className="rounded-2xl border p-6">
            <h2 className="text-xl font-semibold">{product.name}</h2>
            <p className="text-sm text-gray-600 mt-2">{product.description}</p>
            <p className="text-3xl font-bold mt-4">
              ${(product.prices[0].priceAmount ?? 0) / 100}
              <span className="text-base text-gray-500">
                {product.prices[0].type === "recurring" ? "/mo" : ""}
              </span>
            </p>
            <CheckoutButton productId={product.id} />
          </div>
        ))}
      </div>
    </main>
  );
}

Le bouton de checkout est un Client Component qui ouvre le checkout hébergé de Polar dans une iframe intégrée. C'est le plus grand gain UX par rapport à une redirection hors de votre domaine, car les taux d'abandon chutent d'environ vingt pour cent lorsque les utilisateurs restent sur la page.

"use client";
 
import { useState } from "react";
 
export function CheckoutButton({ productId }: { productId: string }) {
  const [loading, setLoading] = useState(false);
 
  async function handleClick() {
    setLoading(true);
    const res = await fetch("/api/checkout", {
      method: "POST",
      body: JSON.stringify({ productId }),
    });
    const { url } = await res.json();
    window.location.href = url;
  }
 
  return (
    <button
      onClick={handleClick}
      disabled={loading}
      className="mt-6 w-full rounded-lg bg-black text-white py-2 font-medium"
    >
      {loading ? "Loading..." : "Subscribe"}
    </button>
  );
}

Étape 5 : Créer le route handler de checkout

La route checkout crée une session Polar Checkout et renvoie l'URL hébergée. Passez customerExternalId afin que lorsque le webhook se déclenche plus tard, vous puissiez faire correspondre le client Polar avec votre propre enregistrement utilisateur sans recherche supplémentaire.

Créez src/app/api/checkout/route.ts.

import { polar } from "@/lib/polar";
import { NextRequest, NextResponse } from "next/server";
 
export async function POST(req: NextRequest) {
  const { productId } = await req.json();
 
  const checkout = await polar.checkouts.create({
    products: [productId],
    successUrl: `${process.env.NEXT_PUBLIC_BASE_URL}/dashboard?checkout_id={CHECKOUT_ID}`,
    customerExternalId: "user_abc123",
    metadata: { source: "pricing_page" },
  });
 
  return NextResponse.json({ url: checkout.url });
}

En production, remplacez le customerExternalId codé en dur par l'ID utilisateur authentifié depuis votre fournisseur d'authentification, qu'il s'agisse de Clerk, Better Auth ou NextAuth. La variable de modèle {CHECKOUT_ID} est remplacée par Polar après le paiement, ce qui permet à la page de succès de confirmer la commande sans faire confiance à une chaîne de requête contrôlée par l'utilisateur.

Étape 6 : Gérer les webhooks pour la synchronisation des abonnements

Les webhooks sont la seule façon fiable de garder votre base de données synchronisée avec Polar. Le polling est fragile et sujet aux conditions de concurrence. Le SDK Polar fournit un assistant de style Express qui vérifie les signatures à l'aide de HMAC, donc vous n'avez pas à le réimplémenter vous-même.

Créez src/app/api/webhooks/polar/route.ts.

import { Webhooks } from "@polar-sh/nextjs";
import { db } from "@/db";
import { customers, subscriptions } from "@/db/schema";
 
export const POST = Webhooks({
  webhookSecret: process.env.POLAR_WEBHOOK_SECRET!,
 
  onSubscriptionCreated: async (payload) => {
    const sub = payload.data;
    await db.insert(customers).values({
      id: sub.customer.externalId ?? sub.customer.id,
      polarCustomerId: sub.customer.id,
      email: sub.customer.email,
    }).onConflictDoNothing();
 
    await db.insert(subscriptions).values({
      id: sub.id,
      customerId: sub.customer.externalId ?? sub.customer.id,
      productId: sub.productId,
      status: sub.status,
      currentPeriodEnd: new Date(sub.currentPeriodEnd!),
    });
  },
 
  onSubscriptionUpdated: async (payload) => {
    const sub = payload.data;
    await db.update(subscriptions)
      .set({
        status: sub.status,
        currentPeriodEnd: new Date(sub.currentPeriodEnd!),
      })
      .where((s, { eq }) => eq(s.id, sub.id));
  },
 
  onSubscriptionCanceled: async (payload) => {
    await db.update(subscriptions)
      .set({ status: "canceled" })
      .where((s, { eq }) => eq(s.id, payload.data.id));
  },
 
  onOrderCreated: async (payload) => {
    console.log("One-time order received:", payload.data.id);
  },
});

Pour enregistrer cette URL avec Polar, allez dans Settings, Webhooks, et ajoutez https://your-domain.com/api/webhooks/polar avec tous les événements d'abonnement et de commande sélectionnés. Copiez la clé de signature dans POLAR_WEBHOOK_SECRET. Pour le développement local, exécutez ngrok et pointez-le vers le port 3000, puis enregistrez l'URL ngrok temporairement.

ngrok http 3000

Polar réessaie les livraisons de webhook échouées avec un backoff exponentiel pendant jusqu'à vingt-quatre heures, mais vous devriez quand même traiter chaque gestionnaire comme idempotent. La clause onConflictDoNothing et le motif update ci-dessus sont tous deux sûrs à exécuter deux fois.

Étape 7 : Protéger les routes premium avec le middleware

Une base de données d'abonnements est inutile si vous ne la vérifiez pas réellement. Le middleware Next.js s'exécute avant chaque requête, ce qui en fait le bon endroit pour appliquer les paywalls sans disperser les vérifications dans les pages. Créez src/middleware.ts.

import { NextRequest, NextResponse } from "next/server";
import { db } from "@/db";
import { subscriptions } from "@/db/schema";
import { eq, and, gte } from "drizzle-orm";
 
const PROTECTED_PATHS = ["/dashboard/pro", "/api/pro"];
 
export async function middleware(req: NextRequest) {
  if (!PROTECTED_PATHS.some((p) => req.nextUrl.pathname.startsWith(p))) {
    return NextResponse.next();
  }
 
  const userId = req.cookies.get("user_id")?.value;
  if (!userId) return NextResponse.redirect(new URL("/login", req.url));
 
  const active = await db.select().from(subscriptions).where(
    and(
      eq(subscriptions.customerId, userId),
      eq(subscriptions.status, "active"),
      gte(subscriptions.currentPeriodEnd, new Date()),
    )
  );
 
  if (active.length === 0) {
    return NextResponse.redirect(new URL("/pricing", req.url));
  }
 
  return NextResponse.next();
}
 
export const config = {
  matcher: ["/dashboard/pro/:path*", "/api/pro/:path*"],
};

Notez que le middleware s'exécute par défaut sur le runtime Edge, ce qui signifie que vous ne pouvez pas utiliser le pilote pg standard. Pour la compatibilité Edge, remplacez le pool Drizzle par le pilote HTTP Neon ou poussez la vérification d'authentification vers un Route Handler. Le correctif le plus simple pendant le développement est d'ajouter export const runtime = "nodejs" si vous exécutez le middleware sur Node 20.

Étape 8 : Intégrer le portail client

Lorsqu'un client veut mettre à jour sa carte ou annuler, vous n'avez pas besoin de construire cette interface. Polar fournit un portail client hébergé qui gère les méthodes de paiement, les factures, les changements de plan et les annulations. Générez une URL signée à usage unique et redirigez.

Créez src/app/api/portal/route.ts.

import { polar } from "@/lib/polar";
import { NextRequest, NextResponse } from "next/server";
 
export async function POST(req: NextRequest) {
  const { customerId } = await req.json();
 
  const session = await polar.customerSessions.create({
    customerExternalId: customerId,
  });
 
  return NextResponse.json({ url: session.customerPortalUrl });
}

L'URL de session est à usage unique et expire dans une heure. Générez-la toujours à la demande côté serveur plutôt que de la mettre en cache. Côté client, un seul bouton suffit.

"use client";
export function PortalButton({ customerId }: { customerId: string }) {
  return (
    <button onClick={async () => {
      const res = await fetch("/api/portal", {
        method: "POST",
        body: JSON.stringify({ customerId }),
      });
      const { url } = await res.json();
      window.open(url, "_blank");
    }}>
      Manage subscription
    </button>
  );
}

Étape 9 : Ajouter la facturation à l'usage avec les Meters

Pour les produits IA et les API, les abonnements forfaitaires laissent de l'argent sur la table. Les Polar Meters vous permettent de facturer par unité, avec un palier gratuit et un tarif de dépassement, le tout réglé sur la prochaine facture. Dans le Sandbox, allez dans Meters, cliquez sur New Meter, nommez-le api_calls et définissez l'agrégation à sum de units. Attachez le compteur à votre produit Pro comme prix mesuré à un cent par appel après les premiers dix mille appels gratuits par mois.

Maintenant, ingérez les événements depuis votre API. Créez src/lib/meter.ts.

import { polar } from "@/lib/polar";
 
export async function recordUsage(
  customerExternalId: string,
  units: number,
) {
  await polar.events.ingest({
    events: [
      {
        name: "api_calls",
        externalCustomerId: customerExternalId,
        metadata: { units },
      },
    ],
  });
}

Appelez recordUsage depuis n'importe quelle route qui consomme une ressource facturable. Polar déduplique par ID d'événement pendant une heure, donc les nouvelles tentatives d'un client instable ne facturent pas en double. La prochaine facture inclut automatiquement la ligne de dépassement mesuré ; vous n'avez rien à calculer ni à facturer vous-même.

Étape 10 : Émettre des clés de licence pour les plans à vie

Certains acheteurs veulent un paiement unique avec un binaire ou une bibliothèque auto-hébergée. Polar émet des clés de licence nativement. Lorsque vous créez le produit Lifetime, activez License Keys et définissez la limite d'activation à trois machines par clé.

Dans votre gestionnaire de webhook, écoutez onOrderCreated et persistez la clé émise.

onOrderCreated: async (payload) => {
  const order = payload.data;
  const benefit = order.items[0]?.benefits.find((b) => b.type === "license_keys");
  if (!benefit?.licenseKey) return;
 
  await db.insert(licenseKeys).values({
    id: benefit.licenseKey.id,
    key: benefit.licenseKey.key,
    customerId: order.customer.externalId ?? order.customer.id,
    productId: order.productId,
    maxActivations: 3,
  });
},

Ensuite, exposez un endpoint de validation que votre CLI ou application auto-hébergée peut atteindre. Polar gère le gros du travail via licenseKeys.validate.

import { polar } from "@/lib/polar";
 
export async function POST(req: NextRequest) {
  const { key, instanceId } = await req.json();
  try {
    const result = await polar.licenseKeys.validate({
      key,
      activationId: instanceId,
    });
    return NextResponse.json({ valid: true, expiresAt: result.expiresAt });
  } catch {
    return NextResponse.json({ valid: false }, { status: 403 });
  }
}

Tester votre implémentation

Lancez le serveur de développement et parcourez le flux complet de bout en bout.

npm run dev

Ouvrez /pricing et cliquez sur Subscribe sur le palier Starter. Utilisez la carte de test Polar sandbox 4242 4242 4242 4242 avec n'importe quelle date d'expiration future et CVC. Complétez le checkout. Vous devriez être redirigé vers /dashboard, et votre terminal devrait afficher le webhook qui frappe onSubscriptionCreated. Interrogez votre Postgres local pour confirmer qu'une ligne a atterri à la fois dans customers et subscriptions.

Maintenant, accédez directement à /dashboard/pro. Le middleware devrait vous laisser passer car votre abonnement est actif. Ouvrez le tableau de bord Polar sandbox, trouvez le client et annulez l'abonnement. En quelques secondes, votre ligne de base de données locale est mise à jour à canceled, et la prochaine requête vers /dashboard/pro redirige vers la tarification.

Pour le comptage, exécutez un script qui appelle recordUsage dix mille et une fois. Vérifiez le tableau de bord Polar, consultez le client et vérifiez que le compteur affiche un cent en frais en attente. La prochaine facture inclura automatiquement cet élément de ligne.

Dépannage

La vérification de la signature webhook échoue. Vérifiez deux fois que vous avez copié la clé de signature depuis le même environnement d'où vous envoyez. Sandbox et production ont des clés différentes, et les mélanger est la cause la plus courante.

Le checkout renvoie un 422. Polar exige que le produit ait au moins un prix publié. Si vous créez un produit mais ne cliquez jamais sur Publish, l'endpoint de checkout le refuse. Confirmez que le produit est marqué comme Active dans le tableau de bord.

L'email du client est manquant dans le webhook. Cela se produit lorsqu'un checkout se termine sans email collecté, généralement à cause d'une intégration personnalisée qui a contourné le formulaire. Définissez toujours customerEmail lors de la création du checkout si vous l'avez depuis votre propre système d'authentification.

Le middleware expire à la périphérie. Les requêtes de base de données depuis le middleware doivent utiliser des pilotes basés sur HTTP comme Neon ou Turso. Les pilotes de pool de connexions comme pg ne fonctionnent que dans le runtime Node, que le middleware n'utilise pas par défaut.

Étapes suivantes

  • Connectez Polar avec Better Auth en utilisant le plugin Polar Better Auth pour éviter de construire votre propre mappage utilisateur-client
  • Ajoutez un programme de parrainage en utilisant les fonctionnalités d'affiliation de Polar pour des commissions récurrentes
  • Auto-hébergez une vitrine communautaire en utilisant le starter Next.js open source de Polar
  • Passez du sandbox à la production en basculant POLAR_ENVIRONMENT et en enregistrant l'URL de webhook en direct
  • Lisez notre guide d'intégration Stripe pour comparer avec l'approche DIY si votre revenu dépasse deux millions

Conclusion

Vous avez maintenant une couche de facturation complète pour un SaaS mondial sans jamais toucher à un formulaire fiscal. Polar.sh gère la charge légale et de conformité tout en exposant un SDK convivial pour les développeurs qui s'intègre naturellement dans les motifs Next.js 15 : Server Components pour la page de tarification, Route Handlers pour le checkout et les webhooks, et middleware pour les paywalls. Le même motif passe d'un projet parallèle avec un client à une véritable entreprise avec dix mille. La seule chose qu'il reste à construire, c'est le produit lui-même.


Vous voulez lire plus de tutoriels? Découvrez notre dernier tutoriel sur Maîtriser la prise de notes avec FlutterFlow et Supabase : Un guide complet.

Discutez de votre projet avec nous

Nous sommes ici pour vous aider avec vos besoins en développement Web. Planifiez un appel pour discuter de votre projet et comment nous pouvons vous aider.

Trouvons les meilleures solutions pour vos besoins.

Articles connexes

Construire un Starter Kit SaaS avec Next.js 15, Stripe et Auth.js v5

Apprenez a construire une application SaaS prete pour la production avec Next.js 15, Stripe pour la facturation par abonnement, et Auth.js v5 pour l'authentification. Ce tutoriel pas a pas couvre la configuration du projet, la connexion OAuth, les plans tarifaires, la gestion des webhooks et les routes protegees.

35 min read·

Construire un Agent IA Autonome avec Agentic RAG et Next.js

Apprenez a construire un agent IA qui decide de maniere autonome quand et comment recuperer des informations depuis des bases de donnees vectorielles. Un guide pratique complet avec Vercel AI SDK et Next.js, accompagne d'exemples executables.

30 min read·