A searchable directory of 3,467 universities and 27,798 degree programs in Mexico — fully static, served from Cloudflare's edge, with instant client-side fuzzy search.
🔗 Live demo → universidades-mexico.pages.dev
| Landing | Search |
|---|---|
![]() |
![]() |
| University profile | Mobile |
|---|---|
![]() |
![]() |
- ~22,000 static pages pre-rendered in ~20 seconds — every state, university, and unique degree program has its own indexable URL.
- Zero backend. Search runs entirely client-side with Fuse.js (~10 KB) over a single JSON blob.
- Edge-hosted on Cloudflare Pages: free, global CDN, automatic HTTPS, sub-100 ms TTFB.
- Interactive choropleth map of Mexico (inline SVG, ~73 KB) with live density toggle across four metrics.
- ⌘K command palette for fuzzy search across universities, programs, and states.
- CI/CD via GitHub Actions — every push to
mainrebuilds and deploys.
The dataset is read-mostly and rarely changes, so SSG buys real wins:
- No server, no operational surface. No DB to back up, no app to patch, no autoscaling to tune.
- SEO by default. Every university and degree program is a pre-rendered URL that Google can index directly.
- Free global edge. Cloudflare Pages serves the whole site from cache, anywhere, for $0.
Fuse.js is small enough (~10 KB) and the dataset compact enough (~3.5 MB JSON) to ship the entire search index to the client. After the first load, search has zero network roundtrips — no backend to scale, no rate limits, no cold starts.
This is a rewrite of a legacy Django 1.11 + jQuery app:
| Aspect | Before (Django) | After (Nuxt 3) |
|---|---|---|
| Backend | Django + SQLite | None — fully static |
| Frontend | jQuery + UIkit | Vue 3 + Tailwind |
| Map | CSSMap plugin (26 MB of sprites) | Inline SVG (~73 KB) |
| Search | NLTK + DB queries | Fuse.js client-side |
| Hosting | None (local-only) | Cloudflare Pages (free) |
| Deploy | Manual | git push → GitHub Actions |
| Layer | Choice | Why |
|---|---|---|
| Framework | Nuxt 3 (SSG mode) | Static generation, SEO-friendly routing, Vue 3 DX |
| Styling | Tailwind CSS | Utility-first, fast iteration, small bundle |
| Search | Fuse.js | Typo-tolerant fuzzy search, no server required |
| Hosting | Cloudflare Pages | Free global edge, instant cache invalidation |
| Tests | Vitest + @nuxt/test-utils | Component testing with happy-dom |
A few decisions worth calling out:
- Hover highlight on the map. Each Mexican state is a
<path>in document order. When a state is hovered, its accent border can be visually covered by neighbouring states that appear later in the SVG (e.g. Hidalgo, surrounded by Edomex/Puebla/Veracruz). Solution: onmouseenter, clone the path'sdinto an overlay<path fill=accent stroke=accent>appended to the root<svg>withpointer-events: none. The overlay paints last, so the accent isn't obscured, and the original path still owns the cursor —mouseleavefires reliably. Seecomponents/MexicoMap.vue. - Carrera slug deduplication. The raw SEP dataset contains the same program under slight name variations across institutions. The static-build script normalises and deduplicates 27k programs down to ~7.5k unique slugs and generates one canonical
/carrera/[slug]page per program. Seescripts/build-carrera-index.mjs. - No payload extraction. Nuxt's default static payload generation creates one JSON file per route; with ~22k routes this blew past Cloudflare Pages' 20k-file limit. Disabling payload extraction in
nuxt.config.tstrades a small first-paint cost for staying under the limit.
This project uses pnpm and Node 22.
pnpm install # Install dependencies
pnpm dev # Local dev server
pnpm generate # Build static site to .output/public
pnpm preview # Preview the generated build
pnpm test # Run component tests
pnpm deploy # Generate + deploy to Cloudflare PagesAutomatic on every push to main via .github/workflows/deploy.yml.
Required GitHub Actions secrets:
CLOUDFLARE_API_TOKEN— token with Cloudflare Pages: Edit permission.CLOUDFLARE_ACCOUNT_ID— your Cloudflare account ID.
Manual deploys: pnpm deploy (requires wrangler login).
- 33 Mexican states · 3,467 universities · 27,798 degree programs.
- Source: Secretaría de Educación Pública (SEP).
- Exported once from
db.sqlite3topublic/data/universidades.json. The original SEP scraper is discontinued, so the dataset is a historical snapshot.




