A fast, static Eleventy site. No database, no plugins to update, no WordPress maintenance. Edit content by editing text/markdown files and rebuilding - takes under a second.
_data/site.json <- brand name, phone, email, NAP, schema info
(edit THIS file to rebrand the whole site)
_data/locations.json <- list of towns/counties served
(add an entry here -> a new /service-area/
page is generated automatically)
service-area/location-page.njk <- template used for every location page
(edit ONCE, it applies to all locations)
blog/posts/*.md <- blog articles (markdown, see below)
apps-script/ <- Google Apps Script lead handler + setup notes
css/style.css <- all styling
npm install
npm run serve
Opens a local preview at http://localhost:8080 with live reload.
Build the site:
npm install
npm run build
This creates a _site/ folder containing the finished static site.
Go to https://app.netlify.com/drop and drag the _site folder onto
the page. Netlify will give you a live URL (e.g.
random-name-123.netlify.app) immediately.
In Netlify, go to Domain settings and add your custom domain (once you've registered it). Update DNS the same way you did for brightsidecommercialcleaning.com.
This gets you live tonight. The downside of drag-and-drop: every time
you add a blog post or location, you'll need to run npm run build
again and re-drag the new _site folder.
For the "add content without touching HTML" workflow to be fully hands-off:
netlify.toml and handles the build
automatically (npm run build, publishes _site).Create a new file in blog/posts/, e.g.
blog/posts/2026-07-01-when-to-remove-a-stump.md:
---
layout: layouts/post.njk
title: "When Should You Remove a Stump vs. Leave It?"
description: "A quick guide to deciding whether a stump needs to go now or can wait."
date: 2026-07-01
permalink: /blog/when-to-remove-a-stump/
---
Your article content here, written in plain markdown...
It will automatically appear on /blog/ and get its own page, sitemap
entry, and schema-friendly title/meta.
Add a new entry to _data/locations.json:
{
"name": "Johnson City",
"state": "TN",
"stateFull": "Tennessee",
"county": "Washington County",
"slug": "johnson-city-tn",
"localNote": "One unique sentence about this area - landmarks, terrain, common job types, etc."
}
A full /service-area/johnson-city-tn/ page is generated automatically
using the existing template, and it's added to the homepage, footer,
sitemap, and schema areaServed list everywhere.
Everything pulls from _data/site.json. Update businessName,
phoneDisplay, phoneRaw, email, domain, etc. in that one file and
rebuild - it updates the header, footer, every page's schema, and the
contact page.
_data/site.json -> callrailScriptUrl. It's automatically injected
into every page's <head>.site.phoneDisplay value in the same format, CallRail's swap script
will reliably find and replace it everywhere - header, footer,
homepage hero, every location page, and the contact page.apps-script/).See apps-script/LeadFormHandler.gs for the full setup. Short version:
a Google Sheet with a "Leads" tab (every submission gets logged) and a
"Config" tab (edit a cell to reroute notifications to a different
operator - no code changes).