# Dev Server

Run `sitemd launch` to start a local dev server at `localhost:4747`. Every feature works — pages, auth, forms, data, analytics, SEO, gating — regardless of activation status. Save any file and the site rebuilds automatically.

## How it works

The dev server renders your site in memory and serves it as a single-page application. Instead of writing HTML files to disk, it builds all pages into an in-memory store and serves them through a lightweight HTTP server with SPA navigation.

```text
Browser request → skeleton HTML shell
  └─ hydrate.js fetches shell (header, footer) from /__api/shell
  └─ hydrate.js fetches page content from /__api/page?slug=/about
  └─ hydrate.js fetches metadata from /__api/meta?slug=/about
  └─ clicking a link → fetches the new page without a full reload
```

The skeleton HTML is an empty document with container elements. All content is loaded client-side by the hydration script. View-sourcing a page shows references to `localhost` URLs — without the dev server running, the page is blank.

## Skeleton HTML

Every page request returns the same HTML shell:

```html
<div id="sitemd-shell"></div>      <!-- header + nav injected here -->
<main id="sitemd-main">
  <article class="content"></article>  <!-- page content injected here -->
</main>
<div id="sitemd-footer"></div>     <!-- footer injected here -->
```

The hydration script (`hydrate.js`) populates these containers by calling the dev server API. Navigation between pages swaps the content without reloading — page transitions are instant.

## API endpoints

The dev server exposes internal endpoints for the hydration layer:

| Endpoint | Returns |
|---|---|
| `/__api/shell` | Header HTML, footer HTML, brand, theme CSS path |
| `/__api/page?slug=/about` | Rendered page content (the `<article>` inner HTML) |
| `/__api/meta?slug=/about` | Page title, description, sidebar, nav, auth attributes |
| `/__api/layout-scripts` | Inline JS from `theme/layout.html` (search, lightbox, modals) |
| `/__reload` | Server-Sent Events stream for live reload |

These endpoints are internal to the dev server. They don't exist in production builds.

## Auth and data in dev mode

When an auth provider is configured in `settings/auth.md`, the dev server injects:

- The **account button** in the header (person icon linking to `/login`)
- **Auth config** (`window.__sitemdAuthCfg`) and the `auth.js` runtime script
- **Flash prevention** — hides page content until auth state resolves on gated pages
- **Gated section CSS** — hides `gated:` blocks until the auth runtime reveals them
- **Per-page auth attributes** — `data-auth="required"` and `data-gated-types` on `<main>` for pages that require login

When a data provider is configured in `settings/data.md`, the dev server injects the `data.js` runtime script with provider credentials.

Auth and data work identically in dev and production. The only difference is where the HTML comes from — memory (dev) vs disk (production build).

## Local auth testing

When using `provider: custom`, the dev server includes a built-in auth stub so you can test login, signup, magic links, gated pages, and account dashboards without a real API backend.

The stub intercepts all auth API calls locally — no external server needed. It accepts any email and password, exchanges any magic link code, and returns mock session data. Page gating, the header auth button, and gated sections all work exactly as they would in production.

### How it works

The dev server overrides `apiUrl` to point to a local endpoint (`/__auth`) and handles all auth routes in-memory:

| Action | What happens |
|---|---|
| **Login** (any email + password) | Creates a session, logs you in |
| **Signup** (any email + password) | Creates a session, logs you in |
| **Magic link exchange** (any code) | Creates a session, logs you in |
| **Logout** | Clears the session |
| **Account endpoints** | Returns mock user data from the current session |
| **Licenses, activations, API keys** | Returns mock data |

Sessions are stored in memory on the dev server. Restarting the server clears all sessions.

### Testing magic links

Navigate directly to your `afterLogin` page with any magic code in the URL hash:

```
http://localhost:4747/account#magic=anytoken
```

The stub accepts any value as a valid exchange code. You're logged in immediately.

### Testing page gating

1. Set `auth: required` in a page's frontmatter
2. Visit the page while logged out — you're redirected to `/login`
3. Log in with any email and password
4. Visit the gated page again — content is visible

### Testing gated sections

Add `gated:` blocks in your page content. Log in to see them appear. Log out to confirm they're hidden.

### What the stub does not do

The stub is for testing UI flows. It does not:

- Send emails (magic link requests return success but no email is sent)
- Validate passwords (any password is accepted)
- Persist data (sessions clear on server restart)
- Run webhooks (`userDataUrl` calls still go to the configured external URL)

For production auth behavior, configure your real API URL in `settings/auth.md` and deploy.

### Third-party providers

The local auth stub only applies to `provider: custom`. If you use Supabase, Firebase, Clerk, or Auth0, the dev server connects to your provider directly — those providers handle auth in both dev and production.

## What you see vs what ships

The dev server shows you the exact same site that `sitemd deploy` produces. The differences are structural, not visual:

| | Dev server | Production build |
|---|---|---|
| **HTML source** | Skeleton + client hydration | Standalone, fully rendered |
| **Output location** | Memory only | `site/` directory on disk |
| **Navigation** | SPA (no full reloads) | Standard page loads |
| **SEO metadata** | Rendered in memory | Written to HTML, sitemap.xml, robots.txt |
| **Search** | Uses search index from last build | Fresh search-index.json in output |
| **Dev panel** | Available (⌘/) | Not included |
| **Trial banner** | Shown if not activated | Not included |

## Trial vs activated

The dev server behaves the same whether the site is activated or not. All features render fully in both modes.

The only visible differences in trial mode:

- A **trial mode banner** at the bottom of every page
- The **"built with sitemd"** footer badge is always visible
- `sitemd build` and `sitemd deploy` are not available

These are licensing markers, not feature restrictions. Activate your site to unlock production builds. See [Activate a Site](/docs/how-to-activate-site).

## Why skeleton HTML?

The dev server never writes standalone HTML to disk during development. This is by design:

- **Faster rebuilds** — writing to memory is faster than writing files
- **SPA navigation** — instant page transitions during development
- **Source protection** — the dev server binary contains the build logic; skeleton HTML has no value without the running server

Production-ready HTML is produced by `sitemd build` or `sitemd deploy`, both of which require [activation](/docs/how-to-activate-site).

## Starting the dev server

Three ways to start:

```bash
# CLI
sitemd launch

# Agent skill
/launch

# MCP tool
sitemd_build   # with serve mode
```

The dev server watches `pages/`, `settings/`, and `theme/` for changes. Saves trigger a rebuild and the browser refreshes automatically via [Live Build Sync](/docs/live-build-sync).

## Related

- [User Auth & Gating](/docs/user-auth) — full auth setup, gating pages, user types
- [Magic Link Auth](/docs/magic-link-auth) — passwordless login configuration
- [Live Build Sync](/docs/live-build-sync) — file watching, theme sync, auto-reload
- [Dev Panel](/docs/dev-panel) — in-browser editor
- [Build Modes](/docs/build-modes) — trial vs activated
- [Activate a Site](/docs/how-to-activate-site) — unlock production builds
- [Site Diagnostics](/docs/site-diagnostics) — debugging auth and data issues on deployed sites