A fast, mobile-first website template for trade and service businesses — handymen, electricians, plumbers, landscapers, and more. Built with Astro 6 and Tailwind CSS v4. Ready to deploy on Netlify in minutes.
- Full homepage with Hero, Trust Bar, Services, About, Reviews, Gallery, and CTA sections
- Inner pages: About, Services, Contact (with Netlify Forms), Reviews, Blog
- SEO-ready:
<title>, meta descriptions, canonical URLs, Open Graph, JSON-LD structured data, sitemap, robots.txt - Mobile-first responsive layout with a hamburger drawer nav and sticky desktop header
- Astro View Transitions for smooth page navigation
- Google Fonts (Oswald + Inter) optimized via Astro's built-in font API
- Tailwind v4 design token system — swap the entire brand with two file edits
# 1. Install dependencies (uses pnpm)
pnpm install
# 2. Start the dev server
pnpm run dev
# → http://localhost:4321
# 3. Build for production
pnpm run build
# 4. Preview the production build locally
pnpm run previewNote: This project uses
pnpm. Do not usenpm installoryarn— they will create a conflicting lockfile.
All placeholder content lives in exactly two files. You do not need to touch any component or page files to swap out a client's information.
Open this file and replace every placeholder value with the real business information.
export const client = {
name: 'Your Business Name', // Used in the header, footer, and SEO
email: 'hello@yourbusiness.com',
phoneForTel: '303-555-0100', // Format: digits and hyphens only (used in tel: links)
phoneFormatted: '(303) 555-0100', // Format: however you want it displayed
license: 'Lic# 123456', // Contractor license number — leave empty '' to hide
address: {
lineOne: '123 Main Street',
lineTwo: 'Suite 100', // Leave empty '' if no suite/unit
city: 'Denver',
state: 'CO',
zip: '80206',
country: 'US',
mapLink: 'https://maps.app.goo.gl/your-link', // Google Maps link to the business
},
socials: {
facebook: 'https://facebook.com/yourbusiness', // Leave empty '' to hide the icon
instagram: 'https://instagram.com/yourbusiness', // Leave empty '' to hide the icon
google: 'https://g.page/yourbusiness', // Google Business Profile link
},
domain: 'https://www.yourdomain.com',
};This data flows automatically into the header, footer, contact page, and all SEO tags. You never need to search-and-replace a phone number across multiple files.
This controls the site name, tagline, colors, and fonts.
export const brand = {
name: 'Your Business Name',
tagline: 'Professional service you can trust.',
description: 'A short sentence used as the default SEO meta description.',
url: 'https://www.yourdomain.com', // Must match client.domain
fonts: {
body: 'Inter', // Google Fonts name for body text
display: 'Oswald', // Google Fonts name for headings
},
colors: {
primary: '#1B3A6B', // Main brand color (nav, buttons, headings)
primaryFg: '#ffffff', // Text color on top of primary backgrounds
accent: '#F97316', // CTA buttons, highlights
// ... see file for full list
},
};After changing colors you must also update the matching hex values in
src/styles/theme.cssinside the@theme { }block. The variable names there correspond 1-to-1 with the keys inbrand.colors.After changing fonts you must also update
astro.config.mjs— find thefonts:array and change thenamefield to match your new Google Font name.
small-business-starter/
├── public/ # Static files served as-is (favicon, og-image.png)
├── src/
│ ├── components/ # Reusable UI sections
│ │ ├── Header.astro # Sticky nav with mobile hamburger drawer
│ │ ├── Footer.astro # Dark footer with columns and social links
│ │ ├── Hero.astro # Homepage hero with dual CTA
│ │ ├── TrustBar.astro # Trust signals strip (years, reviews, guarantee)
│ │ ├── Services.astro # Services grid
│ │ ├── About.astro # About section with benefits list
│ │ ├── Reviews.astro # Customer testimonials grid
│ │ ├── Gallery.astro # Project photo grid with skeleton loading
│ │ ├── CTA.astro # Full-bleed call-to-action section
│ │ └── Banner.astro # Inner-page hero with auto breadcrumbs
│ ├── config/
│ │ └── brand.ts # ✏️ Visual identity (colors, fonts, tagline)
│ ├── content/
│ │ └── blog/ # ✏️ Markdown blog posts (.md files)
│ ├── data/
│ │ └── client.ts # ✏️ Business info (phone, address, socials)
│ ├── layouts/
│ │ ├── BaseLayout.astro # Master HTML shell (SEO, fonts, skip link)
│ │ └── PostLayout.astro # Blog post layout
│ ├── pages/
│ │ ├── index.astro # Homepage
│ │ ├── about.astro
│ │ ├── services.astro
│ │ ├── reviews.astro
│ │ ├── contact/
│ │ │ ├── index.astro # Contact form (Netlify Forms-ready)
│ │ │ └── success.astro # Confirmation page after form submit
│ │ └── blog/
│ │ ├── index.astro # Blog listing
│ │ └── [...slug].astro # Individual post pages (auto-generated)
│ └── styles/
│ ├── global.css # Base styles, dark mode, reduced motion
│ └── theme.css # Tailwind v4 @theme design tokens
├── astro.config.mjs # Astro config (fonts, integrations, site URL)
├── netlify.toml # Netlify build + security headers config
└── package.json
Files marked ✏️ are the ones you will edit most often.
The theme ships with placeholder photos from Unsplash so it looks great immediately. To replace them with a client's real photos, edit one file: src/config/images.ts.
src/assets/images/
hero/ ← one image for the homepage Hero section
about/ ← one image for the About section
gallery/ ← all project photos (add as many as you like)
Images in src/assets/ are processed by Astro at build time — they are automatically converted to modern formats (WebP/AVIF), resized, and given proper srcset attributes. This is significantly better than using external URLs.
- Drop your image file into the matching folder (
hero/orabout/) - Open
src/config/images.tsand find the section for that image - Uncomment the
importline and update the filename:
// Before (placeholder is used):
// import heroImage from '../assets/images/hero/hero.jpg';
export const heroImage: ImageMetadata | undefined = undefined;
// After (your local image is used):
import heroImage from '../assets/images/hero/hero.jpg';
export const heroImage = heroImage;The gallery uses automatic file discovery. You do not need to edit any code:
- Delete the placeholder
.gitkeepfile fromsrc/assets/images/gallery/ - Drop your project photos into
src/assets/images/gallery/ - Run
pnpm run build— your images appear automatically
The filename becomes the caption. Name your files descriptively:
kitchen-remodel.jpg → "Kitchen Remodel"
deck-installation.jpg → "Deck Installation"
bathroom-tile-work.jpg → "Bathroom Tile Work"
Recommended image specs:
| Section | Min size | Aspect ratio |
|---|---|---|
| Hero | 1600 × 1200 px | 4:3 landscape |
| About | 900 × 700 px | 4:3 landscape |
| Gallery | 800 × 600 px each | 4:3 landscape |
Supported formats: .jpg .jpeg .png .webp .avif
Blog posts live in src/content/blog/ as Markdown files. Create a new .md file and add the required frontmatter at the top:
---
title: "5 Signs You Need a New Roof"
description: "A short summary shown on the blog listing and in search results."
author: "Jane Smith"
date: 2026-04-01
tags: ["roofing", "maintenance"]
draft: false
---
Your post content goes here. Standard Markdown is supported.The filename becomes the URL slug. Keep it lowercase with hyphens:
how-to-prepare-for-a-plumbing-inspection.md→/blog/how-to-prepare-for-a-plumbing-inspection
Set draft: true to write a post without publishing it.
- Push the project to a GitHub repository
- In Netlify, click Add new site → Import an existing project and connect the repo
- Netlify will auto-detect the build settings from
netlify.toml— no manual config needed - Set your live domain in two places after deploying:
src/data/client.ts→domainsrc/config/brand.ts→urlastro.config.mjs→site
The netlify.toml file already includes security headers (X-Frame-Options, X-Content-Type-Options, etc.) and immutable caching for hashed assets.
| Tool | Version | Purpose |
|---|---|---|
| Astro | 6 | Framework & static site generator |
| Tailwind CSS | 4 | Utility-first styling |
| Netlify | — | Hosting, forms, CDN |
| pnpm | 9+ | Package manager |
| Command | What it does |
|---|---|
pnpm install |
Install all dependencies |
pnpm run dev |
Start dev server at localhost:4321 |
pnpm run build |
Build the production site to ./dist/ |
pnpm run preview |
Preview the production build locally |
pnpm run astro check |
Type-check all .astro files |