Agrega una tienda en línea a tu app de Next.js con Supabase

Esta guía convierte un proyecto de Next.js (App Router) en una tienda con checkout de Stripe y panel de administración, en unos diez minutos. Al terminar tienes:

Todo vive en tu repo y tu proyecto de Supabase: el esquema, la API (Supabase Edge Functions) y los componentes de la tienda. No hay comisión por venta ni un backend de terceros. Sellbase es open source (MIT).

En inglés: Add an ecommerce store to a Next.js app with Supabase.

¿Por qué no hacerlo a mano?

La receta de siempre es una tabla products en Supabase, una Server Action que crea la sesión de Stripe Checkout y una ruta de webhook que guarda el pedido. Sirve para la primera venta. Después la tienda también necesita:

Sellbase es esa capa completa, ya hecha y probada:

Requisitos

1. Instalar

Desde la raíz de tu proyecto:

npx supabase init            # sáltalo si ya tienes supabase/config.toml
npx supabase start
npx sellbase init --yes

sellbase init hace lo siguiente:

¿Quieres productos de ejemplo para verla funcionando? Corre npx sellbase seed cafeteria. También hay ropa, curso y consultorio.

Con un proyecto de Supabase en la nube, pasa sus llaves en lugar de levantar el stack local:

npx sellbase init --yes --supabase-url https://<proyecto>.supabase.co --anon-key … --service-role-key … --db-url … --owner-email tu@correo.com

La service role key solo se usa durante init y nunca se escribe en tu frontend.

2. Conectar el provider y el tema

Envuelve la app una sola vez en app/layout.tsx:

import { CartButton, CartDrawer } from '@/components/sellbase/cart-drawer';
import { SellbaseStoreProvider } from '@/components/sellbase/provider';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="es">
      <body>
        <SellbaseStoreProvider>
          <header>
            <a href="/">Mi tienda</a>
            <CartButton />
          </header>
          <main>{children}</main>
          <CartDrawer cartHref="/carrito" />
        </SellbaseStoreProvider>
      </body>
    </html>
  );
}

El admin trae su propio diseño a pantalla completa. Si no quieres que tu header salga en /admin, pon las páginas de la tienda en un grupo de rutas como app/(store)/layout.tsx, igual que la tienda de ejemplo.

Importa el tema en tu CSS global y pon tu marca. Con Tailwind v4:

@import 'tailwindcss';
@import '../components/sellbase/theme.css';
@source '../components/sellbase';

:root {
  --sb-primary: #3f2a1d; /* botones y acentos */
  --sb-radius: 14px;
}

3. Agregar las páginas de la tienda

// app/page.tsx: catálogo
import { ProductGrid } from '@/components/sellbase/product-grid';

export default function Home() {
  return <ProductGrid />;
}
// app/products/[slug]/page.tsx: ficha de producto con SEO
import { createSellbase, productMetadata } from '@sellbase/react';
import { ProductDetail } from '@/components/sellbase/product-detail';
import { ProductJsonLd } from '@/components/sellbase/product-seo';

const sellbase = createSellbase({
  url: process.env.NEXT_PUBLIC_SELLBASE_URL!,
  anonKey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
});
type Props = { params: Promise<{ slug: string }> };

export async function generateMetadata({ params }: Props) {
  const product = await sellbase.products.get((await params).slug).catch(() => null);
  return product
    ? productMetadata(product, { url: `https://tusitio.com/products/${product.slug}` })
    : {};
}

export default async function ProductPage({ params }: Props) {
  const { slug } = await params;
  const product = await sellbase.products.get(slug).catch(() => null);
  return (
    <>
      {product && <ProductJsonLd product={product} url={`https://tusitio.com/products/${slug}`} />}
      <ProductDetail slug={slug} />
    </>
  );
}
// app/checkout/page.tsx
import { Checkout } from '@/components/sellbase/checkout';
export default function CheckoutPage() {
  return <Checkout successPath="/gracias" cancelPath="/carrito" />;
}

// app/gracias/page.tsx: espera el webhook, muestra el pedido y vacía el carrito
import { CheckoutReturn } from '@/components/sellbase/order-status';
export default function GraciasPage() {
  return <CheckoutReturn />;
}

También están <CartPage /> (cart-page), <OrderLookup /> para la página "Mi pedido" y <ProductCarousel />. Los componentes leen todo de la API, así que productos y precios nunca quedan fijos en el código.

4. Productos y Stripe

Corre npm run dev, abre http://localhost:3000/admin y entra con los datos de .env.sellbase:

  1. Productos → Agregar producto: fotos, precio, variantes e inventario.

  2. Ajustes → Pagos: pega tu llave secreta de prueba de Stripe (sk_test_…). Se guarda en Supabase Vault.

    • En un proyecto desplegado, el webhook de Stripe se crea solo.

    • En local, redirígelo con la CLI de Stripe y pega el whsec_… que imprime:

      stripe listen --forward-to http://127.0.0.1:54321/functions/v1/sellbase-webhooks/stripe
      
  3. Compra de prueba: compra con la tarjeta 4242 4242 4242 4242. El pedido aparece en Pedidos en cuanto el webhook confirma el pago.

npx sellbase doctor lista lo que falta, con el siguiente paso de cada punto.

O deja que tu agente lo haga

init registró el servidor MCP de Sellbase en .mcp.json. Abre Claude Code o Cursor en el proyecto y dile:

Configura mi tienda con Sellbase: vendo velas artesanales a $250 MXN, envío $120.

El agente crea los productos, conecta Stripe en modo prueba y repite la compra de prueba hasta que sale bien. Todo lo que mueve dinero o borra datos te pide confirmación y queda en la bitácora.

5. Publicar

Guías completas: despliegue y cobrar de verdad con Stripe.

O empieza desde una plantilla

npx sellbase create mi-tienda --template nextjs
cd mi-tienda && npm install && npm run setup && npm run dev

Es una tienda completa con Next.js 16 y Tailwind, con botón de deploy a Vercel: examples/nextjs-store. ¿Tu sitio es HTML puro, WordPress o Webflow en lugar de React? Usa --template html, que funciona con los componentes web <sellbase-*>.

Raw Markdown for agents: guides/tienda-nextjs-supabase.md · Edit on GitHub