Skip to content
Andy Lawton

Leaving Squarespace for Static HTML and Firebase Hosting

Why I replaced a hosted CMS with an Astro static build, self-hosted fonts, and edge redirects on Firebase Hosting.

Published
Updated
—
Reading
1 min
Filed under
#web #astro #firebase #colophon

For several years, andylawton.com ran on Squarespace. It did the job when I just needed a landing page and a couple of posts, but over time the trade-offs got harder to justify: a recurring subscription to serve pages that change once a fortnight, megabytes of layout runtime to render a few hundred words of text, and awkward date-prefixed URLs like /home/2023/6/19/gb-energy-changes.

Moving the site to a pure static Astro build deployed to Google Cloud’s edge CDN via Firebase Hosting removes all of that overhead while keeping hosting covered by monthly GCP developer credits.

What changed under the hood

  • Zero runtime processes: Every page is compiled ahead of time by Astro (output: 'static') into flat .html, .css, and .woff2 files in dist/. There is no Node server, PHP worker, or database in the request path.
  • Typed content collections: Blog posts (src/content/blog/) and the projects directory (src/content/projects/) are plain Markdown files validated at build time with Zod schemas. If a frontmatter date or project category is mistyped, the build fails before firebase deploy ever runs.
  • Preserved URLs: All existing top-level paths (/projectslist, /gb-grid, /dice-roller, /get-in-touch) resolve without .html extensions or trailing slashes via "cleanUrls": true and "trailingSlash": false, and legacy Squarespace blog paths return permanent 301 redirects to their new /blog/<slug> addresses at the CDN edge.
{
  "hosting": {
    "public": "dist",
    "cleanUrls": true,
    "trailingSlash": false,
    "redirects": [
      {
        "source": "/home/2023/6/19/gb-energy-changes",
        "destination": "/blog/gb-energy-changes",
        "type": 301
      }
    ]
  }
}

Deploying in one command

Publishing a new article or updating a project status is now a single command (npm run deploy) that builds dist/ locally and publishes it to Firebase Hosting (firebase deploy --only hosting). If an old link looks broken after the move, drop me a note on the contact page.