Permalinks, mapped
WordPress to Next.js URL Structure: Keep the Addresses Google Already Trusts
A WordPress site has far more addresses than it has pages. Date folders, category archives, /page/2/, feeds, attachment pages and the ?p=123 links WordPress quietly answers to all count. Here is where each one lands in a Next.js build, and which ones deserve to survive the move to Next.js.
October 8, 2026 · 10 min read
The short answer
Keep your WordPress post and page URLs exactly as they are unless they are genuinely broken. Rebuild the permalink pattern as Next.js dynamic routes, match the old trailing slash, recreate the category and paginated archives that earn traffic, and send ?p= links, extra feeds, attachment pages and retired archives to their closest live page with permanent redirects.
On this page
- Count the addresses before you count the pages
- Six permalink settings and the route folder each one becomes
- Keep, change or retire: one decision per URL family
- Trailing slashes: one character on every address
- Archives, page two and the feeds that still have readers
- The canonical decisions WordPress was making behind your back
- A URL inventory in six moves
- Who guards the URL rules after launch
Count the addresses before you count the pages
Ask an owner how big their site is and they will say forty pages and a blog. Ask a crawler and it will find several hundred URLs. WordPress is generous with addresses. Every post can be reached by its permalink, by its numeric ID, through each category and tag it belongs to, through a date archive, an author archive and at least one feed. None of this is a problem while WordPress is answering. It becomes a problem the day something else has to.
Here are the URL families a typical WordPress site exposes, whether or not anyone meant it to:
- Posts and pages at whatever the Settings, Permalinks screen says, for example /sample-post/ or /2024/03/sample-post/.
- ID links such as /?p=123 for posts and /?page_id=45 for pages. With pretty permalinks on, WordPress redirects these to the real address, so old emails and forum posts still work.
- Taxonomy archives at /category/news/ and /tag/pricing/, or under a custom base set in the Optional section of the Permalinks screen.
- Date and author archives such as /2024/03/ and /author/jane/, which exist even on sites that never link to them.
- Pagination at /page/2/ on the blog and every archive, plus /comment-page-2/ on posts with paged comments.
- Feeds at /feed/, /comments/feed/ and a /feed/ on the end of nearly every archive.
- Attachment pages, one per uploaded file, which still work on sites created before WordPress 6.4.
The inventory is the first deliverable of any WordPress to Next.js development project we run, because every later decision depends on it.
Six permalink settings and the route folder each one becomes
Next.js routes are folders. A folder named in square brackets is a dynamic segment, so app/[slug]/page.tsx answers to any single-segment URL. That makes most WordPress permalink settings easy to reproduce exactly, which is the cheapest way to keep rankings. The table shows each setting from the WordPress Permalinks screen and the route that matches it.
| WordPress example | Next.js route | Watch out for | |
|---|---|---|---|
| Plain | /?p=123 | No route; redirect each ID to a slug | Query strings are not route segments |
| Day and name | /2008/03/31/sample-post/ | app/[year]/[month]/[day]/[slug] | Date must match the original publish date |
| Month and name | /2008/03/sample-post/ | app/[year]/[month]/[slug] | Edited dates in an export can drift |
| Numeric | /archives/123 | app/archives/[id] | IDs must survive the content import |
| Post name | /sample-post/ | app/[slug] | Posts and pages share one namespace |
| Custom with %category% | /news/local/sample-post/ | app/[...path] | Child categories add path segments |
Two rows deserve a closer look. With Post name permalinks, posts and pages live side by side at the root, so the single [slug] route has to look up both and decide which template to render. With %category% in the structure, WordPress writes the full category path, parent and child, into the URL. A post filed under News and then Local lives at /news/local/sample-post/. A catch-all route handles that, but it must use the category that WordPress actually put in the address, which is not always the one the editor thinks of as primary.
Keep, change or retire: one decision per URL family
The default answer is keep. A URL that already ranks has history, links and trust attached to it, and an identical URL in the new build inherits all of it with no redirect at all. Change is a choice you make for a reason, and retirement is for addresses that never earned anything.
Keep the URL as it is
- Posts, pages, products and service pages, character for character
- Category archives that receive search traffic or internal links
- The main feed at /feed/, which readers and email tools still poll
- Paginated blog archives, rebuilt at the same /page/2/ addresses
- Date-based post URLs, unless you are restructuring the whole blog anyway
Redirect or retire it
- ?p= and ?page_id= links, each sent to its post's real address
- Attachment pages, sent to the parent post or the image itself
- Date archives and author archives on single-author sites
- Tag pages holding one or two posts, merged into a category
- Comment feeds and per-archive feeds nobody subscribes to
Changing a date-based structure to clean slugs is the most common temptation. It is legitimate, and a permanent redirect tells Google which address is now canonical. It also means a redirect for every post and a period where Google recrawls the lot. If you want it, do it during the migration rather than six months after, so the site goes through one reshuffle, not two. The SEO-safe migration guide covers what to watch in Search Console while it settles.
Trailing slashes: one character on every address
WordPress pretty permalinks usually end with a slash, because the structure tag is written /%postname%/. Next.js does the opposite by default. Its documentation says it redirects /about/ to /about unless you set trailingSlash: true in next.config, which flips the rule. That one setting decides whether every URL on the site stays put or picks up a redirect.
Match the old site. If WordPress served /services/roof-repair/, set trailingSlash: true and the new build serves the same string. The canonical tag, the XML sitemap, the internal links and the redirect map then all have to agree on that form. A site that links to /pricing in the menu, lists /pricing/ in the sitemap and declares a third version as canonical is sending Google three opinions about one page, and one of them through a redirect. If an old site was inconsistent, pick one form, make it the rule in code and let the framework redirect the other.
The third option
Athena CMS, with AI agents on staff.
Not a theme and not a blank Next.js repo. The content system we put behind every custom site: plain fields, a real preview, every version kept, and AI agents that handle the chores a plugin only nags you about.
- PicassoImages
- ApolloSite analysis
- AresCompetitor watch
- PrometheusContent holes
- AtlasPage depth and structure
- DelphiAI search visibility
and 12 more agents. Two come with Athena; the rest are monthly add-ons.

Archives, page two and the feeds that still have readers
Category archives are real pages to Google, and on content sites they often rank for broad terms the individual posts cannot. Rebuild the ones that earn traffic at the same address, with the same base. If the old site renamed its category base to /topics/ in the Optional settings, the new routes use /topics/ too. Give each archive an introduction worth reading, because a list of excerpts is a thin page in any framework.
Pagination is simpler than it looks. A route such as app/category/[slug]/page/[n] can be generated at build time, so /category/news/page/3/ exists as a static file. Each page in the series should carry its own canonical tag rather than pointing back to page one, so the posts linked from deeper pages stay discoverable. The blog migration guide goes further into archives, authors and comments.
Feeds are the family people forget. Feed readers, podcast apps, email newsletter tools that send new posts automatically, and partner sites can all be polling /feed/ for years. In Next.js a route handler can return the RSS XML at exactly that path. Category feeds can be rebuilt or redirected to the main feed. The comments feed can usually go.
The canonical decisions WordPress was making behind your back
WordPress runs a function called redirect_canonical on most requests. It sends ?p= links to pretty permalinks, adds or removes trailing slashes to match your setting, and, when a URL would otherwise 404, it tries to guess what you meant by matching the slug against existing posts. A link to /roof-repai/ might quietly land on /roof-repair/. Your site has been rescuing broken inbound links for years and nobody told you.
A Next.js build does none of that unless someone writes it. That is mostly a good thing, since guessing is how sites end up with strange duplicates, but it means the rescues have to become explicit. Before launch, pull the inbound links and the old server logs, find the requests WordPress was correcting, and add the ones with value to the redirect map. After launch, Argus in Athena watches for broken links so the stragglers show up as a list, not as a slow slide in traffic.
Canonical tags themselves move into code. Next.js lets each page declare its canonical URL in its metadata, generated from the same route data that builds the page, so it cannot drift away from the real address the way a plugin setting can. If your old SEO plugin had per-post canonical overrides, export them: those were deliberate choices and they belong in the map too. The WordPress vs Next.js SEO comparison explains why metadata in code holds up better over time.
A URL inventory in six moves
- 1
Pull every known URL
Combine the XML sitemaps from the SEO plugin, a full crawl of the live site, the Pages report in Search Console and the top linked pages from a backlink tool.
- 2
Add the hidden families
List ?p= IDs, attachment pages, date and author archives, feeds and paginated archives, which sitemaps usually leave out.
- 3
Tag each URL with a decision
Keep, redirect to a named destination, or retire. Note traffic and links beside each one so the decisions are defensible.
- 4
Write the routes to match
Build Next.js route folders that reproduce the kept patterns exactly, including the trailing slash setting and any custom category base.
- 5
Generate canonicals and sitemaps from the same data
One source of truth for every address means the sitemap, canonical tags and internal links cannot disagree.
- 6
Replay the list against staging
Request every old URL on the preview build and confirm each returns 200 or a single permanent redirect to the right page.
Theme choice changes the inventory more than people expect. A Divi site often carries project and portfolio post types with their own bases, a Newspaper site tends to have deep category trees and heavy pagination, and a WoodMart store adds product, category and filter URLs that the WooCommerce guide maps separately.
Who guards the URL rules after launch
On WordPress, anyone with admin access can open Settings, Permalinks, pick a new structure and change every post address on the site in one click. It happens more often than you would think, usually during a well-meant tidy-up. In a Next.js build the route structure lives in code, reviewed and tested before deploy, so a change of that size is a decision rather than an accident.
Your team still controls what matters day to day. In Athena CMS a page or post slug is a plain field with a real preview, and every version is kept. Atlas flags orphan and thin pages, so archives that stop earning their place get noticed. If you would rather keep editing in WordPress and only replace the front end, the same URL rules apply, as described in keeping WordPress as the CMS behind Next.js. Either way, we keep your URLs and redirect every old one.
Questions people ask before they call
No, but you should unless there is a real reason to change it. Next.js can reproduce almost any permalink pattern with dynamic route folders, so keeping the structure costs little and needs no redirects for your main pages. Change it only when the old structure is actively hurting you, and then redirect every old address permanently. Our migration service starts with that decision.
Only if you were going to restructure the blog anyway. Removing dates means a permanent redirect for every post and a period of recrawling while Google settles on the new addresses. If the date URLs already rank, keeping them is the lower-risk path. If you do change them, do it during the migration so the site goes through one reshuffle instead of two.
WordPress used to redirect them to the pretty permalink. Next.js will not know what they mean unless you tell it. Export the post IDs with their slugs and add redirects that match the p query value and send each one to its post. Query matching is supported in next.config redirects, and a large list can live in a lookup handled by Proxy.
Not by default. Next.js redirects /about/ to /about unless trailingSlash: true is set in next.config, which makes it add the slash instead. Most WordPress sites used trailing slashes, so we usually turn that option on and every address stays identical. The sitemap, canonical tags and internal links then follow the same rule.
Retire them. WordPress itself turned attachment pages off for new sites in version 6.4, redirecting them to the file, because they rarely add anything a search engine values. In a migration we redirect each one to the post it was attached to, or to the image file if it has no parent. The Next.js migration hub lists the related guides.
Keep reading
- The redirect mapWordPress to Next.js Redirects: Build the Map, Choose the Status Code, Test Every LineBuild a redirect map for a WordPress to Next.js move: 301 vs 308, next.config vs Proxy for big maps, chains, old plugin redirects and how to test them.
- SEO-safe migrationMigrate WordPress to Next.js Without Losing SEO: The Checklist That Protects Your RankingsMove from WordPress to Next.js and keep your rankings: the URL inventory, permanent redirects, metadata, schema, internal links, sitemaps and launch checks.
- The blog moveMove a WordPress Blog to Next.js: Posts, Archives, Comments and Feeds, IntactMove a WordPress blog to Next.js with posts, categories, tags, authors, comments, shortcodes, featured images, RSS feeds and pagination carried over intact.
- Astra migration guideAstra to Next.js: Migrate an Astra Site Layer by Layer, Rankings IntactMigrate Astra to Next.js without losing rankings: what happens to astra-settings, Site Builder layouts, Spectra blocks and Elementor pages, step by step.
- Kadence migration guideKadence to Next.js: Moving Kadence Blocks, Shop Kit and MembersKadence to Next.js, step by step: parse Kadence Blocks, map the global palette, rebuild Hooked Elements, move Shop Kit stores and members, keep every URL.
- GeneratePress migration guideGeneratePress to Next.js: Leaving the Cleanest Theme in WordPressGeneratePress to Next.js: why GP sites cost less to move, how Elements, hooks and GenerateBlocks CSS migrate, and the URL plan that keeps your rankings.
- Everything in WordPress to Next.jsSee the section
Get a URL inventory of your WordPress site
Send us your address. We will crawl the live site, list every URL family it exposes and tell you which ones to keep, redirect or retire before any code is written.
Which of these sounds like you? (pick any)
Rather talk now? Call (210) 346-0848.
