- Published on
Desarrollo de blog ultra rápido con Next.js, Supabase y Vercel
- Authors
- Name
- Hidetoshi Yanagisawa
¡Hola! Hoy te traigo una guía paso a paso para un desarrollo de blog ultra rápido y súper económico usando Next.js + Supabase, y desplegándolo en Vercel. Si quieres montar un blog desde cero sin preocuparte de servidores ni gastar un centavo, este tutorial es para ti. 😉
¿Por qué Next.js + Supabase?
- Next.js: Framework React moderno con soporte nativo de SSR/SSG y API Routes.
- Supabase: Base de datos PostgreSQL + API REST auto-generada + Auth, todo en plan gratuito.
- Vercel: Hosting optimizado para Next.js; despliegue automático desde GitHub en segundos.
Combinándolos obtienes “DB → API → Front → Deploy” sin manejar infraestrucura, 100% en free tier y con una experiencia de desarrollo hiper-ágil.
Pasos
1. Crear tu proyecto en Supabase
- Regístrate en https://app.supabase.com
- Haz clic en New project, ponle un nombre y contraseña, elige región y crea.
- En Settings > API anota:
- Project URL
- anon public key
posts
2. Definir la tabla En el editor de tablas o en SQL ejecuta:
create table posts (
id bigserial primary key,
title text not null,
content text not null,
author text not null, -- Nombre del autor o identificador
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
author
es NOT NULL (puede ser un nombre ficticio).created_at
/updated_at
se llenan automáticamente.
3. Configurar el proyecto Next.js
# Crear Next.js + TypeScript + Tailwind
npx create-next-app@latest blog --typescript --import-example with-tailwindcss
cd blog
# Instalar dependencias
npm install @supabase/supabase-js axios
4. Variables de entorno
Crea .env.local
en la raíz y añade:
NEXT_PUBLIC_SUPABASE_URL=https://<tu-proyecto>.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=<tu-anon-key>
🔒 La Service Role Key guárdala sólo para uso interno en código servidor.
5. Inicializar el cliente de Supabase
Crea lib/supabaseClient.ts
:
import { createClient } from '@supabase/supabase-js'
export const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
6. Implementar API Routes
Añade app/api/posts/route.ts
con:
import { NextResponse } from 'next/server'
import { supabase } from '@/lib/supabaseClient'
// GET: lista de posts
export async function GET() {
const { data, error } = await supabase
.from('posts')
.select('*')
.order('created_at', { ascending: false })
if (error) return NextResponse.json({ error }, { status: 500 })
return NextResponse.json(data)
}
// POST: crear un nuevo post
export async function POST(request: Request) {
const { title, content, author } = await request.json()
const { data, error } = await supabase.from('posts').insert({ title, content, author }).select()
if (error) return NextResponse.json({ error }, { status: 500 })
return NextResponse.json(data[0], { status: 201 })
}
Con App Router, cualquier archivo en
app/api/*/route.ts
funciona como función serverless.
7. Frontend con React + Axios
app/page.tsx
)
7.1 Página de lista de posts ('use client'
import { useEffect, useState } from 'react'
import axios from 'axios'
type Post = {
id: number
title: string
content: string
author: string
created_at: string
}
export default function Home() {
const [posts, setPosts] = useState<Post[]>([])
useEffect(() => {
axios.get<Post[]>('/api/posts').then((res) => setPosts(res.data))
}, [])
return (
<main className="p-8">
<h1 className="mb-6 text-3xl">🔥 Lista de blogs</h1>
<ul className="space-y-4">
{posts.map((p) => (
<li key={p.id} className="border-b pb-4">
<h2 className="text-2xl">{p.title}</h2>
<p className="text-sm text-gray-500">
{p.author} · {new Date(p.created_at).toLocaleString()}
</p>
<p className="mt-2">{p.content}</p>
</li>
))}
</ul>
</main>
)
}
app/create/page.tsx
)
7.2 Página de creación de post ('use client'
import { useState } from 'react'
import { useRouter } from 'next/navigation'
import axios from 'axios'
export default function CreatePage() {
const router = useRouter()
const [title, setTitle] = useState('')
const [content, setContent] = useState('')
const [author, setAuthor] = useState('')
const [loading, setLoading] = useState(false)
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setLoading(true)
try {
await axios.post('/api/posts', { title, content, author })
router.push('/')
} catch (err) {
console.error(err)
} finally {
setLoading(false)
}
}
return (
<main className="p-8">
<h1 className="mb-6 text-3xl">✏️ Publicar artículo</h1>
<form onSubmit={handleSubmit} className="space-y-4">
<input
value={author}
onChange={(e) => setAuthor(e.target.value)}
placeholder="Autor"
required
className="w-full border p-2"
/>
<input
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="Título"
required
className="w-full border p-2"
/>
<textarea
value={content}
onChange={(e) => setContent(e.target.value)}
placeholder="Contenido"
required
className="h-48 w-full border p-2"
/>
<button
type="submit"
disabled={loading}
className="rounded bg-blue-600 px-6 py-2 text-white disabled:opacity-50"
>
{loading ? 'Enviando…' : 'Publicar'}
</button>
</form>
</main>
)
}
8. Despliegue en Vercel
- Haz push a tu repositorio en GitHub.
- En Vercel, crea un New Project y selecciona tu repo.
- Configura las mismas Environment Variables (
NEXT_PUBLIC_SUPABASE_URL
yNEXT_PUBLIC_SUPABASE_ANON_KEY
). - Deploy y ¡listo! Tu blog estará online en segundos.
Resumen
- Prepara tu tabla y API en Supabase.
- Implementa API Routes en Next.js App Router.
- Crea frontend React con Axios para listar y publicar.
- Despliega gratis en Vercel.
Con estos pasos tendrás un blog funcionando en tiempo récord y sin gastar un dólar. ¡Éxitos con tu proyecto!