# How to Add a Blog to a Next.js Site on Vercel

> Add a free blog at yourdomain.com/blog to a Next.js app on Vercel with one middleware file and one environment variable. No new pages, no CMS and no database.

Canonical page: [https://tryrankwise.com/resources/guides/add-blog-nextjs-vercel](https://tryrankwise.com/resources/guides/add-blog-nextjs-vercel). Updated 2026-10-30. Published by Rankwise (tryrankwise.com).

You can add a blog to a **Next.js** app on **Vercel** without building blog pages, a CMS or a database. One middleware file rewrites every request under /blog to your Rankwise blog. Readers and search engines see yourdomain.com/blog, and your app keeps every other route.

This guide covers:

- [What you need](#what-you-need)
- [Step 1: Create the blog in Rankwise](#step-1-create-the-blog-in-rankwise)
- [Step 2: Add the middleware file](#step-2-add-the-middleware-file)
- [Step 3: Set the token on Vercel](#step-3-set-the-token-on-vercel)
- [Step 4: Deploy and check](#step-4-deploy-and-check)
- [Next.js 16 and proxy.ts](#nextjs-16-and-proxyts)
- [Troubleshooting](#troubleshooting)

At the end, your blog lives at yourdomain.com/blog with its own sitemap, RSS feed and llms.txt.

## What you need

- **A Rankwise account.** The [free blog](/free-blog) is enough. It covers 10,000 visits a month.
- **A Next.js app** that you deploy on Vercel, with your domain connected to the Vercel project.
- **A free path.** Your app must not already have pages under /blog. This guide uses /blog.

The middleware also runs on a Next.js app you host yourself on a Node.js server or in Docker. It does not run on a static export (`output: "export"`), because the Next.js docs list static export as unsupported for this file.

## Step 1: Create the blog in Rankwise

1. Sign up for Rankwise. On the free blog page, choose **Put it on my own domain at /blog instead**.
2. Open the setup for the blog. Choose **On my own site**.
3. Choose **A path, like /blog**.
4. Enter the blog name, one line about the blog, your website (for example https://yourdomain.com) and the path, for example /blog.
5. Click **Create my blog**.
6. Rankwise shows three snippets. Pick **Next.js (Vercel)** and copy it.

The token is in the last line of the snippet. Rankwise shows it only once, so copy the whole snippet before you leave the page.

This guide covers a blog at a path. To put the blog on a subdomain like blog.yourdomain.com, choose **A subdomain, like blog.yourdomain.com** instead. The snippet then forwards every path on that host, so copy it from the app rather than from this page.

## Step 2: Add the middleware file

Create `middleware.ts` at the root of your Next.js app, next to the `app` or `pages` folder (inside `src` if your app uses one). Paste the snippet from Rankwise. It looks like this, with your own blog id:

```ts
// middleware.ts at the root of your Next.js app.
import { NextResponse, type NextRequest } from "next/server"

const PREFIX = "/blog"
const UPSTREAM = "https://rankwiseblog.com/hosted/YOUR-BLOG-ID"
const TOKEN = process.env.RANKWISE_BLOG_TOKEN ?? ""

export function middleware(request: NextRequest) {
  const { pathname, search, host } = request.nextUrl
  const rest = pathname.slice(PREFIX.length)
  const headers = new Headers(request.headers)
  headers.set("x-rankwise-blog-token", TOKEN)
  headers.set("x-rankwise-forwarded-host", host)
  headers.set(
    "x-rankwise-visitor-ip",
    (request.headers.get("x-forwarded-for") ?? "").split(",")[0].trim()
  )
  return NextResponse.rewrite(new URL(UPSTREAM + rest + search), {
    request: { headers }
  })
}

// Next.js needs literal values here.
export const config = {
  matcher: ["/blog", "/blog/:path*"]
}

// Set this in your Vercel project settings:
// RANKWISE_BLOG_TOKEN=YOUR-TOKEN
```

Here is what each part does:

- **The matcher** runs the middleware only for /blog and the paths under it. Every other route in your app works as before.
- **The rewrite** fetches the page from your Rankwise blog and serves it at your address. The browser never leaves your domain.
- **The headers** tell Rankwise that the request comes from your app (the token) and which domain serves it (the host). The visitor's IP address, from `x-forwarded-for`, lets Rankwise limit spam sign-ups to your newsletter form.

**If your app already has a middleware file**, Next.js uses one file per app. Add the blog branch to the file you have. Return the rewrite when `pathname` is /blog or starts with /blog/, and add both blog paths to your matcher.

## Step 3: Set the token on Vercel

1. Open your project on Vercel and go to **Settings**, then **Environment Variables**.
2. Add `RANKWISE_BLOG_TOKEN` with the token from the last line of the snippet.
3. Apply it to the Production environment, and to Preview if you want the blog in preview deployments.

Keep the token out of your code and out of git. The snippet reads it from the environment for that reason.

## Step 4: Deploy and check

1. Commit `middleware.ts` and deploy. An environment variable reaches your app on the next deployment.
2. Open yourdomain.com/blog. You see your blog's index page.
3. Back in Rankwise, click **Check my blog**. When Rankwise finds the blog on your page, it shows as connected.

To check that search engines may index the blog, run:

```bash
curl -sI https://yourdomain.com/blog/
```

The answer must not contain `x-robots-tag: noindex`. Rankwise sends that header when the token or the host does not match, so the copy on our server never competes with yours.

## Next.js 16 and proxy.ts

Next.js 16 renamed the `middleware` file convention to `proxy`. The old name is deprecated. On Next.js 16 or later:

1. Name the file `proxy.ts` instead of `middleware.ts`.
2. Rename the function from `middleware` to `proxy`.

Everything else in the snippet stays the same. The Next.js docs also offer a codemod that makes both changes: `npx @next/codemod@canary middleware-to-proxy .`

## Troubleshooting

**/blog shows my app's 404 page.** The middleware file is in the wrong folder, or the matcher does not include /blog. The file must sit at the same level as `app` or `pages`.

**The page loads, but the header says noindex.** The token is empty or wrong. Check `RANKWISE_BLOG_TOKEN` on Vercel and redeploy. Also check that **Your website** in the Rankwise setup matches the domain your visitors use.

**My app has its own /blog pages.** Pick another path in Rankwise, such as /articles, and use the snippet Rankwise makes for that path.

**Check my blog fails.** Confirm that yourdomain.com/blog shows the blog, wait a minute, and try again.

Once the blog is live, every post you publish appears at yourdomain.com/blog with its sitemap entry, RSS item, llms.txt line and Markdown copy.
