{"id":12089,"date":"2024-06-06T13:00:00","date_gmt":"2024-06-06T13:00:00","guid":{"rendered":"https:\/\/cheesecakelabs.com\/blog\/"},"modified":"2024-06-06T14:58:23","modified_gmt":"2024-06-06T14:58:23","slug":"next-js-for-seo","status":"publish","type":"post","link":"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/","title":{"rendered":"How to Use Next.js for SEO and Server-Side Rendering Strategies"},"content":{"rendered":"\n<p>Optimizing your website or blog content for search engines using SEO (Search Engine Optimization) is a core digital marketing strategy.<\/p>\n\n\n\n<p>SEO is measured through performance metrics (page loading time), structured data (semantic and information architecture), and user experience (good usability), and enables more users to access your content and discover your offering.&nbsp;<\/p>\n\n\n\n<p>However, since frameworks for building Single-Page Applications (SPAs) like Angular and React have gained popularity, many web pages have dipped in their online visibility and search engine rankings.<\/p>\n\n\n\n<p>This is because these frameworks solely render the page content in the browser (Client-side) through JavaScript file downloads, meaning search engine crawlers struggle to inspect page content.<\/p>\n\n\n\n<p>To make your website more search engine and SEO friendly, it\u2019s best to generate pages on the server side (Server-side Rendering \u2014 SSR) to ensure content is readily available \u2014 and more easily crawlable \u2014 when accessing a URL. That\u2019s where Next.js for SEO comes in.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Why is Next.js good for SEO?<\/strong><\/h2>\n\n\n\n<p>Next.js offers <a href=\"https:\/\/nextjs.org\/docs\/app\/building-your-application\/optimizing\/images\" target=\"_blank\" rel=\"noreferrer noopener\">several features <\/a>that benefit SEO, including font and image optimization, custom head, script, and link components.<\/p>\n\n\n\n<p>However, its primary benefit is its ability to <strong>render web pages on the server (SSR) instead of in the browser (Client-side).<\/strong><\/p>\n\n\n\n<p>This allows search engine crawlers to <strong>better understand and index web pages.<\/strong> It also provides a faster load time, improving important <a href=\"https:\/\/developers.google.com\/search\/docs\/appearance\/core-web-vitals\" target=\"_blank\" rel=\"noreferrer noopener\">Core Web Vitals<\/a> that are key to SEO success.&nbsp;<\/p>\n\n\n\n<p><strong>In this article, we&#8217;ll explore how to leverage Next.js (one of the most popular React frameworks) to create server-side rendered pages optimized for search engines.&nbsp;<\/strong><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>How to leverage Next.js for SEO<\/strong><\/h2>\n\n\n\n<p>To illustrate how to use Next.js for SEO, we&#8217;ll create a project called &#8220;Country of the Day&#8221; that displays information about a given country based on what day it is using the publicly-available API <a href=\"https:\/\/restcountries.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">REST Countries<\/a>.<\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/jofelipe\/countryoftheday\" target=\"_blank\" rel=\"noreferrer noopener\">The repository for this project is available on GitHub.<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Project setup<\/strong><\/h3>\n\n\n\n<p>With the API integrations set up and the business logic in place, we can access today\u2019s country information with the following line of code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">const<\/span> country = <span class=\"hljs-keyword\">await<\/span> getCountry();<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The &#8216;<code>country<\/code>&#8216; object provides the country\u2019s name, capital city, flag, population, and currency, among others, as shown <a href=\"https:\/\/restcountries.com\/v3.1\/name\/Brazil\" target=\"_blank\" rel=\"noreferrer noopener\">in this example.<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Static metadata<\/strong><\/h3>\n\n\n\n<p>To define the title and meta description of the page, export a constant called &#8216;metadata&#8217; within the page file, as shown in the example below:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-keyword\">type<\/span> { Metadata } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next'<\/span>\n \n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> metadata: Metadata = {\n  title: <span class=\"hljs-string\">'Country of the day'<\/span>,\n  description: <span class=\"hljs-string\">'Discover the country of the day in our amazing page!'<\/span>,\n}\n \n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Page<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>You can also create a standardized <em>template<\/em> that automatically adds the website name to each page title, increasing brand awareness.<\/p>\n\n\n\n<p>You can do this in the layout.tsx file at the root of the <strong>app<\/strong> directory:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">import<\/span> { Metadata } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> metadata: Metadata = {\n  title: {\n    <span class=\"hljs-keyword\">default<\/span>: <span class=\"hljs-string\">'Country of the day'<\/span>,\n    template: <span class=\"hljs-string\">'%s - Country of the day'<\/span>,\n  }\n};\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">RootLayout<\/span>(<span class=\"hljs-params\">{\n  children,\n}: {\n  children: React.ReactNode;\n}<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> children;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Thanks to this code, all website pages will follow the same \u201cpage title + website name\u201d structure.&nbsp;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Dynamic metadata<\/strong><\/h3>\n\n\n\n<p>Alternatively, you can create dynamic metadata within the application by exporting an asynchronous function called &#8216;<strong><code>generateMetadata<\/code><\/strong>&#8216;, as shown in the example below:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">import<\/span> { Metadata } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next'<\/span>\n \n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">generateMetadata<\/span>(<span class=\"hljs-params\"><\/span>): <span class=\"hljs-title\">Promise<\/span>&lt;<span class=\"hljs-title\">Metadata<\/span>&gt; <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> country = <span class=\"hljs-keyword\">await<\/span> getCountry()\n\n  <span class=\"hljs-keyword\">const<\/span> {\n    name,\n    flags,\n  } = country;\n \n  <span class=\"hljs-keyword\">return<\/span> {\n    title: name.common,\n    description: name.official,\n    openGraph: {\n      images: &#91;<span class=\"hljs-string\">'\/some-specific-page-image.jpg'<\/span>, ...flags.png],\n    },\n  }\n}\n \n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Page<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This code retrieves the name and flag of the country to create the title, meta description, and Open Graph images of the page.<\/p>\n\n\n\n<p>Dynamic Metadata also allows you to retrieve parameters from the page\u2019s URL, such as the <em>id<\/em> or the <em>slug<\/em>. To do this, use the following code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">import<\/span> { Metadata } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next'<\/span>\n \n<span class=\"hljs-keyword\">type<\/span> Props = {\n  params: { id: <span class=\"hljs-built_in\">string<\/span> }\n}\n \n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">generateMetadata<\/span>(<span class=\"hljs-params\">\n  { params }: Props,\n<\/span>): <span class=\"hljs-title\">Promise<\/span>&lt;<span class=\"hljs-title\">Metadata<\/span>&gt; <\/span>{\n  <span class=\"hljs-comment\">\/\/ read route params<\/span>\n  <span class=\"hljs-keyword\">const<\/span> id = params.id\n \n  <span class=\"hljs-comment\">\/\/ fetch data<\/span>\n  <span class=\"hljs-keyword\">const<\/span> product = <span class=\"hljs-keyword\">await<\/span> fetch(<span class=\"hljs-string\">`https:\/\/...\/<span class=\"hljs-subst\">${id}<\/span>`<\/span>).then(<span class=\"hljs-function\">(<span class=\"hljs-params\"><span class=\"hljs-params\">res<\/span><\/span>) =&gt;<\/span> res.json())\n \n  <span class=\"hljs-keyword\">return<\/span> {\n    title: product.title,\n    description: product.description,\n    openGraph: {\n      images: &#91;<span class=\"hljs-string\">'\/some-specific-page-image.jpg'<\/span>, ...product.image.url],\n    },\n  }\n}\n \n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Page<\/span>(<span class=\"hljs-params\">{ params }: Props<\/span>) <\/span>{}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\"><strong>File-based metadata<\/strong><\/h3>\n\n\n\n<p>If you want to create the app icons for your Country of the Day application, you can use the file-based metadata with Vercel&#8217;s Edge Functions.<\/p>\n\n\n\n<p>To do this, create a favicon based on the country of the day. Using the <a href=\"http:\/\/next.js\" target=\"_blank\" rel=\"noreferrer noopener\">Next.js documentation<\/a>, add a file called <code>icon.tsx <\/code>in the root of the app directory:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">import<\/span> getCountry <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@\/services\/country\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { ImageResponse } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"next\/og\"<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> runtime = <span class=\"hljs-string\">\"edge\"<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> size = {\n  width: <span class=\"hljs-number\">32<\/span>,\n  height: <span class=\"hljs-number\">32<\/span>,\n};\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> contentType = <span class=\"hljs-string\">\"image\/png\"<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Icon<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> country = <span class=\"hljs-keyword\">await<\/span> getCountry();\n\n  <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">new<\/span> ImageResponse(\n    (\n      &lt;div\n        style={{\n          background: <span class=\"hljs-string\">\"#333\"<\/span>,\n          width: <span class=\"hljs-string\">\"100%\"<\/span>,\n          height: <span class=\"hljs-string\">\"100%\"<\/span>,\n          display: <span class=\"hljs-string\">\"flex\"<\/span>,\n          alignItems: <span class=\"hljs-string\">\"center\"<\/span>,\n          justifyContent: <span class=\"hljs-string\">\"center\"<\/span>,\n          paddingLeft: <span class=\"hljs-number\">4<\/span>,\n          paddingRight: <span class=\"hljs-number\">4<\/span>,\n        }}\n      &gt;\n        &lt;img src={country.flags.png} alt={country.name.official} \/&gt;\n      &lt;<span class=\"hljs-regexp\">\/div&gt;\n    ),\n    {\n      ...size,\n    },\n  );\n}<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>And there you have it \u2014 a dynamic favicon based on the country of the day \ud83e\udd29<\/p>\n\n\n\n<p>You can also create other files such as <strong>robots.txt<\/strong>, <strong>sitemap.xml<\/strong>, and <strong>Open Graph images<\/strong>, as shown in the example below.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>OpenGraph<\/strong><\/h3>\n\n\n\n<p>The Open Graph, an internet protocol developed by Facebook, standardizes metadata to improve how a page\u2019s content is represented.<\/p>\n\n\n\n<p>With it, you can enhance the link-sharing experience on the web, attracting more visitors to your content.<\/p>\n\n\n\n<p>However, creating and sharing images for each new page on a website can be costly. <strong>Instead, let\u2019s automate this process.<\/strong><\/p>\n\n\n\n<p>Similar to creating a favicon, create a file called <code>opengraph-image.tsx<\/code> in the directory of your page within the app folder of your application.&nbsp;<\/p>\n\n\n\n<p>This code will return an ImageResponse \u2014 an image generated with JavaScript. The coolest part is that you can create images based on the route segment of the application, <a href=\"http:\/\/next.js\" target=\"_blank\" rel=\"noreferrer noopener\">as the Next.js documentation shows here.<\/a><\/p>\n\n\n\n<p>In this example, let\u2019s create an image similar to the layout below:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" width=\"1200\" height=\"630\" src=\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2024\/05\/open-graph-next.js-for-seo.png\" alt=\"og tag image example brazilian tag\" class=\"wp-image-12090\" srcset=\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2024\/05\/open-graph-next.js-for-seo.png 1200w, https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2024\/05\/open-graph-next.js-for-seo-600x315.png 600w, https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2024\/05\/open-graph-next.js-for-seo-768x403.png 768w, https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2024\/05\/open-graph-next.js-for-seo-760x399.png 760w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure>\n\n\n\n<p>Using the <a href=\"https:\/\/og-playground.vercel.app\/\" target=\"_blank\" rel=\"noreferrer noopener\">Vercel OG Image Playground<\/a> tool, create a file with the following code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">import<\/span> getCountry <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@\/services\/country\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { ImageResponse } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"next\/og\"<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> runtime = <span class=\"hljs-string\">\"edge\"<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Image<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> country = <span class=\"hljs-keyword\">await<\/span> getCountry();\n\n  <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">new<\/span> ImageResponse(\n    (\n      &lt;div\n        style={{\n          backgroundColor: <span class=\"hljs-string\">\"#151718\"<\/span>,\n          width: <span class=\"hljs-string\">\"100%\"<\/span>,\n          height: <span class=\"hljs-string\">\"100%\"<\/span>,\n          display: <span class=\"hljs-string\">\"flex\"<\/span>,\n          textAlign: <span class=\"hljs-string\">\"center\"<\/span>,\n          alignItems: <span class=\"hljs-string\">\"center\"<\/span>,\n          justifyContent: <span class=\"hljs-string\">\"center\"<\/span>,\n        }}\n      &gt;\n        &lt;div\n          style={{\n            color: <span class=\"hljs-string\">\"rgb(237, 237, 237)\"<\/span>,\n            display: <span class=\"hljs-string\">\"flex\"<\/span>,\n            fontSize: <span class=\"hljs-string\">\"4rem\"<\/span>,\n            fontWeight: <span class=\"hljs-string\">\"bold\"<\/span>,\n            flexDirection: <span class=\"hljs-string\">\"column\"<\/span>,\n            alignItems: <span class=\"hljs-string\">\"center\"<\/span>,\n          }}\n        &gt;\n          &lt;img\n            src={country.flags.png}\n            width=<span class=\"hljs-string\">\"320\"<\/span>\n            height=<span class=\"hljs-string\">\"200\"<\/span>\n            style={{ borderRadius: <span class=\"hljs-number\">8<\/span>, marginBottom: <span class=\"hljs-number\">48<\/span> }}\n          \/&gt;\n          &lt;div\n            style={{\n              backgroundImage:\n                <span class=\"hljs-string\">\"linear-gradient(180deg, rgb(237, 237, 237), rgb(139, 149, 154))\"<\/span>,\n              backgroundClip: <span class=\"hljs-string\">\"text\"<\/span>,\n              color: <span class=\"hljs-string\">\"transparent\"<\/span>,\n            }}\n          &gt;\n            {country.name.official}\n          &lt;<span class=\"hljs-regexp\">\/div&gt;\n          &lt;div style={{ display: \"flex\", fontSize: \"2.4rem\" }}&gt;\n            is the country of the day\n          &lt;\/<\/span>div&gt;\n          &lt;div style={{ display: <span class=\"hljs-string\">\"flex\"<\/span>, fontSize: <span class=\"hljs-string\">\"1.6rem\"<\/span>, marginTop: <span class=\"hljs-number\">48<\/span> }}&gt;\n            \ud83d\udd17 countryoftheday.vercel.app\n          &lt;<span class=\"hljs-regexp\">\/div&gt;\n        &lt;\/<\/span>div&gt;\n      &lt;<span class=\"hljs-regexp\">\/div&gt;\n    ),\n    {\n      width: 1200,\n      height: 630,\n    },\n  );\n}<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>As you can see, the code dynamically retrieves the name and flag of the country and creates an image through JavaScript code.<\/p>\n\n\n\n<p>This will make the page content more engaging when you share the link on social media. We recommend using the website <a href=\"https:\/\/opengraph.xyz\/\" target=\"_blank\" rel=\"noreferrer noopener\">opengraph.xyz<\/a> to conduct your tests after publishing the page:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" width=\"558\" height=\"395\" src=\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2024\/05\/social-media-sharing-og-tag-next.js-seo.png\" alt=\"social media sharing og tag example brazilian flag\" class=\"wp-image-12092\"\/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>JSON-LD<\/strong><\/h3>\n\n\n\n<p>Last but not least, you can structure your content using the JSON Linked Data protocol to enhance the display of the page in Google Search results, for example.<\/p>\n\n\n\n<p>Structured data is a standardized format to provide information about a page and classify its content.<\/p>\n\n\n\n<p>For example, on a country page, structured data can provide information about the country\u2019s population, total area, local currency, and so on.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>&#8220;Rotten Tomatoes added structured data to 100,000 unique pages and measured a 25% higher click-through rate on pages enhanced with structured data compared to pages without this feature.<\/p>\n<\/blockquote>\n\n\n\n<p>Continuing with the Country of the Day example, you could structure a page\u2019s content as follows:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">import<\/span> { Country, WithContext } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"schema-dts\"<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> getCountry <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@\/services\/country\"<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Page<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> country = <span class=\"hljs-keyword\">await<\/span> getCountry();\n  <span class=\"hljs-keyword\">const<\/span> { name, flags, coatOfArms, latlng } = country;\n\n  <span class=\"hljs-keyword\">const<\/span> jsonLd: WithContext&lt;Country&gt; = {\n    <span class=\"hljs-string\">\"@context\"<\/span>: <span class=\"hljs-string\">\"https:\/\/schema.org\"<\/span>,\n    <span class=\"hljs-string\">\"@type\"<\/span>: <span class=\"hljs-string\">\"Country\"<\/span>,\n    image: flags.png,\n    latitude: latlng&#91;<span class=\"hljs-number\">0<\/span>],\n    longitude: latlng&#91;<span class=\"hljs-number\">1<\/span>],\n    logo: coatOfArms.png,\n    name: name.official,\n    alternateName: name.common,\n  };\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    &lt;article&gt;\n      {<span class=\"hljs-comment\">\/* Page content *\/<\/span>}\n\n      &lt;script\n        <span class=\"hljs-keyword\">type<\/span>=<span class=\"hljs-string\">\"application\/ld+json\"<\/span>\n        dangerouslySetInnerHTML={{ __html: <span class=\"hljs-built_in\">JSON<\/span>.stringify(jsonLd) }}\n      \/&gt;\n    &lt;<span class=\"hljs-regexp\">\/article&gt;\n  );\n}<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Note the inclusion of&nbsp; &#8220;application\/ld+json&#8221; to add structured data into the HTML of the page.<\/p>\n\n\n\n<p>It&#8217;s also worth noting how the npm library <code>schema-dts<\/code> helps to type and correctly define the provided information.<\/p>\n\n\n\n<p>With these measures, you&#8217;re on your way to achieving excellent results in search engines.<\/p>\n\n\n\n<p>Plus, the examples presented already include server-side rendering, ensuring that the content is immediately available when accessing any page.<\/p>\n\n\n\n<p>You can check out the finalized project at <a href=\"https:\/\/countryoftheday.vercel.app\/\" target=\"_blank\" rel=\"noreferrer noopener\">Country of the Day.<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Next.js is a great choice for SEO projects<\/strong><\/h2>\n\n\n\n<p>Since releasing Next.js version 13, Next.js has made a significant leap in its SEO-focused features. What previously required third-party libraries is now possible natively.&nbsp;<\/p>\n\n\n\n<p>Plus, developing an application with this framework ensures its performance is optimized for SEO from the get-go.<\/p>\n\n\n\n<p>Here at Cheesecake, we&#8217;ve already started using Next.js for SEO with server-side rendering in some of our projects.&nbsp;<\/p>\n\n\n\n<p>To learn more about what we\u2019ve been working on lately, be sure to <a href=\"https:\/\/cheesecakelabs.com\/portfolio\/\" target=\"_blank\" rel=\"noreferrer noopener\">check out our portfolio<\/a>. <\/p>\n\n\n\n<p>If you have a project that could benefit from Next.js or have an idea you\u2019d like to discuss, <a href=\"https:\/\/cheesecakelabs.com\/contact\/\" target=\"_blank\" rel=\"noreferrer noopener\">send us a message<\/a> \u2014 we\u2019d love to hear from you.&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Optimizing your website or blog content for search engines using SEO (Search Engine Optimization) is a core digital marketing strategy. SEO is measured through performance metrics (page loading time), structured data (semantic and information architecture), and user experience (good usability), and enables more users to access your content and discover your offering.&nbsp; However, since frameworks [&hellip;]<\/p>\n","protected":false},"author":81,"featured_media":12098,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[432],"tags":[1275,1274,1276],"class_list":["post-12089","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-engineering","tag-java-script","tag-next-js","tag-typescript"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>How to use Next.js for SEO and Server-Side Rendering strategies<\/title>\n<meta name=\"description\" content=\"Find out why Next.js is good for SEO and how to leverage its key features, including creating SSR pages optimized for search engines.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to use Next.js for SEO and Server-Side Rendering strategies\" \/>\n<meta property=\"og:description\" content=\"Find out why Next.js is good for SEO and how to leverage its key features, including creating SSR pages optimized for search engines.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/\" \/>\n<meta property=\"og:site_name\" content=\"Cheesecake Labs\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/cheesecakelabs\" \/>\n<meta property=\"article:published_time\" content=\"2024-06-06T13:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-06-06T14:58:23+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2024\/05\/next.js-for-seo-ssr.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1921\" \/>\n\t<meta property=\"og:image:height\" content=\"861\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Cheesecake Labs\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@cheesecakelabs\" \/>\n<meta name=\"twitter:site\" content=\"@cheesecakelabs\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/\"},\"author\":{\"name\":\"Jonathan Felipe de Oliveira\"},\"headline\":\"How to Use Next.js for SEO and Server-Side Rendering Strategies\",\"datePublished\":\"2024-06-06T13:00:00+00:00\",\"dateModified\":\"2024-06-06T14:58:23+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/\"},\"wordCount\":1133,\"image\":{\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2024\/05\/next.js-for-seo-ssr.png\",\"keywords\":[\"java script\",\"next js\",\"typescript\"],\"articleSection\":[\"Engineering\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/\",\"url\":\"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/\",\"name\":\"How to use Next.js for SEO and Server-Side Rendering strategies\",\"isPartOf\":{\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2024\/05\/next.js-for-seo-ssr.png\",\"datePublished\":\"2024-06-06T13:00:00+00:00\",\"dateModified\":\"2024-06-06T14:58:23+00:00\",\"author\":{\"@type\":\"person\",\"name\":\"Jonathan Felipe de Oliveira\"},\"description\":\"Find out why Next.js is good for SEO and how to leverage its key features, including creating SSR pages optimized for search engines.\",\"breadcrumb\":{\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/#primaryimage\",\"url\":\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2024\/05\/next.js-for-seo-ssr.png\",\"contentUrl\":\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2024\/05\/next.js-for-seo-ssr.png\",\"width\":1921,\"height\":861,\"caption\":\"next.js for seo\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cheesecakelabs.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to Use Next.js for SEO and Server-Side Rendering Strategies\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/#website\",\"url\":\"https:\/\/cheesecakelabs.com\/blog\/\",\"name\":\"Cheesecake Labs\",\"description\":\"Nearshore outsourcing company for Web and Mobile design and engineering services, and staff augmentation for startups and enterprises..\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cheesecakelabs.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"name\":\"Jonathan Felipe de Oliveira\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2024\/05\/Jonathan-Felipe-de-Oliveira.jpg\",\"contentUrl\":\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2024\/05\/Jonathan-Felipe-de-Oliveira.jpg\",\"caption\":\"Jonathan Felipe de Oliveira\"},\"url\":\"https:\/\/cheesecakelabs.com\/blog\/autor\/jonathan-felipe-de-oliveira\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"How to use Next.js for SEO and Server-Side Rendering strategies","description":"Find out why Next.js is good for SEO and how to leverage its key features, including creating SSR pages optimized for search engines.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/","og_locale":"en_US","og_type":"article","og_title":"How to use Next.js for SEO and Server-Side Rendering strategies","og_description":"Find out why Next.js is good for SEO and how to leverage its key features, including creating SSR pages optimized for search engines.","og_url":"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/","og_site_name":"Cheesecake Labs","article_publisher":"https:\/\/www.facebook.com\/cheesecakelabs","article_published_time":"2024-06-06T13:00:00+00:00","article_modified_time":"2024-06-06T14:58:23+00:00","og_image":[{"width":1921,"height":861,"url":"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2024\/05\/next.js-for-seo-ssr.png","type":"image\/png"}],"author":"Cheesecake Labs","twitter_card":"summary_large_image","twitter_creator":"@cheesecakelabs","twitter_site":"@cheesecakelabs","twitter_misc":{"Written by":null,"Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/#article","isPartOf":{"@id":"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/"},"author":{"name":"Jonathan Felipe de Oliveira"},"headline":"How to Use Next.js for SEO and Server-Side Rendering Strategies","datePublished":"2024-06-06T13:00:00+00:00","dateModified":"2024-06-06T14:58:23+00:00","mainEntityOfPage":{"@id":"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/"},"wordCount":1133,"image":{"@id":"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/#primaryimage"},"thumbnailUrl":"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2024\/05\/next.js-for-seo-ssr.png","keywords":["java script","next js","typescript"],"articleSection":["Engineering"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/","url":"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/","name":"How to use Next.js for SEO and Server-Side Rendering strategies","isPartOf":{"@id":"https:\/\/cheesecakelabs.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/#primaryimage"},"image":{"@id":"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/#primaryimage"},"thumbnailUrl":"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2024\/05\/next.js-for-seo-ssr.png","datePublished":"2024-06-06T13:00:00+00:00","dateModified":"2024-06-06T14:58:23+00:00","author":{"@type":"person","name":"Jonathan Felipe de Oliveira"},"description":"Find out why Next.js is good for SEO and how to leverage its key features, including creating SSR pages optimized for search engines.","breadcrumb":{"@id":"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/#primaryimage","url":"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2024\/05\/next.js-for-seo-ssr.png","contentUrl":"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2024\/05\/next.js-for-seo-ssr.png","width":1921,"height":861,"caption":"next.js for seo"},{"@type":"BreadcrumbList","@id":"https:\/\/cheesecakelabs.com\/blog\/next-js-for-seo\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cheesecakelabs.com\/blog\/"},{"@type":"ListItem","position":2,"name":"How to Use Next.js for SEO and Server-Side Rendering Strategies"}]},{"@type":"WebSite","@id":"https:\/\/cheesecakelabs.com\/blog\/#website","url":"https:\/\/cheesecakelabs.com\/blog\/","name":"Cheesecake Labs","description":"Nearshore outsourcing company for Web and Mobile design and engineering services, and staff augmentation for startups and enterprises..","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cheesecakelabs.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","name":"Jonathan Felipe de Oliveira","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cheesecakelabs.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2024\/05\/Jonathan-Felipe-de-Oliveira.jpg","contentUrl":"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2024\/05\/Jonathan-Felipe-de-Oliveira.jpg","caption":"Jonathan Felipe de Oliveira"},"url":"https:\/\/cheesecakelabs.com\/blog\/autor\/jonathan-felipe-de-oliveira\/"}]}},"_links":{"self":[{"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/posts\/12089","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/users\/81"}],"replies":[{"embeddable":true,"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/comments?post=12089"}],"version-history":[{"count":3,"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/posts\/12089\/revisions"}],"predecessor-version":[{"id":12102,"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/posts\/12089\/revisions\/12102"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/media\/12098"}],"wp:attachment":[{"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/media?parent=12089"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/categories?post=12089"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/tags?post=12089"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}