---
updatedAt: 2025-09-11T20:04:04.000Z
agentTools:
  projectIndex: https://docs.makaira.io/llms.txt
---

# NextJs Update from 13 to 15

# Guide: Updating `storefront-starter-kit` from Next.js 13 to Next.js 15

This guide outlines the steps to upgrade `storefront-starter-kit` to Next.js 15, including updating dependencies, migrating routing logic, and aligning environment variable handling to match Next.js's built-in mechanisms.

***

## 1. Update Dependencies

Begin by upgrading your dependencies to ensure compatibility with Next.js 15:

```javascript
npm i next@^15 react@^18 react-dom@^18 eslint-config-next@^15
```

***

## 2. Aligning Environment Variables

### Previous Approach: `dotenv-webpack`

In older versions, your project might use `dotenv-webpack` to read `.env` files and make environment variables accessible in both server and client-side code. For example:

```javascript
webpack: (config) => {
  config.plugins = config.plugins || [];

  config.plugins = [
    ...config.plugins,
    // Read the .env file
    new Dotenv({
      path: path.join(__dirname, '.env'),
      systemvars: true,
    }),
  ];

  return config;
},
```

### Why Change?

1. **Conflicts in Next.js 15**:\
   The `dotenv-webpack` plugin conflicts with Next.js 15's middleware system, causing issues such as:
   * Middleware not functioning correctly.
   * Unexpected behavior during runtime.

2. **Native Next.js Support**:\
   Next.js now provides a robust way to handle environment variables without external plugins.

### New Approach: Use Next.js `.env` Conventions

1. Remove the `dotenv-webpack` plugin configuration from `next.config.js`.

2. Rename your `.env` variables to align with Next.js conventions:
   * **Public Variables**: Prefix with `NEXT_PUBLIC_` to make them accessible in client-side code.
   * **Private Variables**: Do not prefix with `NEXT_PUBLIC_` to restrict them to server-side code.

### Example `.env` Update:

Before:

```text .env
API_URL=https://api.example.com
SECRET_KEY=my-secret-key
```

After:

```env .env
NEXT_PUBLIC_API_URL=https://api.example.com
SECRET_KEY=my-secret-key
```

### Important Notes:

* **Restart the development server** after modifying `.env`.
* Public variables (`NEXT_PUBLIC_*`) will automatically be accessible on both the client and server.
* Private variables will remain server-side only.

***

## 3. Standard Routing: Replace `app.render` with `rewrites()`

In your `server/index.js`, you might find routing logic like this:

```javascript
server.get('/pali', (req, res) => {
  app.render(req, res, '/library/entry', req.query);
});
```

### Action: Use `rewrites()` Instead

1. Remove the route from `server/index.js`.
2. Add a rewrite rule in `next.config.js`:

```javascript
module.exports = {
  async rewrites() {
    return [
      {
        source: '/pali',
        destination: '/library/entry',
      },
    ];
  },
};
```

***

## 4. Wildcard Dynamic Routing

For dynamic routing where all paths redirect to a specific page, replace this logic in `server/index.js`:

```javascript
server.get(/^(.*)$/, (req, res) => {
  app.render(req, res, '/frontend/entry', {
    seoUrl: req.params[0],
    ...req.query,
  });
});
```

### **Step 1: Add Middleware**

Create a `middleware.js` file in the root of your project:

```javascript
import { NextRequest, NextResponse } from 'next/server';

export function middleware(req) {
  const pathname = req.nextUrl.pathname;

  // Match all paths using a wildcard pattern
  const pattern = /^(.*)$/;

  if (pattern.test(pathname)) {
    const url = req.nextUrl.clone();

    // Set `seoUrl` parameter based on the pathname
    const seoUrl = url.pathname;
    url.searchParams.set('seoUrl', seoUrl);

    // Preserve existing query parameters
    req.nextUrl.searchParams.forEach((value, key) => {
      url.searchParams.set(key, value);
    });

    // Rewrite the request to /frontend/entry
    return NextResponse.rewrite(url);
  }

  return NextResponse.next();
}
```

### **Step 2: Add a Wildcard Rewrite in`next.config.js`**

Update the `rewrites()` function to include a wildcard rule:

```javascript
module.exports = {
  async rewrites() {
    return [
      {
        source: '/pali', // Example standard route
        destination: '/library/entry',
      },
      {
        source: '/:path*', // Wildcard for all other paths
        destination: '/frontend/entry',
      },
    ];
  },
};
```

***

## 5. Remove Legacy Code

### Delete Routing in `server/index.js`

Remove any `app.render` logic, including both standard routes and wildcard handlers:

```javascript
server.get('/pali', (req, res) => {
  app.render(req, res, '/library/entry', req.query);
});

server.get(/^(.*)$/, (req, res) => {
  app.render(req, res, '/frontend/entry', {
    seoUrl: req.params[0],
    ...req.query,
  });
});
```

***

## 6. Test Your Application

1. **Restart the Development Server**\
   Start the app with:

   ```javascript
   npm run dev
   ```

2. **Verify Environment Variables**\
   Test public and private variables:
   * Log `process.env.NEXT_PUBLIC_API_URL` in client-side code.
   * Log `process.env.SECRET_KEY` in server-side code.

3. **Verify Routing**
   * Test `/pali` to ensure it rewrites to `/library/entry`.
   * Test wildcard routes like `/example` to confirm they rewrite to `/frontend/entry` with `seoUrl` and query parameters.

***

## Why Migrate?

### Environment Variables

* **Conflict Resolution**: Removing `dotenv-webpack` resolves conflicts that break Middleware in Next.js 15.
* **Native Support**: Next.js provides first-class support for `.env` handling without additional configuration.

### Routing

* **Deprecation of`app.render`** : Next.js 15 fully adopts the App Router, making custom server routing obsolete.
* **Performance**: Middleware operates at the edge, reducing latency for dynamic routes.

By following this guide, your `storefront-starter-kit` will be fully compatible with Next.js 15, adhering to its best practices for environment variables, routing, and middleware.