Install
$ agentstack add skill-mvstepanek-nextjs-ecommerce-seo-skills-seo-redirects ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Redirect & 404 Handling SEO Guidelines
Follow these rules when implementing redirects or handling missing pages.
Redirect Types
| Code | Name | When to use | |------|------|------------| | 301 | Permanent | URL has permanently changed — product renamed, section restructured | | 308 | Permanent (preserves method) | Same as 301 but preserves POST/PUT — use for API redirects | | 302 | Temporary (default in Next.js) | Temporary redirect — locale detection, A/B tests, maintenance | | 307 | Temporary (preserves method) | Same as 302 but preserves POST/PUT |
Default rule: Use 301 for permanent URL changes (most common SEO case). Use 302 for locale detection redirects. Never use 302 when you mean 301 — it delays canonicalization and signals the wrong intent to search engines.
Next.js Redirects in next.config.js
For simple, static redirect patterns:
// next.config.js
module.exports = {
async redirects() {
return [
// Old product URL pattern to new
{
source: '/:locale/old-products/:id',
destination: '/:locale/products/:id',
permanent: true, // 301
},
// Removed page to replacement
{
source: '/:locale/about-us',
destination: '/:locale/contact-us',
permanent: true,
},
// Regex pattern for old category structure
{
source: '/:locale/shop/:category',
destination: '/:locale/categories/:category',
permanent: true,
},
];
},
};
Use next.config.js redirects when: The pattern is simple, applies to all requests, and doesn't need request-time logic.
Middleware Redirects
For complex, dynamic redirect logic:
// middleware.ts
import { NextRequest, NextResponse } from 'next/server';
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// Locale detection — TEMPORARY redirect (302)
if (pathname === '/') {
const locale = detectLocale(request) || DEFAULT_LOCALE;
return NextResponse.redirect(new URL(`/${locale}/`, request.url), 302);
}
// Old product URL migration — PERMANENT redirect (301)
const oldProductMatch = pathname.match(/^\/(\w{2}-\w{2})\/old-products\/(\d+)/);
if (oldProductMatch) {
const [, locale, id] = oldProductMatch;
return NextResponse.redirect(
new URL(`/${locale}/products/${id}`, request.url),
301
);
}
}
Use middleware redirects when: You need request-time logic (headers, cookies, geo-detection) or complex matching.
Redirect Chains
Never create redirect chains — where URL A redirects to B, which redirects to C.
BAD: /old-page → /moved-page → /final-page (chain)
GOOD: /old-page → /final-page (direct)
/moved-page → /final-page (direct)
Redirect chains:
- Slow down page load (each redirect adds a network round trip)
- Waste crawl budget — Googlebot may stop following after several hops
- Confuse search engine crawlers and delay canonicalization
When migrating URLs, always redirect to the final destination, even if there were intermediate moves.
Canonical vs Redirect
| Scenario | Solution | |----------|----------| | Two URLs serve the same content, both should remain accessible | Use canonical on both pointing to the preferred URL | | An old URL should no longer be used | 301 redirect to the new URL | | Trailing slash vs non-trailing slash | Pick one, redirect the other | | HTTP to HTTPS | 301 redirect HTTP to HTTPS | | www to non-www (or vice versa) | 301 redirect to the canonical domain | | Filter params creating duplicate content | Set canonical to the base category URL |
404 Handling
- Custom 404 page with useful navigation — help users find what they were looking for
- Never redirect 404s to the homepage — it sends a false "200 OK" signal and confuses search engines
- Return actual 404 status code — Google needs to see 404 to remove old URLs from the index
- Include in the 404 page: search box, top categories, popular products, contact link
// Not found page (app/[locale]/not-found.tsx or pages/404.tsx)
export default function NotFound() {
return (
Page Not Found
The page you're looking for doesn't exist or has been moved.
Popular Categories
Electronics
Accessories
Contact Us
);
}
Locale Redirects
- Root
/→ detected locale — use 302 (temporary), not 301 - Locale mismatch — if a user manually navigates to a wrong locale, do NOT auto-redirect; let them stay (they may be comparing prices or using a different language on purpose)
- Non-existent locale —
/xx-YY/products/123should 404, not redirect to a default locale
// middleware.ts — locale redirect rules
export function middleware(request: NextRequest) {
const pathname = request.nextUrl.pathname;
// Only redirect the bare root
if (pathname === '/') {
const locale = detectLocaleFromHeaders(request) || DEFAULT_LOCALE;
return NextResponse.redirect(new URL(`/${locale}/`, request.url), 302);
}
// Validate locale prefix
const localeMatch = pathname.match(/^\/([a-z]{2}-[A-Z]{2})\//);
if (localeMatch && !ALL_LOCALES.includes(localeMatch[1])) {
// Invalid locale — return 404, don't redirect
return NextResponse.rewrite(new URL('/not-found', request.url));
}
}
HTTPS and Domain Redirects
- All HTTP requests must 301 redirect to HTTPS (typically handled at CDN/infrastructure level)
- Ensure consistent domain — no duplicate content between
wwwand non-wwwvariants
Common Mistakes to Avoid
- 302 for permanent moves — always use 301 for permanent URL changes
- Redirect chains — always redirect directly to the final URL
- Redirecting 404s to homepage — return proper 404 status with helpful content
- 301 for locale detection — use 302 (user preference may change)
- Missing redirects after URL change — if you rename a slug or move a section, add redirects for old URLs
- Redirect loops — page A redirects to B, B redirects to A (crashes the browser)
- Redirecting with query params — don't strip important query params during redirects without intent
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: mvstepanek
- Source: mvstepanek/nextjs-ecommerce-seo-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.