1

I'm working on a multi-tenant Next.js application where I'm experiencing an issue with metadata generation. When a valid subdomain exists and the tenant is found, everything works perfectly - the app renders and metadata is applied correctly. However, when the tenant validation fails and conditional rendering is triggered, the metadata for the invalid tenant doesn't load unless I make a code change that triggers Next.js hot reload - only then does the metadata appear. (Please be nice, I'm new in Nextjs lmao)

layout.tsx:

import type { Metadata } from "next";

import "./globals.css";
import { getTenantData } from "@/lib/utils";
import MissingSubdomainError from "@/components/errors/MissingSubdomainError";
import InvalidTenantError from "@/components/errors/InvalidTenantError";
import { TenantProvider } from "@/components/providers/tenant-provider";

export async function generateMetadata(): Promise<Metadata> {
  const { subdomain, tenant } = await getTenantData();

  if (!subdomain) {
    return {
      title: "Subdominio no definido",
      description: "No se proporcionó un subdominio válido",
    };
  }

  if (!tenant) {
    return {
      title: "Tenant inválido",
      description: `No se encontró ningún tenant llamado "${subdomain}"`,
    };
  }

  return {
    title: tenant.name,
    description: `Sitio de ${tenant.name}`,
  };
}

export default async function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const { subdomain, tenant } = await getTenantData();

  if (!subdomain) return <MissingSubdomainError />;
  if (!tenant) return <InvalidTenantError subdomain={subdomain} />;

  return (
    <html lang="es">
      <body>
        <TenantProvider subdomain={subdomain} tenantData={tenant}>
          {children}
        </TenantProvider>
      </body>
    </html>
  );
}

InvalidTenantError.tsx:

export default function InvalidTenantError({
  subdomain,
}: {
  subdomain: string;
}) {
  return (
    <html lang="es">
      <body className="flex items-center justify-center min-h-screen bg-gray-100">
        <div className="bg-white p-8 rounded-xl shadow-lg text-center max-w-md">
          <h1 className="text-3xl font-bold text-red-600 mb-4">
            Subdominio inválido
          </h1>
          <p className="text-gray-700 mb-2">
            El subdominio{" "}
            <span className="font-semibold text-gray-900">{subdomain}</span> no
            está registrado.
          </p>
          <p className="text-gray-600 mb-4">
            Verifica que lo hayas escrito correctamente. Por ejemplo:
          </p>
          <code className="bg-gray-100 px-2 py-1 rounded text-sm text-gray-800">
            empresa.localhost
          </code>
          <p className="text-sm text-gray-500 mt-4">
            Si crees que esto es un error o necesitas ayuda, contáctanos.
          </p>
        </div>
      </body>
    </html>
  );
}

utils.ts:

import { headers } from "next/headers";
import { prisma } from "./prisma";

export async function validateTenant(subdomain: string) {
  try {
    const tenant = await prisma.tenant.findUnique({
      where: {
        subdomain: subdomain,
        active: true,
      },
    });

    return tenant;
  } catch (error) {
    console.error("Error validating tenant:", error);
    return null;
  }
}

export async function getTenantData() {
  const headersList = await headers();
  const subdomain = headersList.get("x-tenant");

  if (!subdomain) {
    return { subdomain: null, tenant: null };
  }

  const tenant = await validateTenant(subdomain);
  return { subdomain, tenant };
}

package.json:

{
  "name": "tenanttest",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev --turbopack",
    "build": "prisma generate && next build",
    "start": "next start",
    "lint": "next lint",
    "db:seed": "tsx prisma/seed.ts"
  },
  "dependencies": {
    "@prisma/client": "^6.8.2",
    "next": "15.3.2",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "zustand": "^5.0.5"
  },
  "devDependencies": {
    "@eslint/eslintrc": "^3",
    "@tailwindcss/postcss": "^4",
    "@types/node": "^20",
    "@types/react": "^19",
    "@types/react-dom": "^19",
    "eslint": "^9",
    "eslint-config-next": "15.3.2",
    "prisma": "^6.8.2",
    "tailwindcss": "^4",
    "tsx": "^4.19.4",
    "typescript": "^5"
  }
}

Metadata working:

Metadata working

Metadata not working:

Metadata not working

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.