Rocket
On this page

Configuration#

Rocket reads project configuration from rocket-config.js in the current working directory unless the CLI is given another config file. The config decides which files become Pages, which files are ignored, how the dev server is adjusted, and which deployment adapter handles request-time Pages.

Basic config#

Create rocket-config.js at the project root:

/** @type {import('@rocket/js/types.js').RocketConfig} */
export default {
  includeGlobs: ['src/pages/**/*.rocket.{md,js}'],
};

The file is an ES module and must have a default export. Rocket reads the config before it loads Pages, so config imports should be server-safe and should not depend on Page output.

Config shape#

type RocketConfig = {
  includeGlobs: string[];
  excludeRegex?: (string | RegExp)[];
  adjustDevServerConfig?: (config: DevServerConfig) => DevServerConfig;
  adapter?: RocketAdapter;
  siteOrigin?: string;
  siteHeadMetadata?: {
    siteName: string;
    defaultDescription: string;
    language: string;
    icons?: {
      ico?: string;
      svg?: string;
      appleTouchIcon?: string;
    };
    themeColor?: string;
    socialPreview?: {
      delivery?: 'static';
      template?: (data: SocialPreviewTemplateData) => string;
    };
  };
  iconLibraries?: IconLibrariesConfig;
  defaultIconLibrary?: string;
  siteDiscoverability?: {
    sitemap?: boolean;
    robots?: boolean;
  };
  urlLifecycle?: {
    redirects?: {
      source: string;
      target: string;
      status?: 301 | 302 | 307 | 308;
    }[];
  };
};

includeGlobs is required. Keep the list narrow enough that Rocket only discovers Page files.

excludeRegex removes matching file paths from discovery. Each entry is checked against the file path either as string inclusion or as a regular expression. node_modules is always excluded.

adjustDevServerConfig receives Rocket's default @web/dev-server config and returns the config that should be used locally.

adapter is required only when the project has Pages with config.render: 'server'.

siteOrigin is the canonical absolute origin for the deployed site. Configure it when Rocket needs to emit generated outputs or Site Head Metadata with public absolute URLs.

siteHeadMetadata controls browser and social identity metadata emitted by Rocket-owned document helpers. It is disabled by default.

Social Preview Images are configured under siteHeadMetadata.socialPreview, not under siteDiscoverability.

siteDiscoverability controls crawler-facing files generated by rocket build. All outputs are off by default.

urlLifecycle controls public URL preservation and change rules, initially exact-path Redirects.

iconLibraries configures trusted SVG libraries for the Rocket Icon component. defaultIconLibrary selects the library used by <rocket-icon name="..."></rocket-icon> when the host omits library.

Public Assets do not need project config. Files under public/ are served by rocket start and copied by rocket build at stable root-relative URLs.

Page discovery#

Rocket discovers Markdown Pages and JavaScript Pages from includeGlobs:

export default {
  includeGlobs: ['docs/**/*.rocket.{md,js}', 'src/pages/**/*.rocket.{md,js}'],
};

Each discovered file must export a Page config with a unique path.

When an includeGlobs entry looks like a directory path and does not contain * or ., Rocket expands it to include everything below that directory:

export default {
  includeGlobs: ['docs'],
};

For predictable projects, prefer explicit globs such as docs/**/*.rocket.{md,js}.

Excluding Pages#

Use excludeRegex for drafts, generated files, or fixtures that live near real Pages:

export default {
  includeGlobs: ['src/**/*.rocket.{md,js}'],
  excludeRegex: [/\.draft\.rocket\.md$/, '/fixtures/'],
};

String entries match when the file path includes that string. Regular expressions match with pattern.test(filePath).

Dev server config#

Rocket starts @web/dev-server with defaults for Page rendering, package resolution, watching, browser opening, and port 8888. Use adjustDevServerConfig to change only the parts your project owns:

export default {
  includeGlobs: ['src/pages/**/*.rocket.{md,js}'],
  adjustDevServerConfig: config => ({
    ...config,
    port: 3000,
    open: false,
  }),
};

Keep Rocket's plugin list unless you are deliberately replacing Page serving behavior.

Deployment adapter#

Static-only sites do not need an adapter. Add one when at least one Page uses config.render: 'server':

import { netlify } from '@rocket/js/adapters/netlify.js';

/** @type {import('@rocket/js/types.js').RocketConfig} */
export default {
  includeGlobs: ['src/pages/**/*.rocket.{md,js}'],
  adapter: netlify(),
};

Without an adapter, rocket build fails early when it finds server-rendered Pages.

Icon Libraries#

Configure project-owned Icon Libraries in rocket-config.js:

import { iconsFromPackage, iconsFromPath } from '@rocket/js/icons.js';

/** @type {import('@rocket/js/types.js').RocketConfig} */
export default {
  includeGlobs: ['src/pages/**/*.rocket.{md,js}'],
  iconLibraries: {
    bootstrap: iconsFromPackage('bootstrap-icons', 'icons/*.svg'),
    local: iconsFromPath('./src/icons/*.svg'),
  },
  defaultIconLibrary: 'bootstrap',
};

Package-backed sources resolve files from an installed npm package. Trusted local folder sources resolve files from the project. Icon names come from SVG file basenames, so icons/alarm.svg is referenced as name="alarm".

Reusable layouts can also supply Icon Libraries during render. Project iconLibraries are layered with the active layout's libraries, but a project library cannot use the same name as a library supplied by that layout in this first slice.

For packages with separate styles or families that reuse filenames, configure each style as a separate Icon Library:

import { iconsFromPackage } from '@rocket/js/icons.js';

export default {
  includeGlobs: ['src/pages/**/*.rocket.{md,js}'],
  iconLibraries: {
    'fa-solid': iconsFromPackage('@fortawesome/fontawesome-free', 'svgs/solid/*.svg'),
    'fa-regular': iconsFromPackage('@fortawesome/fontawesome-free', 'svgs/regular/*.svg'),
  },
};

Configured SVG sources are trusted. Rocket inserts the SVG bytes as server-rendered Icon Component content and does not sanitize, rewrite, normalize, or fetch remote icon URLs in this first slice.

When a Page uses icon-loading="client", Rocket resolves the Icon References during server rendering, emits an Icon Manifest, and publishes only the referenced SVG files as generated local assets. Generated asset URLs are deterministic Rocket-owned paths with content hashes, such as /_rocket/icons/bootstrap/alarm.4f3a2c9d8e11.svg. The browser rocket-icon runtime fetches only URLs listed in that manifest; icons absent from the manifest cannot be fetched by client-created or mutated elements.

For author-facing icon usage, see Rocket Icon.

Document Baseline Metadata#

Rocket-owned document helpers always emit Document Baseline Metadata for HTML documents they create:

Document Baseline Metadata is separate from Site Head Metadata. It is emitted whether or not siteHeadMetadata is configured, so Site Authors do not need to opt into launch-facing identity metadata to get the generic document baseline.

Site Head Metadata#

Enable Site Head Metadata when Rocket should own the repeated browser and social identity metadata for rendered Pages:

/** @type {import('@rocket/js/types.js').RocketConfig} */
export default {
  includeGlobs: ['src/pages/**/*.rocket.{md,js}'],
  siteOrigin: 'https://docs.example.com',
  siteHeadMetadata: {
    siteName: 'Acme Docs',
    defaultDescription: 'Guides and reference for Acme UI components.',
    language: 'en',
    icons: {
      ico: '/favicon.ico',
      svg: '/favicon.svg',
      appleTouchIcon: '/apple-touch-icon.png',
    },
    themeColor: '#123456',
    socialPreview: {},
  },
};

siteHeadMetadata.siteName, siteHeadMetadata.defaultDescription, and siteHeadMetadata.language are required non-empty strings. siteOrigin is also required because canonical and social URLs must be absolute public URLs. Use only an origin, such as https://docs.example.com, without a path, query string, or hash.

Pages rendered through Rocket's document helper receive:

The home Page title is the site name. Other Page titles are formatted as Page Metadata title | site name. Descriptions use config.metadata.description from the current Page when present and fall back to siteHeadMetadata.defaultDescription. Canonical and social URLs use siteOrigin plus the current concrete Page path.

siteHeadMetadata.icons accepts Site Author-provided Favicon Asset references. Rocket emits only the configured references:

Rocket does not generate, transform, or existence-check Favicon Assets.

siteHeadMetadata.themeColor emits <meta name="theme-color"> when present.

Social Preview Images#

Social Preview Images are the images social platforms show when a Page URL is shared. Rocket can generate Default Social Preview Images from a project-level template, and individual Pages can point at Explicit Social Preview Images when they need a hand-authored or externally hosted card.

Both options are part of Site Head Metadata. Configure generated defaults in siteHeadMetadata.socialPreview; configure one-off Page images in config.siteHeadMetadata.socialPreview.image.

Default Images#

Add an empty socialPreview object to generate a Default Social Preview Image for each eligible Page during rocket build:

/** @type {import('@rocket/js/types.js').RocketConfig} */
export default {
  includeGlobs: ['src/pages/**/*.rocket.{md,js}'],
  siteOrigin: 'https://docs.example.com',
  siteHeadMetadata: {
    siteName: 'Acme Docs',
    defaultDescription: 'Guides and reference for Acme UI components.',
    language: 'en',
    socialPreview: {},
  },
};

The playground below renders the same built-in template Rocket uses for Default Social Preview Image capture:

An empty socialPreview object uses static delivery, the default and currently only delivery strategy. Writing socialPreview: { delivery: 'static' } is equivalent.

During rocket build, Rocket renders the built-in Social Preview Template, captures it in Chromium at 1200x630, writes a fingerprinted PNG under /_rocket/social-preview/<fingerprint>.png, and emits the absolute public image URL as both og:image and twitter:image. Pages with an Explicit Social Preview Image skip generated default image capture.

Default Social Preview Images are generated for configured concrete Pages and generated paginated archive Page variants. Each generated archive URL uses its concrete public path, such as /blog/2/, for canonical metadata, Social Preview Template data, the image fingerprint, and the emitted image metadata. Parameterized Pages remain excluded until Rocket has a static params Module that can enumerate their public URLs.

Standalone Demo URLs are excluded from Default Social Preview Image generation by default. They are focused child documents for inspecting one demo, not separate Page entries with their own social identity; the parent Markdown Page remains eligible for a Social Preview Image.

Custom Templates#

Use siteHeadMetadata.socialPreview.template when the built-in card design should match your site:

/** @type {import('@rocket/js/types.js').RocketConfig} */
export default {
  includeGlobs: ['src/pages/**/*.rocket.{md,js}'],
  siteOrigin: 'https://docs.example.com',
  siteHeadMetadata: {
    siteName: 'Acme Docs',
    defaultDescription: 'Guides and reference for Acme UI components.',
    language: 'en',
    socialPreview: {
      template({ site, page }) {
        return `<!doctype html>
<html lang="${site.language}">
  <head>
    <meta charset="utf-8">
    <style>
      html, body { width: 1200px; height: 630px; margin: 0; }
      body { display: grid; place-items: center; font-family: system-ui; }
    </style>
  </head>
  <body>
    <main>
      <p>${site.name}</p>
      <h1>${page.title}</h1>
      <p>${page.description}</p>
    </main>
  </body>
</html>`;
      },
    },
  },
};

socialPreview.template must be a function value in rocket-config.js, not a string path. It receives normalized site and Page facts:

type SocialPreviewTemplateData = {
  site: {
    name: string;
    defaultDescription: string;
    language: string;
    themeColor?: string;
  };
  page: {
    pathname: string;
    /** Page Metadata title, without the site name suffix. */
    title: string;
    /** Full HTML document title. */
    documentTitle: string;
    description: string;
    canonicalUrl: string;
    language: string;
  };
};

The function returns HTML accepted by Social Preview Capture. Normal browser-compatible HTML and CSS can be used because Rocket captures the rendered template in Chromium. Keep template dimensions at 1200x630 unless your layout intentionally controls overflow inside that viewport.

page.title is the Page Metadata title, so templates can render it next to site.name without duplicating the site name. Use page.documentTitle when a template needs the full HTML document title. page.description is the Page Metadata description when present, otherwise site.defaultDescription.

Build Output And Caching#

Static delivery fingerprints each Default Social Preview Image from the inputs that can affect the captured pixels: the selected template, normalized template data, site origin, Page path, output dimensions, rendered template HTML, and Rocket's Social Preview renderer version. Unrelated Page body content is not part of the fingerprint unless your template data includes content-derived values.

Rocket stores captured images in .rocket/social-preview-images/ and reuses a cached image when the fingerprint is unchanged. The emitted URL contains the fingerprint, so generated preview images are immutable and safe for long-lived CDN or browser caches. Restore .rocket/social-preview-images/ in CI before rocket build to avoid recapturing unchanged images; missing cache entries are regenerated normally. Changes to template source, template configuration, site facts, Page title or description, canonical URL, dimensions, local assets included by the rendered template HTML, or Rocket's renderer version invalidate the cached image and produce a new hash-named asset.

Social Preview Capture uses puppeteer-core with @sparticuz/chromium in Linux serverless and Lambda-style environments. Local macOS and Windows builds use a local Chromium-compatible browser; set PUPPETEER_EXECUTABLE_PATH when Chrome, Chromium, Edge, or Brave is not installed in a standard location. If browser capture fails, rocket build fails instead of rendering metadata that points at a missing Default Social Preview Image.

Previewing Templates#

During local development, run rocket start and open /_rocket/social-preview-template-preview/ to inspect Social Preview Templates without creating public Pages or static build artifacts. The preview page lists available Page paths, embeds the live template document at the Social Preview Capture viewport, and links to the captured PNG output. Choose a Page with ?page=/guides/runtime or target a full URL with ?url=https://docs.example.com/guides/runtime. Add title and description query parameters to try longer sample text while tuning fit:

/_rocket/social-preview-template-preview/?page=/guides/runtime&title=Long%20sample%20title

The raw template document is available at /_rocket/social-preview-template-preview/template?page=/guides/runtime, and the captured image response is available at /_rocket/social-preview-template-preview/image.png?page=/guides/runtime. Template, style, Page, and config edits update through the normal development server reload or restart workflow. These preview routes are development-time behavior by default; rocket build does not add them to the Page Registry, Page Collections, configured Pages, or normal static output.

Explicit Page Images#

Page-level HTML indexing metadata is configured on the Page under config.siteHeadMetadata, not in project config.

Page-level Explicit Social Preview Images are configured on the Page under config.siteHeadMetadata.socialPreview.image:

export const config = {
  path: '/guides/runtime',
  siteHeadMetadata: {
    socialPreview: {
      image: 'social/card.png',
    },
  },
};

Explicit images work even when project-level Default Social Preview Images are not enabled, as long as Site Head Metadata is enabled for the project. An Explicit Social Preview Image takes precedence over the generated Default Social Preview Image for that Page.

The image source may be:

Rocket resolves Page-relative and site-root paths with siteOrigin so emitted og:image and twitter:image values are absolute public URLs. For example, on /guides/runtime, social/card.png resolves to https://docs.example.com/guides/runtime/social/card.png when siteOrigin is https://docs.example.com.

Explicit Social Preview Images are metadata references only. Rocket does not generate, transform, copy, or existence-check the image file. For a source-controlled image that should be served from the site root, put it under public/, such as public/social/card.png, and reference /social/card.png. Use a Page-relative URL only when your deployment serves the file at that public route.

Site Discoverability#

Enable the Sitemap when you want rocket build to emit dist/sitemap.xml:

/** @type {import('@rocket/js/types.js').RocketConfig} */
export default {
  includeGlobs: ['src/pages/**/*.rocket.{md,js}'],
  siteOrigin: 'https://docs.example.com',
  siteDiscoverability: {
    sitemap: true,
  },
};

The Sitemap is disabled unless siteDiscoverability.sitemap is explicitly true. Configuring siteOrigin alone does not emit generated files.

When the Sitemap is enabled, siteOrigin is required because Sitemap URLs must be absolute public URLs. Use only an origin, such as https://docs.example.com, without a path, query string, or hash.

The Sitemap includes public concrete static Pages and public concrete server-rendered Pages by default. menu: false only hides a Page from navigation; it does not remove the Page from the Sitemap.

Use Page-level discoverability.sitemap: false when a Page should keep rendering and keep its menu behavior but stay out of sitemap.xml:

export const config = {
  path: '/release-notes/internal',
  metadata: { title: 'Internal release notes' },
  discoverability: {
    sitemap: false,
  },
};

discoverability.sitemap controls only Sitemap inclusion. menu: false controls only navigation. You can use either option independently, or combine them when a Page should be hidden from both the Sitemap and menus.

Parameterized Pages are excluded until Rocket has a static params Module that can enumerate their public URLs. Standalone Demo URLs are also excluded; the parent Markdown Page remains eligible.

Enable the Robots File when you want rocket build to emit dist/robots.txt:

/** @type {import('@rocket/js/types.js').RocketConfig} */
export default {
  includeGlobs: ['src/pages/**/*.rocket.{md,js}'],
  siteOrigin: 'https://docs.example.com',
  siteDiscoverability: {
    robots: true,
  },
};

The Robots File is disabled unless siteDiscoverability.robots is explicitly true. It also requires siteOrigin because the generated file includes a canonical Sitemap: reference:

Sitemap: https://docs.example.com/sitemap.xml

The Robots File can be generated with or without dist/sitemap.xml. Set both siteDiscoverability.robots and siteDiscoverability.sitemap to true when you want rocket build to emit both crawler-facing files.

When the Robots File is enabled, Page-level discoverability.robots controls whether that Page adds a crawler directive to robots.txt:

export const config = {
  path: '/release-notes/internal',
  metadata: { title: 'Internal release notes' },
  discoverability: {
    robots: 'disallow',
  },
};

discoverability.robots: 'disallow' emits Disallow: /release-notes/internal. discoverability.robots: 'allow', or omitting discoverability.robots, emits no Page-specific Disallow directive.

Robots Page Options are independent of Sitemap inclusion, Page rendering, and navigation. discoverability.robots only controls Robots File crawler directives; it does not add HTML noindex metadata. Use discoverability.sitemap: false separately when a Page should be omitted from sitemap.xml.

URL Lifecycle Redirects#

Use urlLifecycle.redirects when an existing public URL should send visitors to a new URL before Rocket loads or renders a Page:

/** @type {import('@rocket/js/types.js').RocketConfig} */
export default {
  includeGlobs: ['src/pages/**/*.rocket.{md,js}'],
  urlLifecycle: {
    redirects: [
      { source: '/old-guide', target: '/guides/new-guide' },
      { source: '/external-docs', target: 'https://docs.example.com/', status: 302 },
    ],
  },
};

Redirect source values are internal absolute paths and are matched exactly against the request pathname. Rocket does not normalize trailing slashes for Redirects, so /old-guide and /old-guide/ are different sources. Redirect sources must be unique and cannot use a URL owned by a configured Page or by Rocket-generated output such as Standalone Demo URLs or generated archive Pages.

Redirect target values may be internal absolute paths or absolute http:/https: URLs. Rocket sends the target value in the Location header. Targets are not required to exist in the project, so they may point to future Pages, Rocket-generated output, or external destinations.

Redirects use status 308 by default. Set status to 301, 302, 307, or 308 when a rule needs a specific redirect status. Rocket validates Redirect rules during project setup and static builds so invalid paths, unsupported statuses, duplicate sources, and ambiguous source collisions fail early with an actionable error.

In adapterless static builds, Rocket emits an HTML fallback file at each Redirect source. The fallback uses an instant meta refresh, a small script redirect, and a canonical link that points to the configured target, so static hosts without native redirect configuration can still send visitors to the new URL. These fallback files are generated output, not Pages: they do not appear in PageData navigation, Page Registry queries, or sitemap.xml.

HTML fallback redirects are less precise than native HTTP redirects. A static host serves the fallback document with its normal file status, usually 200, because HTML cannot represent the configured HTTP redirect status. Static host file resolution can also normalize extensionless paths and trailing slashes, so fallback files cannot guarantee Rocket's exact source matching on every host. Use a deployment adapter with native Redirect output when crawlers, clients, or method-preserving redirects need the configured 301, 302, 307, or 308 status.

Alternate config file#

Use the CLI -c option when a project has more than one Rocket config:

npx rocket -c ./config/rocket-docs.config.js start
npx rocket -c ./config/rocket-docs.config.js build

The path is resolved from the current working directory.

Common fixes#