Skip to content
Docs

Testing & troubleshooting microfrontends

The @vercel/microfrontends package includes test utilities to help avoid common misconfigurations.

The validateMiddlewareConfig test ensures Middleware is configured to work correctly with microfrontends. Passing this test does not guarantee Middleware is set up correctly, but it should find many common problems.

Since Middleware only runs in the default application, you should only run this test on the default application. If it finds a configuration issue, it will throw an exception so that you can use it with any test framework.

tests/middleware.test.ts
/* @jest-environment node */
 
import { validateMiddlewareConfig } from '@vercel/microfrontends/next/testing';
import { config } from '../middleware';
 
describe('middleware', () => {
  test('matches microfrontends paths', () => {
    expect(() =>
      validateMiddlewareConfig(config, './microfrontends.json'),
    ).not.toThrow();
  });
});

The validateMiddlewareOnFlaggedPaths test checks that Middleware is correctly configured for flagged paths by ensuring that Middleware rewrites to the correct path for these flagged paths. Since Middleware only runs in the default application, you should only run this testing utility in the default application.

tests/middleware.test.ts
/* @jest-environment node */
 
import { validateMiddlewareOnFlaggedPaths } from '@vercel/microfrontends/next/testing';
import { middleware } from '../middleware';
 
// For this test to work, all flags must be enabled before calling
// validateMiddlewareOnFlaggedPaths. There are many ways to do this depending
// on your flag framework, test framework, etc. but this is one way to do it
// with https://flags-sdk.dev/
jest.mock('flags/next', () => ({
  flag: jest.fn().mockReturnValue(jest.fn().mockResolvedValue(true)),
}));
 
describe('middleware', () => {
  test('rewrites for flagged paths', async () => {
    await expect(
      validateMiddlewareOnFlaggedPaths('./microfrontends.json', middleware),
    ).resolves.not.toThrow();
  });
});

The validateRouting test validates that the given paths route to the correct microfrontend. You should only add this test to the default application where the microfrontends.json file is defined.

tests/microfrontends.test.ts
import { validateRouting } from '@vercel/microfrontends/next/testing';
 
describe('microfrontends', () => {
  test('routing', () => {
    expect(() => {
      validateRouting('./microfrontends.json', {
        marketing: ['/', '/products'],
        docs: ['/docs', '/docs/api'],
        dashboard: [
          '/dashboard',
          { path: '/new-dashboard', flag: 'enable-feature-x' },
        ],
      });
    }).not.toThrow();
  });
});

The above test confirms that microfrontends routing:

  • Routes / and /products to the marketing microfrontend.
  • Routes /docs and /docs/api to the docs microfrontend.
  • Routes /dashboard and /new-dashboard (with the enable-feature-x flag enabled) to the dashboard microfrontend.

See debug routing for how to enable debug logs to see where and why the local proxy routed the request.

Debug headers expose the internal reason for the microfrontend response. You can use these headers to debug issues with routing.

You can enable debug headers in the Vercel Toolbar, or by setting a cookie VERCEL_MFE_DEBUG to 1 in your browser.

Requests to your domain will then return additional headers on every response:

  • x-vercel-mfe-app: The name of the microfrontend project that handled the request.
  • x-vercel-mfe-target-deployment-id: The ID of the deployment that handled the request.
  • x-vercel-mfe-default-app-deployment-id: The ID of the default application deployment, the source of the microfrontends.json configuration.
  • x-vercel-mfe-zone-from-middleware: For flagged paths, the name of the microfrontend that middleware decided should handle the request.
  • x-vercel-mfe-matched-path: The path from microfrontends.json that was matched by the routing configuration.
  • x-vercel-mfe-response-reason: The internal reason for the MFE response.

Microfrontends routing information is stored in Observability and can be viewed in the team or project scopes. Click on the Observability tab, and then find Microfrontends in the CDN section.

Microfrontends routing is captured by Vercel Session tracing. Once you have captured a trace, you can inspect the Microfrontends span in the logs section in the sidebar.

You may need to zoom in to the Microfrontends span. The span includes:

  • vercel.mfe.app: The name of the microfrontend project that handled the request.
  • vercel.mfe.target_deployment_id: The ID of the deployment that handled the request.
  • vercel.mfe.default_app_deployment_id: The ID of the default application deployment, the source of the microfrontends.json configuration.
  • vercel.mfe.app_from_middleware: For flagged paths, the name of the microfrontend that middleware decided should handle the request.
  • vercel.mfe.matched_path: The path from microfrontends.json that was matched by the routing configuration.

The following are common issues you might face with debugging tips:

A build that ends with Could not find a microfrontends.json file in the repository that contains the "<application>" application means the application couldn't locate a microfrontends.json that lists it when it builds. Every application in the group reads microfrontends.json at build time through withMicrofrontends.

In a monorepo, each application searches the repository for the configuration automatically and matches applications by name. The build fails when:

  • The application isn't listed under applications in microfrontends.json.
  • The application's name in microfrontends.json doesn't match its Vercel project name. If the package.json name differs from the Vercel project name, add a packageName field to the application in microfrontends.json. See Configuration.

In a polyrepo, the configuration lives in only one repository, so the other applications can't find it unless you give them access:

  • Pull the configuration into the application with vercel microfrontends pull, which writes it to the application's .vercel directory. See Accessing the configuration file.
  • Or set the VC_MICROFRONTENDS_CONFIG environment variable to the path of the configuration file.
  • If the configuration uses a custom file name, set VC_MICROFRONTENDS_CONFIG_FILE_NAME. See File naming.

Add any environment variables to every project in the microfrontends group so they apply during each build.

See debug routing for how to enable debug logs to see where and why the local proxy routed the request.

To validate where requests are being routed to in production, follow these steps:

  1. Verify that the path is covered by the microfrontends routing configuration.
  2. Inspect the debug headers or view a page trace to verify the expected path was matched.

Pages Router pages that use getStaticProps or getServerSideProps rely on /_next/data/...json requests during client-side navigation. If Pages Router support or the required proxy and routing behavior is missing, the page can work on direct load but fail when you navigate to it from another microfrontend. This can happen when navigating from an App Router page to a Pages Router page.

Check for these symptoms:

  • /_next/data requests return a 404 response.
  • /_next/data requests route to the wrong microfrontend.
  • The page loads stale or incorrect data after navigation.

For any Next.js microfrontend that uses the Pages Router, enable supportPagesRouter in withMicrofrontends().

See Set up microfrontends with your framework.

Use this checklist before promoting a microfrontends change that includes any Next.js Pages Router routes:

  • Test a direct page load.
  • Test client-side navigation from another microfrontend into the Pages Router page.
  • Test navigation from App Router pages to Pages Router pages.
  • Test Pages Router pages that use getStaticProps.
  • Test Pages Router pages that use getServerSideProps.
  • Inspect network requests for /_next/data.
  • Test through the local microfrontends proxy.
  • Test on a Preview deployment.

Was this helpful?

supported.