Get Started

Thu Jul 03

A guide to the project structure, commands, and i18n setup of the Astro Starter Template (Astro 6 + Tailwind v4 + TypeScript).

Astro Starter Template

This is a starter template built on Astro 6 + Tailwind CSS v4 + TypeScript, with a blog, full-text search, a UI component library, and multi-language (i18n) support — all wired up out of the box.

Demo → https://dev-astro-three.vercel.app/

What’s included

CategoryDetails
FrameworkAstro 6 (output: 'static')
StylingTailwind CSS v4 (@import "tailwindcss" style)
TypingTypeScript 6 (strict)
i18nja / en (extendable to any number of locales)
ContentMarkdown / MDX blog, locale-scoped folders
SearchStatic full-text search via Pagefind
SliderEmbla Carousel with AutoScroll plugin
ImagesAstro Image + sharp for optimization
UI componentsTabs, Accordion, Modal, Lightbox, Dropdown, Hamburger, etc.
SEOOGP, Twitter Card, hreflang, locale-aware sitemap
AI guidelinesCLAUDE.md and .cursor/rules/ bundled

Quick start

# 1. Install dependencies
npm install

# 2. Start the dev server (http://localhost:4321)
npm run dev

# 3. Production build
npm run build

# 4. Preview the production build
npm run preview

Note: Pagefind (search) does not work in dev mode. Run npm run build first.

Project structure

src/
├── assets/             # Static assets, optimized by Astro
├── components/         # Reusable UI components
├── content/blog/       # Blog entries ({locale}/{slug}.{md,mdx})
│   ├── en/         # Default locale (English) content
│   └── ja/         # Japanese translations
├── i18n/               # i18n config, dictionary, helpers
├── icons/              # Local icons for astro-icon
├── layouts/            # Page layouts
├── pages/              # File-based routing
│   ├── ja/             # Japanese static pages (about, index, library, search, etc.)
│   └── [lang]/         # Dynamic routes for non-default locales (blog, tags, etc.)
├── scripts/            # Client-side scripts
├── styles/             # Tailwind v4 + global CSS
├── types/              # Shared TypeScript types
└── env.ts              # BASE_URL constant

Production site URL (site)

Set the production URL in astro.config.mjs so that absolute URLs are generated correctly:

export default defineConfig({
  site: 'https://your-production-domain.com', // ← change to your real URL
  // ...
});

This value is used by:

If you forget to update this, the demo URL (https://dev-astro-three.vercel.app) ends up in your production HTML, breaking SEO and social sharing.

BASE_URL (subdirectory prefix) is a separate setting — see the “Environment BASE_URL” section below.

Using i18n

Displaying translated strings

---
import { getLocaleFromUrl, useTranslations } from '../i18n/utils';
const locale = getLocaleFromUrl(Astro.url);
const t = useTranslations(locale);
---

<h1>{t('nav.home')}</h1>

Add new translation keys to every locale block in src/i18n/ui.ts — TypeScript will flag any missing keys.

Locale-aware URLs

import { BASE_URL } from '../env';
import { localizePath } from '../i18n/utils';

const href = `${BASE_URL}${localizePath('/blog/post-1/', locale).slice(1)}`;
// en: "/blog/post-1/"   ja: "/ja/blog/post-1/"

Adding a new locale

  1. Add the code to locales, localeLabels, and localeHtmlLang in src/i18n/config.ts
  2. Add a new dictionary block to src/i18n/ui.ts (TypeScript enforces all keys)
  3. Create src/pages/{locale}/ and add translated copies of index.astro, about.astro, library.astro, and search.astro (use src/pages/ja/ as a reference)
  4. Create src/content/blog/{locale}/ and add posts as needed (optional)
  5. Add the locale to astro.config.mjs (i18n.locales and the sitemap() call)

Static pages (step 3) follow the official Astro localized-folders pattern — each locale has its own per-page file. Everything else wires up automatically:

Pages without a translation

Blog posts can be translated selectively. If en/post-1.md exists but ja/post-1.md doesn’t, the language switcher on /blog/post-1/ shows Japanese as disabled (not clickable).

Search is locale-scoped

Search results are limited to the current locale. /search/?q=astro searches English pages; /ja/search/?q=astro searches Japanese pages.

How it works:

This wires up automatically when you add a new locale.

Where to customize

What you want to changeEdit
Site title / OGPsrc/i18n/ui.ts, astro.config.mjs (site)
Colors / fontssrc/styles/global.css (Tailwind v4 @theme)
Menu itemssrc/components/Navigation.astro
Header / Footersrc/components/Header.astro / Footer.astro
Top pagesrc/pages/index.astro (EN), src/pages/ja/index.astro (JA)
Blog postssrc/content/blog/{locale}/*.md
New componentssrc/components/

Environment BASE_URL

When deploying to a subdirectory, pass ASTRO_BASE at build time:

ASTRO_BASE=/subdir/ npm run build

src/env.ts exports a BASE_URL constant that you should use in internal links:

<a href={`${BASE_URL}${localizePath('/about/', locale).slice(1)}`}>About</a>

AI assistant rules

This repo ships with CLAUDE.md at the root and .cursor/rules/ for Cursor. They define naming conventions, i18n usage, and patterns to avoid — so Claude Code and Cursor stay consistent with the rest of the codebase. See CLAUDE.md for the full rules.

Deployment

Drop the dist/ folder onto any static host (Vercel, Netlify, GitHub Pages, Cloudflare Pages, S3, etc.). No Node runtime needed at runtime — this is a fully static site.

License

MIT. Note that redistribution or resale of this template (modified or not) as a competing product requires the author’s permission.

Created by: mooonycat ✨