Skip to content

Guide

The Page Creation Workflow

8 min readLast updated Mar 2026

Overview

Creating a new page in Squarespace Developer Mode is not as simple as adding an HTML file. There is a specific 3-step process that involves registering the page with Squarespace's CMS, then removing it from the admin panel so everything lives cleanly in GitHub.

This workflow might seem counterintuitive at first. You create a file to register the page, then rename that file to unregister it from the UI while keeping the page live. The result is a site where the admin panel is nearly empty and GitHub is the single source of truth.

Step 1: The Discovery File (.page.conf)

To tell Squarespace that a new page exists, create a file with the .page.conf extension in the pages/ directory:

// pages/services.page.conf
{
  "title": "Our Services",
  "description": "Professional web development services for growing businesses."
}

The .page.conf extension is the trigger. When Squarespace sees a file with this extension, it registers the page in its CMS. The page appears in the admin panel under the Pages section, and Squarespace assigns it a URL based on the file stem.

The JSON content provides two fields:

  • title — rendered as the <title>tag in the page's head. This is what appears in browser tabs and search results.
  • description— rendered as the <meta name="description"> tag. This is the snippet Google shows below your page title in search results.

Push this file to GitHub. Within seconds, the page will appear in your Squarespace admin panel.

How it works

The .page.confextension is purely a discovery mechanism. It tells Squarespace's CMS engine to register a new page. Without this step, Squarespace has no idea the page exists, even if you create the .page content file.

Step 2: Rename to .conf

Once the page appears in the Squarespace admin panel (confirming it has been registered), rename the file from .page.conf to just .conf:

# Before: page is visible in admin panel
pages/services.page.conf

# After: page drops from admin panel
pages/services.conf

This rename does two things:

  1. Removes the discovery trigger. Squarespace no longer sees the .page.conf extension, so it stops treating this file as a page registration signal.
  2. Drops the page from the admin panel. The page is still live and accessible at its URL, but it no longer clutters the admin interface.

The .conf file continues to serve the title and description fields for SEO. Those values still populate the <title> and <meta>tags. The only thing that changes is the page's visibility in the admin panel.

Goal state

Your Squarespace admin panel should be nearly empty. No pages listed, no navigation items. Everything is managed through GitHub. The admin panel is just the host dashboard — not a content management interface.

Step 3: The Permanent Files

While Steps 1 and 2 handle registration, the actual page content lives in files that exist from the start and never change extension:

The .page file (HTML content)

<!-- pages/services.page -->
<div class="ldp-service-page ldp-page-services">
  <section class="hero">
    <h1>Our Services</h1>
    <p>Professional development for Squarespace sites.</p>
  </section>

  <section class="service-grid">
    <div class="service-card">
      <h3>Custom Development</h3>
      <p>Full Dev Mode builds from scratch.</p>
    </div>
    <div class="service-card">
      <h3>Migration</h3>
      <p>Move your site to Squarespace 7.0 Dev Mode.</p>
    </div>
  </section>

  <script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "Service",
    "name": "Custom Squarespace Development",
    "provider": {
      "@type": "Organization",
      "name": "Your Company"
    }
  }
  </script>
</div>

The .less file (page styles)

/* styles/services.less */
.ldp-page-services {
  .hero {
    padding: 80px 40px;
    text-align: center;
  }

  .service-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 24px;
    padding: 60px 40px;
  }

  .service-card {
    padding: 32px;
    background: var(--color-off-white);
  }
}

Remember to add the LESS file to the stylesheets array in template.conf or it will never be compiled.

Summary of all files for one page

pages/
  services.page.conf  → Step 1: discovery (rename to .conf after)
  services.conf       → Step 2: permanent config (title + description)
  services.page       → Permanent: HTML content

styles/
  services.less       → Permanent: page-specific styles (optional)

The Mental Model

The key to understanding this workflow is shifting your mental model of what Squarespace is. In Developer Mode, Squarespace is not a CMS. It is a connector and host.

Squarespace provides three things:

  1. Domain routing— maps your domain to the content.
  2. Asset compilation— compiles LESS into CSS and bundles JavaScript.
  3. URL routing— maps file stems to page URLs.

GitHub is the source of truth. Your template files, page content, styles, and configuration all live in the repository. The Squarespace admin panel should be nearly empty — no pages listed, no nav items configured through the UI. Everything is version-controlled, reviewable, and deployable through Git.

Why this matters

If you treat Squarespace as a CMS, you will constantly fight against it. Pages appearing and disappearing from the admin panel will confuse you. The .page.conf to .conf rename will feel like a hack. But when you understand that GitHub is the CMS and Squarespace is just the host, the workflow makes perfect sense.

File Naming Rules

Squarespace enforces strict rules on file names in the pages/ directory:

  • 30-character stem limit. The stem is everything before the first dot. So in services.page.conf, the stem is services (8 characters).
  • No periods in the stem. The first dot separates the stem from the extension. A file named my.services.page.conf would have the stem my, not my.services.
  • Lowercase, hyphens preferred. Use web-development rather than WebDevelopment or web_development. The file stem becomes the URL slug.

Warning

If your file stem exceeds 30 characters, Squarespace will silently ignore the file. No error, no warning. The page simply will not exist.

What Goes in .page Files

A .pagefile contains partial HTML — a fragment that gets injected into the global site.region shell. It is not a full HTML document.

Allowed

  • Semantic HTML content (divs, sections, headings, paragraphs, lists, etc.)
  • Behavioral <script> tags at the bottom (scroll reveal, FAQ accordion, form integrations)
  • <script type="application/ld+json"> at the bottom for structured data — Google reads JSON-LD from the body
  • Inline <style> blocks for pages with extensive unique CSS

Not allowed

  • <!doctype>, <html>, <head>, <body>— these are provided by site.region
  • {squarespace-headers} or {squarespace-footers} — these belong in site.region only
  • JavaScript-rendered content (no dynamic HTML generation via JS — content must be in the markup)
  • JavaScript style injection via document.createElement('style')

How Content Injection Works

In site.region, there is a tag:

{squarespace.main-content}

When a visitor requests a page, Squarespace looks up the URL slug, finds the matching .page file, and injects its content at this location. The result is a complete HTML document where site.region provides the shell (head, header, footer) and the .page file provides the body content.

<!-- site.region (simplified) -->
<!doctype html>
<html>
<head>
  {squarespace-headers}
</head>
<body>
  <header>...</header>
  <main>
    {squarespace.main-content}
    <!-- ^ Your .page file content renders HERE -->
  </main>
  <footer>...</footer>
  {squarespace-footers}
</body>
</html>

Tip

Always wrap your .page content in a single outer div with the page class: <div class="ldp-service-page ldp-page-services">. This gives you a reliable CSS scope for per-page styles and prevents style collisions between pages.

Tool

Page Scaffolder

Generate all page files (.page, .conf, .less) in one step

← LESS ArchitectureJSON-LD Schema →