npm.io
1.1.0 • Published yesterdayCLI

@rankworker/nextjs-blog

Licence
MIT
Version
1.1.0
Deps
16
Size
673 kB
Vulns
0
Weekly
0

@rankworker/nextjs-blog

A complete, customizable, SEO-optimized blog layer for Next.js.
Explore the usage guide »

Report bug · Request feature

Quality npm version npm downloads MIT License Coverage threshold: 90%

Table of Contents
  1. About the project
  2. Getting started
  3. Usage
  4. Contributing
  5. License
  6. Contact
  7. Acknowledgments

About the project

@rankworker/nextjs-blog gives a Next.js App Router project a complete blog without copying the same routing, pagination, metadata, and sitemap code into every app.

  • Paginated index, article, and tag pages
  • MDX rendering with frontmatter and reusable presentation components
  • Canonical metadata, Open Graph tags, JSON-LD, and blog/image sitemaps
  • All presentation components are customizable and can be overridden
  • 2 content stores
    • Local MDX - free, no subscription required
    • Managed RankWorker Headless CMS - paid, subscription required

(back to top)

Getting started

Prerequisites
  • Node.js 20.9+
  • Next.js 16+ with the App Router
  • React 19.2+
Installation

Run the initializer in an existing Next.js project. It installs the library if it is not already listed in package.json, then generates the route adapters and starter configuration:

npx @rankworker/nextjs-blog init

The initializer configures /blog by default. It asks for the content source, site URL, site name, and path, and wraps a conventional existing Next config with withRankWorkerBlog. Use --skip-install to manage the dependency yourself, or --yes with explicit flags for non-interactive setup.

(back to top)

Usage

Local MDX

With local MDX your content lives in the repository.

npx @rankworker/nextjs-blog init \
  --source local-mdx \
  --site-url https://example.com \
  --site-name "Example" \
  --base-path /blog \
  --yes

The initializer creates content/blog/welcome-to-your-blog.mdx as a starter article with a placeholder cover from picsum.photos, and the generated rankworker-blog.ts uses that local source. Adjust the content directory if needed:

import { createLocalMdxSource, defineBlog } from "@rankworker/nextjs-blog";

export const blog = defineBlog({
  source: createLocalMdxSource({ directory: "content/blog" }),
  site: {
    url: "https://example.com",
    name: "Example",
    author: {
      name: "Example Editorial Team",
      url: "https://example.com/about",
      image: "/authors/editorial-team.jpg",
    },
  },
  labels: {
    indexTitle: "Insights",
    indexDescription: "Practical guides for growing your website.",
  },
});

Articles use RankWorker-exported frontmatter and must remain inside the project directory. JavaScript expressions in MDX are blocked by default.

RankWorker API

Use RankWorker as a headless CMS when content is managed through a RankWorker subscription.

npx @rankworker/nextjs-blog init \
  --source rankworker \
  --site-url https://example.com \
  --site-name "Example" \
  --base-path /blog \
  --yes

Set server-only secrets in .env.local:

RANKWORKER_DIRECT_API_KEY=...
RANKWORKER_WEBHOOK_SECRET=...

The generated configuration is equivalent to:

import { createRankWorkerSource, defineBlog } from "@rankworker/nextjs-blog";

export const blog = defineBlog({
  source: createRankWorkerSource({
    apiKey: () => process.env.RANKWORKER_DIRECT_API_KEY,
  }),
  site: { url: "https://example.com", name: "Example" },
  webhook: {
    secret: () => process.env.RANKWORKER_WEBHOOK_SECRET,
    warm: "article-and-index",
  },
});

Configure RankWorker to POST article webhooks to https://example.com/api/rankworker/webhook. The handler verifies the HMAC signature and lazily invalidates cached RankWorker article data, listings, tags, and sitemaps. The library uses standard Next.js fetch caching and does not require Cache Components.

MDX security

MDX can contain JavaScript expressions that execute while the consuming Next.js application renders an article on the server. The library blocks those expressions by default for both local and RankWorker API content.

Only enable JavaScript when every author, CMS account, API response, and content-delivery system in the publishing path is trusted to publish server-side code:

export const blog = defineBlog({
  // source and site
  dangerouslyAllowMdxJavaScript: true,
});

This option retains next-mdx-remote's dangerous-operation checks, but those checks are defense in depth and are not a security sandbox. An author or compromised content system may still be able to consume server resources or invoke configured components in unintended ways. Keep content access restricted, rotate compromised credentials immediately, and apply request and execution limits at the hosting layer.

Custom MDX components

Pass an mdxComponents map to render your own React components from article MDX. The same map works with local MDX and the RankWorker API.

import { createRankWorkerSource, defineBlog } from "@rankworker/nextjs-blog";
import type { ReactNode } from "react";

function Callout({ children }: { children: ReactNode }) {
  return <aside className="callout">{children}</aside>;
}

function ProductLink({ href, children }: { href: string; children: ReactNode }) {
  return (
    <a href={href} className="product-link">
      {children} →
    </a>
  );
}

export const blog = defineBlog({
  source: createRankWorkerSource({
    apiKey: () => process.env.RANKWORKER_DIRECT_API_KEY,
  }),
  site: { url: "https://example.com", name: "Example" },
  mdxComponents: { Callout, ProductLink },
});

Then use the components in an article:

<Callout>Content in a reusable callout.</Callout>

Read our <ProductLink href="/pricing">pricing guide</ProductLink>.

FAQ is included by default and emits FAQPage JSON-LD. Its items array is a JavaScript expression, so enable dangerouslyAllowMdxJavaScript only for a fully trusted content pipeline before using it directly in an article:

<FAQ
  items={[
    {
      question: "What is RankWorker?",
      answer: "RankWorker is an SEO content platform.",
    },
  ]}
/>
Eject components

Default components stay in the package, so upgrades do not overwrite copied templates. “Eject” only the component you need by passing an override:

import type { BlogComponentProps } from "@rankworker/nextjs-blog";
import Link from "next/link";

function ArticleCard({ article, href }: BlogComponentProps["ArticleCard"]) {
  return (
    <article>
      <h2>
        <Link href={href}>{article.title}</Link>
      </h2>
      <p>{article.excerpt}</p>
    </article>
  );
}

export const blog = defineBlog({
  // source and site
  components: { ArticleCard },
});

Available components include Layout, IndexPage, ArticleCard, Pagination, ArticlePage, ArticleHeader, TableOfContents, and ArticleBody.

Custom styles

The generated blog layout imports the default stylesheet. Override its tokens anywhere after that import:

.rw-blog {
  --rw-bg: #fff;
  --rw-text: #171717;
  --rw-accent: #1d4ed8;
  --rw-radius: 0.5rem;
}

Or omit @rankworker/nextjs-blog/styles.css and provide a complete design.

The default Next.js configuration helper allows images from cdn.rankworker.com and the starter article's picsum.photos placeholder. If local MDX or a custom content source references another remote image host, add that host to images.remotePatterns in the consuming application's Next.js configuration.

(back to top)

Contributing

Contributions are welcome. Read CONTRIBUTING.md, keep changes scoped, add tests for behavior changes, and include a Changeset for user-visible changes.

Top contributors
Top contributors

(back to top)

License

Distributed under the MIT License. See LICENSE for details.

Contact

RankWorker - RankWorker.com

Acknowledgments

This project exists thanks to RankWorker, which delivers high-quality, SEO-optimized content creation on autopilot.

(back to top)

Keywords