Response Headers not set on Vercel environment

Hello all,

I am encountering an issue where all response headers that I set in the Middleware work fine locally but are not included in the response after deployment to a Vercel environment.

Current Behavior

When running locally, I can see all headers added correctly. However, when deployed, some headers that are set using res.headers.set() in the middleware do not appear in the final response.

Here is the code from my middleware:

import { NextResponse } from 'next/server';
import { NextRequest } from 'next/server';
import crypto from 'crypto';
import { Session } from './session'; // Assuming Session is imported from another module

export function middleware(request: NextRequest) {
    const optimizelyCmsUrl = process.env.OPTIMIZELY_CMS_URL ?? '';

    // Add CSP
    const nonce = Buffer.from(crypto.randomUUID()).toString('base64');
    const cspHeader = `
        default-src 'self';
        script-src 'self' 'nonce-${nonce}' 'strict-dynamic' ${optimizelyCmsUrl} 'unsafe-eval';
        style-src 'self' 'unsafe-inline';
        img-src 'self' ${optimizelyCmsUrl} blob: data:;
        font-src 'self';
        object-src 'none';
        base-uri 'self';
        form-action 'self' ${optimizelyCmsUrl};
        frame-ancestors 'self' ${optimizelyCmsUrl} https://app-ocxcjomu1du97yp002.cms.optimizely.com;
        upgrade-insecure-requests;
    `;

    // Replace newline characters and spaces
    const contentSecurityPolicyHeaderValue = cspHeader.replace(/\s{2,}/g, ' ').trim();
    console.log("Generated CSP Header:", contentSecurityPolicyHeaderValue);

    // Create response with modified headers
    const requestHeaders = new Headers(request.headers);
    requestHeaders.set('x-nonce', nonce);

    let response = NextResponse.next({
        request: {
            headers: requestHeaders,
        },
    });

    // Clone the response to set headers correctly
    response = new NextResponse(response.body, response);

    // Add the CSP header to the response
    response.headers.set('Content-Security-Policy', contentSecurityPolicyHeaderValue);

    // Enable dev mode adjustments
    const isDev = process.env.NODE_ENV !== 'production' || request.nextUrl.host.includes('localhost');
    if (isDev) {
        response.headers.set('X-Dev-Mode', 'true');
    }

    // Make sure we're always in English - multi language is not supported yet
    if (!request.nextUrl.pathname.startsWith("/en")) {
        const newUrl = request.nextUrl.clone();
        newUrl.pathname = "/en" + newUrl.pathname;
        return NextResponse.redirect(newUrl, {
            status: isDev ? 307 : 308
        });
    }

    // Assign a Visitor ID cookie, so we can identify and track individual visitors
    const visitorId = Session.getOrCreateVisitorId(request);
    Session.addVisitorId(response, visitorId);

    return response;
}

Expected Behavior

I expect Vercel Edge to behave the same way as my local dev environment and apply all headers that are set in the middleware. Specifically, I would like the Content-Security-Policy and other headers set in the response to be included when deployed to production.

Environment Info

Steps to Reproduce

  1. Add the above middleware to a Next.js application.
  2. Deploy the application to Vercel.
  3. Observe that headers set locally in dev mode are not present in the deployed version.

Any help or insight would be greatly appreciated. Has anyone encountered this behavior before or found a way to get the headers applied consistently in both environments?

Thanks in advance!

Hi, @johnny-ftt!

It’s been a while since you posted this. Appreciate your patience :pray:

I was wondering if you managed to figure out what the issue was with your response headers?

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.