npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@pas7/nextjs-sitemap-hreflang

v0.7.3

Published

Add and validate hreflang alternates + x-default for Next.js sitemaps (App Router / MetadataRoute) with a tiny library + CLI postbuild fixer.

Downloads

707

Readme

@pas7/nextjs-sitemap-hreflang

CI npm version npm downloads License: MIT

Routing-agnostic hreflang toolkit for Next.js sitemaps:

  • build hreflang alternates for App Router MetadataRoute.Sitemap
  • inject/fix hreflang directly in generated XML
  • validate sitemap hreflang in CI
  • support mixed content pipelines (.ts, .json, .md/.mdx, CMS)

Install

npm i @pas7/nextjs-sitemap-hreflang

Migration guide (unscoped -> scoped)

npm uninstall nextjs-sitemap-hreflang
npm i @pas7/nextjs-sitemap-hreflang

Update imports:

// before
import { withHreflang } from "nextjs-sitemap-hreflang";

// after
import { withHreflang } from "@pas7/nextjs-sitemap-hreflang";

CLI binary stays the same:

npx nextjs-sitemap-hreflang check --fail-on-missing

Quick start: App Router

import type { MetadataRoute } from "next";
import {
  withHreflangFromRouting,
  routingPrefixAsNeeded,
} from "@pas7/nextjs-sitemap-hreflang";

const routing = routingPrefixAsNeeded({
  defaultLocale: "en",
  locales: ["en", "uk", "de"],
});

export default function sitemap(): MetadataRoute.Sitemap {
  const entries: MetadataRoute.Sitemap = [
    { url: "https://example.com/blog" },
    { url: "https://example.com/about" },
  ];

  return withHreflangFromRouting(entries, routing, {
    baseUrl: "https://example.com",
    ensureXDefault: true,
  });
}

Next.js App Router + static export (sitemap.xml)

Use library generation + XML validation in CI:

next build
npx nextjs-sitemap-hreflang check --fail-on-missing

Optional postbuild fix step:

npx nextjs-sitemap-hreflang inject --out public/sitemap.xml

Auto-detect order when --in is not provided:

  1. public/sitemap.xml
  2. out/sitemap.xml
  3. sitemap.xml

Prefer explicit source when needed:

npx nextjs-sitemap-hreflang check --fail-on-missing --prefer out
npx nextjs-sitemap-hreflang inject --prefer public --out public/sitemap.xml

Generate machine-readable CI report:

npx nextjs-sitemap-hreflang check --fail-on-missing --prefer out --json > report.json

Next.js Full SEO Stack (App Router)

app/sitemap.ts:

import type { MetadataRoute } from "next";
import { routingPAS7, withHreflangFromRouting } from "@pas7/nextjs-sitemap-hreflang";

const baseUrl = "https://example.com";

const routing = routingPAS7({
  defaultLocale: "en",
  locales: ["en", "uk", "de", "it", "hr"],
  suffixPaths: ["/blog", "/projects", "/services", "/cases", "/contact", "/about", "/privacy", "/terms"],
  detailPathPattern: /^\/(blog|projects|services|cases)\//,
});

export default function sitemap(): MetadataRoute.Sitemap {
  return withHreflangFromRouting(
    [
      { url: `${baseUrl}/` },
      { url: `${baseUrl}/blog` },
      { url: `${baseUrl}/blog/en/hello-world` },
      { url: `${baseUrl}/contact` },
    ],
    routing,
    { baseUrl, ensureXDefault: true },
  );
}

app/robots.ts:

import type { MetadataRoute } from "next";

export default function robots(): MetadataRoute.Robots {
  return {
    rules: { userAgent: "*", allow: "/" },
    sitemap: "https://example.com/sitemap.xml",
  };
}

CI script:

next build
npx nextjs-sitemap-hreflang check --fail-on-missing

Universal manifest helper (.ts / .json / .md)

If your pipeline already outputs slug + locales + date, use:

import { createSitemapEntriesFromManifest } from "@pas7/nextjs-sitemap-hreflang";

const entries = createSitemapEntriesFromManifest(blogManifest, {
  baseUrl: "https://pas7.com.ua",
  sectionPath: "/blog",
  defaultLocale: "en",
  routeStyle: "locale-segment", // /blog/en/slug
});

If your content keeps images in nested fields (for example hero.cover + section screenshots), pass imagesFor so the sitemap entry includes all image URLs:

const entries = createSitemapEntriesFromManifest(posts, {
  baseUrl: "https://pas7.com.ua",
  sectionPath: "/blog",
  defaultLocale: "en",
  routeStyle: "locale-segment",
  imagesFor: (post) => [
    post.hero.cover.src,
    ...post.sections.flatMap((section) => section.screenshots?.map((s) => s.src) ?? []),
  ],
});

routingPAS7 with suffixPaths and prefixPaths

import { routingPAS7 } from "@pas7/nextjs-sitemap-hreflang";

const routing = routingPAS7({
  defaultLocale: "en",
  locales: ["en", "uk", "de"],
  // /blog/uk, /contact/uk
  suffixPaths: ["/blog", "/projects", "/services", "/cases", "/contact", "/about", "/privacy", "/terms"],
  // /uk/about (if needed for some sections)
  prefixPaths: ["/about"],
  // keeps highest priority for locale-segment detail pages
  detailPathPattern: /^\/(blog|projects|services|cases)\//,
});

Hybrid recipes:

  • Home pages: prefix-as-needed (/, /uk, /de)
  • Content hubs and static pages: suffix locale (/blog/uk, /contact/uk)
  • Detail pages: locale segment (/blog/en/slug, /blog/uk/slug)
  • Optional mixed prefix pages via prefixPaths (/uk/about)

Routing priority inside routingPAS7:

  1. detailPathPattern
  2. suffixPaths (or legacy hubPaths)
  3. prefixPaths
  4. fallback prefix-as-needed

CLI

inject

npx nextjs-sitemap-hreflang inject \
  --x-default loc \
  --canonical-locale en \
  --prefer public \
  --order canonical-first \
  --trailing-slash never

check

npx nextjs-sitemap-hreflang check \
  --prefer out \
  --origin-policy same \
  --fail-on-missing

JSON report format

--json output is stable and includes:

  • ok
  • issues[] (with code, entryUrl, message, suggestion)
  • summary.byCode
  • inputPath
  • timingMs

Exit codes

  • 0: OK
  • 2: validation errors (--fail-on-missing)
  • 4: input not found
  • 5: invalid XML input

Release and npm publish

Single workflow in .github/workflows/ci.yml:

  1. add changeset (npm run changeset)
  2. push to main
  3. workflow runs ci -> release
  4. version/tag/release/npm publish are automated

Required secret: NPM_TOKEN.

Contribution policy (required)

  • Any user-facing code change must include a changeset (.changeset/*.md).
  • Any API/feature behavior change must include README.md updates in the same PR.
  • CI enforces both rules on pull requests.

Maintained by PAS7 Studio

  • Website: https://pas7.com.ua/
  • Blog: https://pas7.com.ua/blog
  • Contact: https://pas7.com.ua/contact

License

MIT, PAS7 Studio