Astro GitHub Pages CI/CD Sentry Umami

Deploy de Astro en GitHub Pages con CI/CD.

April 4, 2026 7 min read

Qué es GitHub Pages

Hosting gratuito de sitios estáticos directo desde un repositorio de GitHub. Soporta deploy manual (desde una rama) o automático via GitHub Actions. Ideal para proyectos que generan HTML estático en build time — exactamente lo que hace Astro.

Por qué GitHub Pages

Tengo un proyecto Astro que es un conjunto de herramientas web que corren 100% client-side. No hay backend, no hay base de datos. Es un sitio estático puro.

Evaluación rápida:

  • Vercel / Netlify — Excelentes, pero crean una capa más: otra cuenta, otro dashboard, otro login. Para un sitio estático sin funciones serverless, es infraestructura innecesaria.
  • Cloudflare Pages — Mismo caso. Muy bueno, pero no necesito CDN enterprise ni Workers para un sitio de herramientas.
  • GitHub Pages — El código ya está en GitHub. El CI/CD es GitHub Actions. Todo queda en un solo lugar. Para un sitio estático sin requerimientos especiales, es la opción más simple.

Configuración

1. Configurar Astro para GitHub Pages

Astro necesita saber dos cosas: la URL del sitio y el path base (porque GitHub Pages sirve en tu-usuario.github.io/nombre-repo/, no en la raíz).

// astro.config.mjs
export default defineConfig({
  site: "https://TU_USUARIO.github.io", // <- cambiá esto por tu usuario
  base: "/TU_REPO", // <- cambiá esto por el nombre de tu repo
  // ... resto de tu config
});

Gotcha importante: import.meta.env.BASE_URL devuelve el valor de base SIN trailing slash. Si tu base es /webtools, el valor es /webtools, no /webtools/. Todos tus links internos tienen que concatenar con / explícito: `${base}/image`, no `${base}image`. Si no, vas a terminar con rutas como /webtoolsimage.

En archivos .astro, usá import.meta.env.BASE_URL para construir las rutas:

---
const base = import.meta.env.BASE_URL;
---

<a href={base}>Home</a>
<a href={`${base}/image`}>Images</a>
<a href={`${base}/audio`}>Audio</a>

En componentes React (o cualquier framework), funciona igual — Vite lo reemplaza en build time:

const base = import.meta.env.BASE_URL;

const tools = [
  { href: `${base}/image`, title: "Image Optimizer" },
  { href: `${base}/audio`, title: "Audio Optimizer" },
];

3. Crear el workflow de GitHub Actions

# .github/workflows/deploy.yml
name: Deploy to GitHub Pages

on:
  push:
    branches: [main]

permissions:
  contents: read
  pages: write
  id-token: write

concurrency:
  group: pages
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm

      - run: npm ci

      - run: npm run build

      - uses: actions/upload-pages-artifact@v3
        with:
          path: dist

  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - id: deployment
        uses: actions/deploy-pages@v4

Dos jobs separados: build compila el sitio, deploy lo sube a Pages. El concurrency cancela deploys anteriores si pusheás rápido varias veces.

4. Crear el repo y pushear

gh repo create TU_REPO --public --source=. --push # <- cambiá TU_REPO por el nombre

Si es la primera vez que pusheás un archivo en .github/workflows/, tu token de gh necesita el scope workflow. Si te da error de permisos, corré: gh auth refresh -s workflow -h github.com y volvé a pushear.

5. Habilitar GitHub Pages con Actions como source

Desde la terminal:

gh api repos/TU_USUARIO/TU_REPO/pages -X POST --input - <<'EOF'
{"build_type":"workflow","source":{"branch":"main","path":"/"}}
EOF

O desde GitHub: Settings > Pages > Source > GitHub Actions.

A partir de acá, cada push a main dispara el workflow automáticamente.

Agregar Sentry (error tracking)

1. Instalar el SDK

npm install @sentry/astro @sentry/browser

2. Agregar la integración a Astro

// astro.config.mjs
import sentry from "@sentry/astro";

export default defineConfig({
  integrations: [
    // tus otras integraciones...
    sentry(),
  ],
});

3. Crear el archivo de configuración del cliente

// sentry.client.config.js (en la raíz del proyecto)
import * as Sentry from "@sentry/astro";

Sentry.init({
  dsn: "TU_DSN_DE_SENTRY", // <- cambiá esto por tu DSN
  tracesSampleRate: 1.0,
  replaysSessionSampleRate: 0,
  replaysOnErrorSampleRate: 1.0,
});
  • tracesSampleRate: 1.0 — trackea el 100% de las transacciones. Para sitios con mucho tráfico, bajalo a 0.1 o menos.
  • replaysOnErrorSampleRate: 1.0 — graba un replay de la sesión cuando hay un error. Muy útil para debugging.
  • replaysSessionSampleRate: 0 — no graba sesiones sin errores. Ahorra quota.

No pases las opciones directo en sentry() dentro de astro.config.mjs. Está deprecado. Sentry espera el archivo sentry.client.config.js separado.

Agregar Umami (analytics)

1. Crear el sitio en Umami Cloud

Andá a Umami Cloud, creá un sitio con el dominio TU_USUARIO.github.io (sin https://, sin path). Te va a dar un snippet con un data-website-id.

2. Agregar el script al layout

<!-- src/layouts/Layout.astro — dentro del <head> -->
<script
  is:inline
  defer
  src="https://cloud.umami.is/script.js"
  data-website-id="TU_WEBSITE_ID"
></script>

El is:inline es obligatorio en Astro. Sin él, Astro intenta procesar el script (bundlearlo, optimizarlo) y rompe porque tiene atributos custom (data-website-id). is:inline le dice “dejá este script tal cual en el HTML”.

Eso es todo. Umami es un script de 2KB que no usa cookies y es GDPR-compliant. No necesitás banner de cookies.

SEO básico

Ya que estás configurando el deploy, aprovechá para agregar lo mínimo de SEO:

npx astro add sitemap --yes

Esto genera un sitemap-index.xml automáticamente en cada build. Después creá un robots.txt en public/:

User-agent: *
Allow: /

Sitemap: https://TU_USUARIO.github.io/TU_REPO/sitemap-index.xml

Y asegurate de que tu layout tenga Open Graph tags para que los links se vean bien cuando se comparten:

---
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
---

<meta property="og:type" content="website" />
<meta property="og:url" content={canonicalURL} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<link rel="canonical" href={canonicalURL} />

Resultado

El flujo queda así: pusheás a main, GitHub Actions hace build y deploy en menos de un minuto. Sentry te avisa si algo se rompe. Umami te dice quién visita qué. Todo sin pagar un peso.

Enlaces