Scratch
GitHubX

Documentation

#Quick Start

Scratch requires no configuration so it's easy to get started:

# Install scratch
curl -fsSL https://scratch.dev/install.sh | bash

# Create a new project
scratch create

# Start the dev server
scratch dev

Now you're ready to start writing in pages/index.mdx.

#Project Structure

Scratch uses an opinionated project structure and requires no boilerplate or configuration: just create a project, run the dev server, and start writing.

A simple Scratch project (created with scratch create my-scratch-project) looks like this:

my-scratch-project/
pages/
put markdown pages and components here
posts/
index.mdx
accessible at root path (/)
Counter.tsx
public/
static assets
src/
global components and css
AGENTS.md
agent context
package.json
dependencies
.gitignore

Use scratch build to compile this project into a static website, like this one.

#pages/

Markdown files live in pages/ and can be either MDX (.mdx) or vanilla Markdown (.md).

Scratch compiles each Markdown file into a static web page whose route is determined by your project's directory structure:

FileURL
pages/index.mdx/
pages/about.mdx/about/
pages/posts/index.mdx/posts/
pages/posts/hello.mdx/posts/hello/

Component files and libraries can live anywhere in pages/ and src/. They are auto-detected by Scratch and don't need to be explicitly imported in your Markdown files as long as the component name (Counter) matches the component name (Counter.jsx or Counter.tsx).

pages/ can also contain static content like images. These are copied directly into your output directory (dist/) and will be served the same way your compiled Markdown is.

#public/

Add static content like a favicon or _redirects file to the public/ directory. These are copied directly into your output directory (dist/) just like static content in pages/.

#src/

src/ is for CSS files, components and JS/TS libraries. New Scratch projects will contain the following:

#package.json

Scratch automatically installs build dependencies. You can add additional dependencies by editing package.json.

#Commands

#scratch create

Create a new Scratch project.

scratch create [path]

Options:

#scratch dev

Start the development server with live reload.

scratch dev [path]

Options:

#scratch build

Build the project for production.

scratch build [path]

Options:

#scratch preview

Preview the production build locally.

scratch preview [path]

Options:

#scratch view

Quick preview of a single file or directory. Handy for e.g. reading README.md files.

scratch view <path>

Options:

Useful for viewing individual .md or .mdx files without setting up a full project.

#scratch clean

Remove build artifacts.

scratch clean [path]

Removes the dist/ and .scratch-build-cache/ directories.

#scratch checkout

Restore template files from built-in templates.

scratch checkout [file]

Options:

#scratch update

Update Scratch to the latest version.

scratch update

#Global Options

These options work with all commands:

#Writing Content

#Frontmatter

Add YAML frontmatter at the top of your MDX files to set page metadata. These properties are automatically converted to HTML meta tags for SEO and social sharing.

Basic Properties

PropertyDescription
titlePage title. Sets <title>, og:title, and twitter:title
descriptionPage description for SEO. Sets meta description, og:description, and twitter:description
keywordsKeywords for SEO. Can be a string or array (arrays are joined with ", ")
authorPage author. Sets meta[name="author"]
robotsRobots directive (e.g., "index, follow")
langHTML language attribute (e.g., "en")
canonicalCanonical URL. Sets <link rel="canonical">

Open Graph Properties

PropertyDescriptionDefault
imageSocial sharing image URL. Sets og:image and twitter:image-
urlCanonical Open Graph URL. Sets og:url-
typeContent type. Sets og:type"article"
siteNameSite name. Sets og:site_name-
localeLocale (e.g., "en_US"). Sets og:locale-
siteUrlBase URL for resolving relative image paths-

Twitter Card Properties

PropertyDescriptionDefault
twitterCardCard type. Sets twitter:card"summary_large_image"
twitterSiteSite's Twitter handle (e.g., "@mysite"). Sets twitter:site-
twitterCreatorAuthor's Twitter handle. Sets twitter:creator-

Article Properties

PropertyDescription
publishDatePublication date (ISO format). Sets article:published_time
modifiedDateLast modified date (ISO format). Sets article:modified_time
tagsArticle tags. Can be string or array. Sets article:tag

Example

---
title: "My Page Title"
description: "A brief description for SEO and social sharing"
keywords: ["react", "markdown", "static site"]
author: "Your Name"
image: "/og-image.png"
type: "article"
siteName: "My Site"
locale: "en_US"
twitterCard: "summary_large_image"
twitterSite: "@mysite"
publishDate: "2025-01-01"
tags: ["tutorial", "guide"]
canonical: "https://example.com/my-page"
lang: "en"
siteUrl: "https://example.com"
---

Note: Image URLs can be absolute (starting with http:// or https://) or relative paths. Relative paths are resolved against siteUrl if provided.

#Using Components

Components in src/ or pages/ are automatically available in MDX files:

# My Page

<Counter />

<Button>Click me</Button>

The component filename must match the component name (e.g., Counter.tsx exports Counter).

#Component Patterns

Self-closing (wrapped in not-prose div):

<Chart />

Inline children:

<Button>Click me</Button>

Block children (requires blank lines):

<Callout>

## Warning

This is **markdown** inside a component.

</Callout>

#Styling

#Tailwind CSS

Scratch uses Tailwind CSS. Edit src/tailwind.css for global styles:

@import 'tailwindcss';
@plugin "@tailwindcss/typography";

/* Custom styles */
.prose a {
  @apply text-blue-600 hover:text-blue-800;
}

#Typography

Markdown content is styled with Tailwind Typography. Use prose modifiers in src/template/PageWrapper.jsx:

<div className="prose prose-lg prose-slate">
  {children}
</div>

Element modifiers: prose-h1:, prose-a:, prose-p:, prose-code:, prose-pre:, etc.

#Excluding from Prose

Use the not-prose class to exclude elements from typography styling:

<div className="not-prose">
  <CustomComponent />
</div>

#PageWrapper

Create src/template/PageWrapper.jsx to wrap all pages with a layout:

export default function PageWrapper({ children }) {
  return (
    <div className="max-w-2xl mx-auto p-8">
      <nav>...</nav>
      <main className="prose">{children}</main>
      <footer>...</footer>
    </div>
  );
}

#Custom Markdown Components

Override default markdown rendering by creating components in src/markdown/:

// src/markdown/Link.tsx
export default function Link({ href, children, ...props }) {
  const isExternal = href?.startsWith('http');
  return (
    <a
      href={href}
      target={isExternal ? '_blank' : undefined}
      rel={isExternal ? 'noopener noreferrer' : undefined}
      {...props}
    >
      {children}
    </a>
  );
}

Export from src/markdown/index.ts:

export { default as a } from './Link';
export { default as pre } from './CodeBlock';
export { default as h1, default as h2 } from './Heading';

#Syntax Highlighting

Code blocks are highlighted with Shiki. Control highlighting with the --highlight flag:

#Build Pipeline

When you run scratch build, Scratch compiles your MDX files into a fully static website. There's no server-side code running in production—everything is pre-rendered HTML, CSS, and JavaScript that can be hosted on any static file server.

Scratch supports defaults that make it easy to create beautiful & functional websites with your writing. Here's a description of the Scratch build pipeline:

#Build Steps

1. Dependency Resolution

Scratch auto-installs npm dependencies from your package.json using Bun. Dependencies are cached in .scratch-build-cache/ for faster subsequent builds.

2. Entry Generation

For each .mdx or .md file in pages/, Scratch generates client and server entry files that import your content and wire up React rendering.

3. MDX Compilation

MDX files are compiled through a pipeline of remark and rehype plugins:

Remark plugins (process Markdown AST):

Rehype plugins (process HTML AST):

4. Tailwind Compilation

Scratch compiles your CSS using Tailwind CSS v4. Only the utilities actually used in your content are included in the final bundle.

5. Server Build

Scratch builds a server bundle to pre-render each page. The "server bundle" doesn't actually run on a server; it's only used during the build process to generate pre-rendered HTML.

6. Client Build

The client JavaScript is bundled with Bun's bundler. Output is minified for production with content-hashed filenames for cache busting.

7. HTML Generation

Each page is rendered to static HTML with:

8. Static Assets

Files from public/ are copied to the output directory.

9. Output

The final static site is written to dist/, ready for deployment to any static host.

#Deployment

Build your site and deploy the dist/ folder to any static host:

scratch build

For subdirectory deployment, use the --base flag:

scratch build --base /my-site/

#Generated Files

Add these to .gitignore:

dist/
.scratch-build-cache/
node_modules/