# How to Dynamically Change the Browser URL When Using Next.js Rewrites

> Learn how to dynamically change browser URLs with Next.js rewrites. Explore solutions using redirects, client-side routing or middleware to update the address bar for seamless navigation.

- Repository: [Vercel/next.js](https://github.com/vercel/next.js)
- Tags: how-to-guide
- Published: 2026-02-16

---

**Next.js rewrites are server-side mappings that intentionally keep the original URL in the browser address bar, so you must use redirects, client-side router methods, or middleware to display the rewritten path.**

Next.js rewrites allow you to map incoming request URLs to different internal destinations without exposing the underlying path structure. However, when implementing nextjs rewrites, developers often need the browser to display the destination URL rather than the original request path. Understanding how the framework processes these mappings in [`packages/next/src/shared/lib/router/utils/resolve-rewrites.ts`](https://github.com/vercel/next.js/blob/main/packages/next/src/shared/lib/router/utils/resolve-rewrites.ts) is essential for choosing the right approach.

## Why Next.js Rewrites Preserve the Original URL

Rewrites in Next.js operate entirely on the server side before the request reaches the page rendering logic. When a request matches a rewrite rule defined in [`next.config.js`](https://github.com/vercel/next.js/blob/main/next.config.js), the framework internally resolves the destination using the logic found in [`packages/next/src/shared/lib/router/utils/resolve-rewrites.ts`](https://github.com/vercel/next.js/blob/main/packages/next/src/shared/lib/router/utils/resolve-rewrites.ts). Because the client receives the response without an HTTP redirect status code, the browser address bar remains on the original request URL.

This design makes rewrites ideal for proxying API routes, serving content from different folders, or masking external services while maintaining a clean URL structure. However, the transparency of rewrites means they cannot alone update the browser's displayed URL.

## Three Methods to Display the Rewritten Path in the Address Bar

To surface the rewritten path in the browser address bar, you must move beyond basic rewrites and employ one of three strategies: permanent redirects, client-side navigation, or middleware-based conditional logic.

### Use Redirects for Permanent URL Changes

When you want the browser to permanently display the new URL and maintain SEO value, use the `redirects` configuration in [`next.config.js`](https://github.com/vercel/next.js/blob/main/next.config.js). Unlike rewrites, redirects return HTTP 301 or 302 status codes that instruct the browser to navigate to the target URL.

```javascript
// next.config.js
module.exports = {
  async redirects() {
    return [
      {
        source: '/old-blog/:slug',
        destination: '/blog/:slug',
        permanent: true, // 308 permanent redirect → address bar shows "/blog/:slug"
      },
    ]
  },
}

```

### Use Client-Side Navigation After Server Rewrites

For scenarios where you want to preserve the rewrite for initial server-side rendering but update the URL once the page loads, combine a rewrite with `router.replace` or `router.push`. This approach is useful when the rewritten path represents the canonical URL that should appear in the address bar after hydration.

```jsx
// pages/blog/[slug].js
import { useRouter } from 'next/router'
import { useEffect } from 'react'

export default function BlogPost({ data }) {
  const router = useRouter()

  useEffect(() => {
    // Replace the URL after the page has been rendered via a rewrite
    router.replace(`/blog/${data.slug}`, undefined, { shallow: true })
  }, [data.slug])

  return <article>{/* render post */}</article>
}

```

```javascript
// next.config.js – keep the rewrite for internal handling
module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog/:slug',
        destination: '/posts/:slug', // internal data fetch
      },
    ]
  },
}

```

### Use Middleware for Conditional Rewrite and Redirect Logic

For complex routing scenarios where some requests should remain internal while others require URL updates, implement conditional logic in Next.js Middleware. Middleware can examine the request, perform a rewrite for internal handling, and then issue a redirect if the URL should be reflected in the browser.

```typescript
// middleware.ts
import { NextResponse } from 'next/server'

export function middleware(request) {
  const { pathname } = request.nextUrl

  // Example: rewrite /preview/* to /api/preview/*, then show the preview path
  if (pathname.startsWith('/preview/')) {
    const url = request.nextUrl.clone()
    url.pathname = `/api${pathname}`
    const response = NextResponse.rewrite(url)

    // After rewiring, issue a redirect so the browser shows the preview URL
    const redirect = NextResponse.redirect(request.nextUrl)
    redirect.headers.set('Location', pathname) // keep the original preview path
    return redirect
  }

  return NextResponse.next()
}

```

## How Next.js Processes Rewrites Internally

Understanding the internal implementation helps clarify why rewrites cannot alone update the browser URL. The core logic resides in [`packages/next/src/shared/lib/router/utils/resolve-rewrites.ts`](https://github.com/vercel/next.js/blob/main/packages/next/src/shared/lib/router/utils/resolve-rewrites.ts), which parses the rewrite configuration and matches incoming requests against defined patterns.

For the App Router, additional logic in [`packages/next/src/lib/generate-interception-routes-rewrites.ts`](https://github.com/vercel/next.js/blob/main/packages/next/src/lib/generate-interception-routes-rewrites.ts) generates internal rewrite rules for route interception scenarios. The test suite in [`packages/next-routing/src/__tests__/rewrites.test.ts`](https://github.com/vercel/next.js/blob/main/packages/next-routing/src/__tests__/rewrites.test.ts) validates these behaviors, confirming that rewrites operate as transparent server-side mappings without client-side visibility.

Because the rewrite resolution occurs before the Next.js router initializes on the client, the browser has no indication that the content originated from a different path, keeping the original URL intact in the address bar.

## Summary

- **Next.js rewrites** are server-side only and intentionally preserve the original URL in the browser address bar to enable transparent path mapping.
- To display the rewritten path, use **redirects** in [`next.config.js`](https://github.com/vercel/next.js/blob/main/next.config.js) for permanent URL changes that update the address bar via HTTP status codes.
- For dynamic updates after page load, combine rewrites with **client-side navigation** using `router.replace()` or `router.push()` with shallow routing.
- For complex conditional logic, implement **Next.js Middleware** to selectively rewrite internal requests while issuing redirects to update the browser URL when necessary.
- The internal rewrite logic is handled in [`packages/next/src/shared/lib/router/utils/resolve-rewrites.ts`](https://github.com/vercel/next.js/blob/main/packages/next/src/shared/lib/router/utils/resolve-rewrites.ts), confirming that rewrites operate before client-side hydration occurs.

## Frequently Asked Questions

### Do Next.js rewrites change the URL in the browser?

No, Next.js rewrites do not change the URL displayed in the browser address bar. They are designed as transparent server-side mappings that resolve internally in [`packages/next/src/shared/lib/router/utils/resolve-rewrites.ts`](https://github.com/vercel/next.js/blob/main/packages/next/src/shared/lib/router/utils/resolve-rewrites.ts) before the page renders, keeping the original request URL visible to users.

### What is the difference between rewrites and redirects in Next.js?

Rewrites map an incoming URL to a different internal destination without notifying the browser, while redirects return HTTP 301 or 302 status codes that instruct the browser to navigate to a new URL, thereby updating the address bar. Use rewrites for internal path aliasing and redirects when you want users and search engines to recognize the new canonical URL.

### Can I use middleware to rewrite a URL and then change the browser address bar?

Yes, Next.js Middleware can combine both operations by first calling `NextResponse.rewrite()` to handle the request internally, then conditionally returning `NextResponse.redirect()` to update the browser URL. This approach is useful when you need to rewrite certain requests transparently while exposing the rewritten path for specific routes or user segments.

### How do I dynamically rewrite URLs based on request parameters?

You can define dynamic rewrites in [`next.config.js`](https://github.com/vercel/next.js/blob/main/next.config.js) by using path segments like `:slug` or `:path*` in the source pattern, or by providing a function to the destination property that receives the matched parameters. For more complex logic based on headers, cookies, or query strings, implement custom rewrite logic in Next.js Middleware where you have full access to the request object.