A comparison of metadata configurations between Lobechat and Shadcn/ui
In this article, you will learn how metadata is configured in Lobechat and Shadcn/ui. This comparison shows two ways to configure your metadata, key difference here is that Shadcn/ui is a UI components provider. You don’t see any API calls made to the backend and you don’t find any database involved either. Lobechat, on the other hand, is our team’s favorite and is quite complex and a large project that has a database, uses tRPC to make API calls.
You will find out how the files and folders are used to configure metadata depending on the context, more on this in the later parts of this article.
There are two ways you can define metadata in a Next.js layout or a page
-
Config-based Metadata: Export a static metadata object or a dynamic generateMetadata function in a layout.js or page.js file.
-
File-based Metadata: Add static or dynamically generated special files to route segments.
Read more about:
- Static metadata
- Dynamic metadata
- File Based Metadata
With this information from the documentation, we will find out which way Shadcn/ui and Lobechat have chosen.
Shadcn/ui metadata configuration
In the www/app/layout.tsx in Shadcn/ui source code, metadata is defined as shown below:
export const metadata: Metadata = {
title: {
default: siteConfig.name,
template: `%s - ${siteConfig.name}`,
},
metadataBase: new URL(siteConfig.url),
description: siteConfig.description,
keywords: [
"Next.js",
"React",
"Tailwind CSS",
"Server Components",
"Radix UI",
],
authors: [
{
name: "shadcn",
url: "https://shadcn.com",
},
],
creator: "shadcn",
openGraph: {
type: "website",
locale: "en_US",
url: siteConfig.url,
title: siteConfig.name,
description: siteConfig.description,
siteName: siteConfig.name,
images: [
{
url: siteConfig.ogImage,
width: 1200,
height: 630,
alt: siteConfig.name,
},
],
},
twitter: {
card: "summary_large_image",
title: siteConfig.name,
description: siteConfig.description,
images: [siteConfig.ogImage],
creator: "@shadcn",
},
icons: {
icon: "/favicon.ico",
shortcut: "/favicon-16x16.png",
apple: "/apple-touch-icon.png",
},
manifest: `${siteConfig.url}/site.webmanifest`,
}
What this means is that Shadcn/ui uses static metadata. SiteConfig is imported as shown below:
import { META_THEME_COLORS, siteConfig } from "@/config/site"
Lobechat metadata configuration
In the Lobechat/src/app/layout.tsx, you will find the below code:
export { generateMetadata } from './metadata';
generateMetadata here means that Lobechat uses dynamic metadata. Below is the code picked from Lobechat metadata file.
import { Metadata } from 'next';
import { appEnv } from '@/config/app';
import { BRANDING_LOGO_URL, BRANDING_NAME, ORG_NAME } from '@/const/branding';
import { OFFICIAL_URL, OG_URL } from '@/const/url';
import { isCustomBranding, isCustomORG } from '@/const/version';
import { translation } from '@/server/translation';
const BASE_PATH = appEnv.NEXT_PUBLIC_BASE_PATH;
// if there is a base path, then we don't need the manifest
const noManifest = !!BASE_PATH;
export const generateMetadata = async (): Promise<Metadata> => {
const { t } = await translation('metadata');
return {
alternates: {
canonical: OFFICIAL_URL,
},
appleWebApp: {
statusBarStyle: 'black-translucent',
title: BRANDING_NAME,
},
description: t('chat.description', { appName: BRANDING_NAME }),
icons: isCustomBranding
? BRANDING_LOGO_URL
: {
apple: '/apple-touch-icon.png?v=1',
icon: '/favicon.ico?v=1',
shortcut: '/favicon-32x32.ico?v=1',
},
manifest: noManifest ? undefined : '/manifest.json',
metadataBase: new URL(OFFICIAL_URL),
openGraph: {
description: t('chat.description', { appName: BRANDING_NAME }),
images: [
{
alt: t('chat.title', { appName: BRANDING_NAME }),
height: 640,
url: OG_URL,
width: 1200,
},
],
locale: 'en-US',
siteName: BRANDING_NAME,
title: BRANDING_NAME,
type: 'website',
url: OFFICIAL_URL,
},
title: {
default: t('chat.title', { appName: BRANDING_NAME }),
template: `%s · ${BRANDING_NAME}`,
},
twitter: {
card: 'summary_large_image',
description: t('chat.description', { appName: BRANDING_NAME }),
images: [OG_URL],
site: isCustomORG ? `@${ORG_NAME}` : '@lobehub',
title: t('chat.title', { appName: BRANDING_NAME }),
},
};
};
In the Shadcn/ui siteconfig, we saw it contains brand information and relevant urls, but Lobechat has done it differently. There’s a const
folder containing files such as
This configuration in the Lobechat comes from a folder named const instead of config, like in Shadcn/ui, because config folder in Lobechat
About us:
At Thinkthroo, we study large open source projects and provide architectural guides. We have developed reusable Components, built with tailwind, that you can use in your project. We offer Next.js, React and Node development services.
Book a meeting with us to discuss your project.
References:
1. https://github.com/lobehub/lobe-chat/blob/main/src/app/metadata.ts
2. https://github.com/shadcn-ui/ui/blob/main/apps/www/config/site.ts
3. https://nextjs.org/docs/app/building-your-application/optimizing/metadata#static-metadata
4. https://github.com/lobehub/lobe-chat/blob/main/src/app/layout.tsx#L47
5. https://nextjs.org/docs/app/building-your-application/optimizing/metadata#dynamic-metadata