- bump astro 5→6, @astrojs/mdx 4→6, astro-seo 0.8→1.1, sharp 0.33→0.35, plus minor updates - move local images from public/ to src/assets/ - replace <img> with <Image> from astro:assets (inferSize for remote URLs) - content schema uses image() helper for local covers - eager-load above-the-fold images (article covers, hero avatars)
mariosant.dev
Personal site and writing log for Marios Antonoudiou — AI product engineer.
Migrated from a Nuxt 4 + @nuxt/content setup to Astro 5 + Tailwind CSS 4, preserving every URL and the dark-mode design of the original.
Stack
- Astro 5 — static site generation
- Tailwind CSS 4 — utility CSS
- astro-icon — Iconify icons
- astro-seo —
<SEO>component - @astrojs/sitemap — sitemap
- @astrojs/mdx — MDX content
- Inter Variable via
@fontsource-variable/inter
Scripts
pnpm install # install dependencies
pnpm dev # start the dev server at http://localhost:4321
pnpm build # build the static site to ./dist
pnpm preview # preview the built site locally
Project structure
src/
├── components/ # Astro components
│ ├── home/ # Home page sections
│ ├── button.astro # Button primitive
│ ├── container.astro # UContainer equivalent
│ ├── footer.astro
│ ├── link.astro # ULink equivalent
│ ├── previous-role.astro
│ ├── project.astro
│ └── top-nav.astro
├── content/
│ └── articles/ # Markdown articles
├── content.config.ts # Content collection schema
├── layouts/
│ └── Layout.astro # Single layout (default + content)
├── pages/
│ ├── 404.astro
│ ├── index.astro
│ └── articles/
│ ├── index.astro
│ └── [...slug].astro
├── styles/
│ └── global.css
└── utils/
└── date.ts # "15th of June 2026" formatter
public/ # Static assets (avatar, logos, favicon)
Authoring an article
- Drop a new file in
src/content/articles/, e.g.2026-07-01-my-post.md. - Add frontmatter that matches the schema in
src/content.config.ts:--- title: My Post date: 2026-07-01 coverImage: author: Photographer Name authorUrl: https://unsplash.com/@photographer # optional url: https://images.unsplash.com/photo-... --- - Write the body in Markdown.
- The new article will appear at
/articles/2026-07-01-my-postand on the/articlesindex automatically.
Deployment
The site is fully static. Build with pnpm build and deploy the dist/ directory to any static host (Vercel, Netlify, Cloudflare Pages, GitHub Pages, etc.).
Build settings (most hosts)
| Setting | Value |
|---|---|
| Build command | pnpm build |
| Output directory | dist |
| Node version | 20+ |
Recommended cache headers
For /_astro/* (hashed bundles):
Cache-Control: public, max-age=31536000, immutable
For /articles/* (HTML, sitemap-referenced):
Cache-Control: public, max-age=3600, must-revalidate
Configure these via your host's preferred mechanism (vercel.json, _headers for Netlify, _headers for Cloudflare Pages, etc.).
SEO surface
sitemap-index.xml+sitemap-0.xml— auto-generated by@astrojs/sitemap, all 13 routesrobots.txt— points at the sitemaprss.xml— feed of all articles- JSON-LD
Personschema on the home page - JSON-LD
Article+BreadcrumbListschema on each article page - Open Graph + Twitter Card meta on every page
- Canonical URLs on every page
<link rel="alternate" type="application/rss+xml">autodiscovery
Open Graph image
The default OG image is public/mariosant.webp (a 512×512 avatar). For best display on Twitter/LinkedIn (1200×630 recommended), drop a public/og-image.png and update src/utils/seo.ts's default or pass it explicitly to the Layout.