Astro Project Starter Template
An opinionated Astro starter for Arachne web agency client builds. Optimized for accessibility, SEO, AI/LLM readability, Google Business / local search, and webcrawler friendliness out of the box.
npm create astro@latest -- --template https://git.zyrrus/dev/arachne/astro-template
Post-Clone Checklist
Work through these in order. Items marked (required) must be done before the first production build; others can be deferred but should be completed before launch.
1. Project Identity
- (required) Update package.json — set
name,version, and remove any fields that don't apply. - (required) Rewrite this README with project-specific info (or delete it).
- Remove or replace the agency clone command at the top of this file.
- Initialize a fresh git history if cloned via
git cloneinstead of the Astro template flow:rm -rf .git && git init.
2. Environment Variables
- (required) Create
.env.exampledocumenting every variable the project needs. Commit it. - (required) Copy
.env.example→.envand fill in real values. Do not commit.env(already in .gitignore). - (required) Audit the existing .env — the template ships with placeholder Mailgun keys. Rotate any committed credentials immediately.
- (required) Update the
env.schemablock in astro.config.mjs to match the variables the project actually uses. Remove any unused entries (default ships with Mailgun + contact-form vars). - If using a different mailer / form backend, swap or remove the Mailgun env vars entirely.
3. Astro Config
- (required) Set
site: "https://example.com"in astro.config.mjs — this is required for@astrojs/sitemap, canonical URLs, and absolute OG image URLs to work. - Pick the right output mode in astro.config.mjs: keep
output: "server"for SSR (forms, API routes, dynamic content) or change to"static"for fully static builds. Drop@astrojs/nodeif going static. - Remove
@astrojs/preactif the project won't use Preact islands. - Add any extra integrations needed (e.g.
@astrojs/mdx,@astrojs/image).
4. Site Content (site.yaml)
The template ships with sample data for a law firm — replace all of it.
- (required) Replace every field in src/content/site.yaml with the new client's info:
name,shortName,url,tagline,description,phone,email,address,hours,nav. - (required) Update the zod schema in src/content.config.ts to match the shape you actually use. The shipped schema is intentionally minimal; the YAML has extra fields (offices, fax, affiliate, established) that you may want to either remove from YAML or add to the zod schema for type safety.
- Decide on multi-office vs single-office. The shipped YAML has both
offices[]and a top-leveladdress— pick one, update src/lib/schema.ts accordingly. - Review src/lib/schema.ts — it hardcodes
"LegalService"as the schema.org type and"Louisiana"asareaServed. Change@typeto the appropriate schema.org type (LocalBusiness,ProfessionalService,Restaurant, etc.) and updateareaServed. - Add JSON-LD for any extra entity types the project needs (
Personfor staff,Servicefor offerings,FAQPage,Article,Product) — extend src/lib/schema.ts.
5. Base Layout Cleanup
In src/layouts/base-layout.astro:
- (required) Line 73: replace hardcoded
og:site_name="Armor Title Company"with{site.name}. - Line 37: replace
lang="en"with the correct locale, or wire it to a site-level config. - Line 41: change
<meta name="description" content={description} />to usepageDescso the fallback works. - Line 74: replace hardcoded
og:locale="en_US"if the project isn't US English. - Add a
<meta name="theme-color">matching the brand color. - Add
twitter:site/twitter:creatorhandles if the client has a Twitter/X presence.
6. Branding — Colors, Fonts, Tokens
- (required) Add the brand palette to src/styles/global.css inside
@theme { }. Tailwind 4 reads CSS custom properties as tokens — define--color-*,--font-*,--radius-*, etc. Example:@theme { --color-bg: oklch(98% 0.01 80); --color-fg: oklch(20% 0.02 80); --color-accent: oklch(60% 0.15 250); --font-sans: var(--font-inter), system-ui, sans-serif; } - (required) Wire the brand font in astro.config.mjs
fonts: [...]. Default is Inter from Google — swapname,weights,styles, andcssVariablefor the project's font. Then update--font-*in src/styles/global.css and the<Font cssVariable="..." preload />call in src/layouts/base-layout.astro to match. - Fill in the three
TODOcomments in src/components/skip-link.astro with real--color-*tokens once defined. - Set base
bodyfont + background colors in src/styles/global.css.
7. Favicons & App Icons
The base layout references favicon files that don't ship with the template
(only favicon.ico and favicon.svg exist). Generate the rest from the
brand mark.
- (required) Run a source mark through realfavicongenerator.net or similar.
- (required) Drop the generated files into public/favicon/. At minimum the base layout expects:
favicon.icofavicon.svgfavicon-96x96.pngapple-touch-icon.png(180×180)web-app-manifest-512x512.pngsite.webmanifest
- Update
site.webmanifestname,short_name,theme_color,background_color.
8. Open Graph / Social Images
- (required) Generate a default OG image (1200×630) and place it in public/og/.
- (required) Update the
ogImagedefault in src/layouts/base-layout.astro (currently falls back to/favicon/web-app-manifest-512x512.png— not 1200×630, which violates theog:image:width/heightmeta tags). - Consider per-page OG images: pass
ogImageprop to<BaseLayout>per route, or generate them dynamically with@vercel/og/ Satori in an API route.
9. Pages & Routes
- (required) Replace src/pages/index.astro with the real homepage.
- (required) Add a
src/pages/404.astrofor proper 404 handling. - Implement nav target pages to match
naventries in src/content/site.yaml. - Build out the stub components in src/components/sections/, src/components/primitives/, and src/components/composites/.
- If using the contact form endpoint, implement
src/pages/api/contact.ts(or whatevercontactFormEndpointpoints to insite.yaml). - Review src/pages/robots.txt.ts — adjust crawl rules if the site has private areas.
10. Accessibility Pass
The template gives you the bones; verify the build.
- All interactive elements reachable by keyboard; focus styles visible.
- Color contrast ≥ 4.5:1 for body text, ≥ 3:1 for large text and UI components (WCAG AA).
- Every
<img>has meaningfulalt(oralt=""for decorative). - Heading hierarchy is sequential (no skipped levels).
- Forms have associated
<label>s; errors are announced. - Run axe DevTools or Lighthouse a11y audit before launch.
11. SEO / Crawler / Google Business
- Verify
siteURL is set in astro.config.mjs (sitemap and canonicals depend on it). - Confirm
https://your-site/sitemap-index.xmlresolves after build. - Submit the sitemap in Google Search Console.
- Set up / claim the Google Business Profile — make sure NAP (name, address, phone) in
site.yamlexactly matches the GBP listing. - Add
Personschema entries for owners/staff if relevant. - Validate JSON-LD output with Google's Rich Results Test.
- Add per-page
titleanddescriptionprops on every<BaseLayout>usage.
12. AI / LLM Readability
- Use semantic HTML (
<article>,<section>,<nav>,<header>,<footer>,<address>) — LLM scrapers weight this heavily. - Keep JSON-LD comprehensive — it's the canonical structured representation for LLM ingestion.
- Consider adding
/llms.txt(and/llms-full.txt) at the public root summarizing the site for LLM crawlers — see llmstxt.org. - Avoid critical content rendered only via client-side JS; this template defaults to SSR for a reason.
13. Deployment
The template ships with a Gitea Actions workflow that deploys via Pangolin.
- (required) Configure these Gitea repo secrets:
PANGOLIN_API_URL,PANGOLIN_API_KEY,PANGOLIN_ORG_ID,PANGOLIN_DOMAIN_ID,PANGOLIN_SITE_ID,PANGOLIN_TARGET_IP,MAILGUN_API_KEY,MAILGUN_DOMAIN,CONTACT_TO,MAILGUN_FROM. - (required) Configure repo variable
APP_NAME. - Update the
env-vars:block in the workflow if the project uses different env vars than the Mailgun defaults. - If not deploying via Gitea/Pangolin, delete .gitea/ and add the right CI config for your target (Vercel, Netlify, fly.io, raw Docker, etc.).
- Review the dockerfile — it assumes
output: "server". For static builds, switch to an Nginx-based image.
14. Final Pre-Launch Checks
npm run buildsucceeds with no warnings.- Lighthouse scores: Performance ≥ 90, Accessibility 100, SEO 100, Best Practices ≥ 95.
- Test OG preview with OpenGraph.xyz.
- Test Twitter card with the Card Validator.
- Verify
robots.txtandsitemap-index.xmlat the deployed URL. - Verify favicons render correctly across browsers + iOS home screen.
- Click through every nav link and form on mobile + desktop.
Project Structure
.
├── .gitea/workflows/ # Gitea CI/CD (Pangolin deploy)
├── public/
│ ├── favicon/ # Favicons + web manifest
│ └── og/ # Open Graph images
├── src/
│ ├── assets/ # Imported assets (optimized at build time)
│ ├── components/
│ │ ├── primitives/ # Buttons, inputs — atoms
│ │ ├── composites/ # Accordion, marquee — molecules
│ │ ├── sections/ # Header, footer, page sections
│ │ ├── seo-json-ld.astro
│ │ └── skip-link.astro
│ ├── content/
│ │ └── site.yaml # Single source of truth for site metadata
│ ├── layouts/
│ │ └── base-layout.astro # All <head>, SEO, fonts, schemas live here
│ ├── lib/
│ │ ├── schema.ts # JSON-LD generators
│ │ └── site.ts # Typed accessor for site.yaml
│ ├── pages/
│ │ ├── index.astro
│ │ └── robots.txt.ts
│ ├── styles/
│ │ └── global.css # Tailwind import + @theme tokens
│ └── content.config.ts # Content collection schema (zod)
├── astro.config.mjs
├── dockerfile
└── tsconfig.json
Description
Languages
Astro
47.5%
TypeScript
33.5%
JavaScript
12.4%
CSS
6.6%