<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ondřej Chrastina</title>
    <description>The latest articles on DEV Community by Ondřej Chrastina (@simply007).</description>
    <link>https://dev.to/simply007</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F178996%2F66df492a-ed05-46d5-a2c2-81655fb0de8f.jpeg</url>
      <title>DEV Community: Ondřej Chrastina</title>
      <link>https://dev.to/simply007</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/simply007"/>
    <language>en</language>
    <item>
      <title>[Boost]</title>
      <dc:creator>Ondřej Chrastina</dc:creator>
      <pubDate>Thu, 02 Apr 2026 05:40:09 +0000</pubDate>
      <link>https://dev.to/simply007/-1pli</link>
      <guid>https://dev.to/simply007/-1pli</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/ckeditor/drupalcon-chicago-2026-how-i-vibe-coded-my-first-custom-drupal-module-extending-ckeditor-59mn" class="crayons-story__hidden-navigation-link"&gt;DrupalCon Chicago 2026: How I vibe-coded my first custom Drupal module extending CKEditor&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;
          &lt;a class="crayons-logo crayons-logo--l" href="/ckeditor"&gt;
            &lt;img alt="CKEditor logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F2059%2F560da4e4-70e8-4a52-8cb6-b9f0b4398147.png" class="crayons-logo__image" width="652" height="449"&gt;
          &lt;/a&gt;

          &lt;a href="/simply007" class="crayons-avatar  crayons-avatar--s absolute -right-2 -bottom-2 border-solid border-2 border-base-inverted  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F178996%2F66df492a-ed05-46d5-a2c2-81655fb0de8f.jpeg" alt="simply007 profile" class="crayons-avatar__image" width="460" height="460"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/simply007" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Ondřej Chrastina
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Ondřej Chrastina
                
              
              &lt;div id="story-author-preview-content-3436885" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/simply007" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F178996%2F66df492a-ed05-46d5-a2c2-81655fb0de8f.jpeg" class="crayons-avatar__image" alt="" width="460" height="460"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Ondřej Chrastina&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;span&gt;
              &lt;span class="crayons-story__tertiary fw-normal"&gt; for &lt;/span&gt;&lt;a href="/ckeditor" class="crayons-story__secondary fw-medium"&gt;CKEditor&lt;/a&gt;
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;a href="https://dev.to/ckeditor/drupalcon-chicago-2026-how-i-vibe-coded-my-first-custom-drupal-module-extending-ckeditor-59mn" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 1&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/ckeditor/drupalcon-chicago-2026-how-i-vibe-coded-my-first-custom-drupal-module-extending-ckeditor-59mn" id="article-link-3436885"&gt;
          DrupalCon Chicago 2026: How I vibe-coded my first custom Drupal module extending CKEditor
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/drupal"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;drupal&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/tutorial"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;tutorial&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/ckeditor/drupalcon-chicago-2026-how-i-vibe-coded-my-first-custom-drupal-module-extending-ckeditor-59mn#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            7 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>DrupalCon Chicago 2026: How I vibe-coded my first custom Drupal module extending CKEditor</title>
      <dc:creator>Ondřej Chrastina</dc:creator>
      <pubDate>Wed, 01 Apr 2026 14:58:57 +0000</pubDate>
      <link>https://dev.to/ckeditor/drupalcon-chicago-2026-how-i-vibe-coded-my-first-custom-drupal-module-extending-ckeditor-59mn</link>
      <guid>https://dev.to/ckeditor/drupalcon-chicago-2026-how-i-vibe-coded-my-first-custom-drupal-module-extending-ckeditor-59mn</guid>
      <description>&lt;p&gt;I was at &lt;a href="https://events.drupal.org/chicago2026" rel="noopener noreferrer"&gt;DrupalCon Chicago 2026&lt;/a&gt;, juggling booth duty, an AI Summit talk, and a Lightning Talk about CKEditor's contrib modules. &lt;strong&gt;But it's those hallway conversations that stick with you – and this time, the same question kept coming up.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;"How do I customize CKEditor just a little bit?"&lt;/li&gt;
&lt;li&gt;"Can I add my own button?"&lt;/li&gt;
&lt;li&gt;"I want something specific to our workflow, but where do I even start?"&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;People knew what they wanted. They just didn't know how to get there.&lt;/p&gt;

&lt;p&gt;So I grabbed &lt;a href="https://www.drupal.org/u/salmonek" rel="noopener noreferrer"&gt;Wojtek Kukowski&lt;/a&gt; – the main maintainer of the CKEditor Drupal modules (&lt;a href="https://www.drupal.org/project/ckeditor5_plugin_pack" rel="noopener noreferrer"&gt;CKEditor 5 Plugin Pack&lt;/a&gt; and &lt;a href="https://www.drupal.org/project/ckeditor5_premium_features" rel="noopener noreferrer"&gt;CKEditor 5 Premium Features&lt;/a&gt;), and asked him:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"What's actually required to make a CKEditor plugin extension for Drupal?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;He briefed me on the essentials: create a Drupal module that wraps a CKEditor plugin. And I thought: "Let me try to translate this into a prompt for &lt;a href="https://docs.anthropic.com/en/docs/claude-code" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt; and include the official docs and see what happens."&lt;/p&gt;

&lt;h2&gt;
  
  
  The experiment
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Drupal&lt;/strong&gt;: 11.3.3.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool&lt;/strong&gt;: Claude Code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Goal&lt;/strong&gt;: Create a Drupal module with a CKEditor 5 plugin from scratch.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The prompt (almost too simple)
&lt;/h3&gt;

&lt;p&gt;I kept it minimal:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I would like to register a new module for Drupal based on the &lt;a href="https://www.drupal.org/docs/develop/creating-modules" rel="noopener noreferrer"&gt;https://www.drupal.org/docs/develop/creating-modules&lt;/a&gt; information. I would like the module to be a CKEditor plugin &lt;a href="https://ckeditor.com/docs/ckeditor5/latest/framework/tutorials/creating-simple-plugin-timestamp.html" rel="noopener noreferrer"&gt;https://ckeditor.com/docs/ckeditor5/latest/framework/tutorials/creating-simple-plugin-timestamp.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are not sure, ask me.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's it. Two documentation links and an invitation to ask questions.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happened
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Claude explored the codebase&lt;/strong&gt; – I was prompting in the local project with CKEditor AI running. It found existing CKEditor modules (&lt;a href="https://www.drupal.org/project/ckeditor5_plugin_pack" rel="noopener noreferrer"&gt;CKEditor 5 Plugin Pack&lt;/a&gt; and &lt;a href="https://www.drupal.org/project/ckeditor5_premium_features" rel="noopener noreferrer"&gt;CKEditor 5 Premium Features&lt;/a&gt; in my case) and learned from their patterns.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Claude asked clarifying questions&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What should the plugin do? (Insert timestamp.)&lt;/li&gt;
&lt;li&gt;What should the module be called? (&lt;code&gt;ckeditor5_timestamp&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Toolbar button or context menu? (Toolbar button.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Claude created all the files&lt;/strong&gt; – module metadata, CKEditor configuration, JavaScript plugin, PHP class. Everything.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Time&lt;/strong&gt;: A couple of minutes.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let me show you what it generated.&lt;/p&gt;

&lt;h2&gt;
  
  
  The files Claude created
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;All in &lt;code&gt;~/web/modules/custom/ckeditor5_timestamp&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Module metadata
&lt;/h3&gt;

&lt;p&gt;The standard &lt;code&gt;.info.yml&lt;/code&gt; that tells Drupal about your module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CKEditor 5 Timestamp&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;module&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Adds&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;CKEditor&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;5&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;plugin&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;that&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;inserts&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;current&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;at&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;cursor&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;position."&lt;/span&gt;
&lt;span class="na"&gt;package&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CKEditor&lt;/span&gt;
&lt;span class="na"&gt;core_version_requirement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;^10.1&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;||&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;^11"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  CKEditor plugin definition
&lt;/h3&gt;

&lt;p&gt;This is where the magic happens – the &lt;code&gt;.ckeditor5.yml&lt;/code&gt; file that registers your plugin with Drupal's CKEditor integration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;ckeditor5_timestamp_timestamp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ckeditor5&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;timestamp.Timestamp&lt;/span&gt;
  &lt;span class="na"&gt;drupal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Timestamp&lt;/span&gt;
    &lt;span class="na"&gt;library&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ckeditor5_timestamp/timestamp&lt;/span&gt;
    &lt;span class="na"&gt;toolbar_items&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Timestamp&lt;/span&gt;
    &lt;span class="na"&gt;elements&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  JavaScript plugin
&lt;/h3&gt;

&lt;p&gt;The actual CKEditor 5 plugin that creates the toolbar button and handles the timestamp insertion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Plugin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ckeditor5/src/core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ButtonView&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ckeditor5/src/ui&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Timestamp&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Plugin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;componentFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;timestamp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ButtonView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Timestamp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;withText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;tooltip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;execute&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;change&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;editing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;pluginName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Timestamp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Timestamp&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  PHP plugin class
&lt;/h3&gt;

&lt;p&gt;A minimal PHP class that extends Drupal's CKEditor plugin system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Drupal\ckeditor5_timestamp\Plugin\CKEditor5Plugin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Drupal\ckeditor5\Plugin\CKEditor5PluginDefault&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cd"&gt;/**
 * CKEditor 5 Timestamp plugin.
 */&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Timestamp&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;CKEditor5PluginDefault&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The gotcha (there's always one)
&lt;/h2&gt;

&lt;p&gt;I enabled the module, cleared the cache, added the button to a text format... and hit this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CKEditorError: plugincollection-plugin-not-found {"plugin":null}
Read more: https://ckeditor.com/docs/ckeditor5/latest/support/error-codes.html#error-plugincollection-plugin-not-found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fipugutm2q1qbiw3l1kdp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fipugutm2q1qbiw3l1kdp.png" alt="console with error" width="800" height="217"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The problem
&lt;/h3&gt;

&lt;p&gt;Drupal's CKEditor 5 uses a &lt;strong&gt;DLL (Dynamic Link Library) pattern&lt;/strong&gt; – webpack-specific builds that register plugins to the global &lt;code&gt;CKEditor5&lt;/code&gt; variable. Raw ES modules don't work – plugins must be bundled and exported to the &lt;code&gt;CKEditor5.[pluginname]&lt;/code&gt; namespace.&lt;/p&gt;

&lt;p&gt;Drupal core is discussing an &lt;a href="https://www.drupal.org/node/3398525" rel="noopener noreferrer"&gt;Import Maps API&lt;/a&gt; that might let browsers resolve ES module imports natively – no bundling to UMD required. If import maps land in Drupal core, you'll be able to write clean &lt;code&gt;import { Plugin } from 'ckeditor5/src/core'&lt;/code&gt; statements and have the browser figure out the rest. &lt;a href="https://caniuse.com/?search=import+map" rel="noopener noreferrer"&gt;Browser support for import maps&lt;/a&gt; is getting there too: Chrome 133+ and Safari already support multiple import maps, with Firefox ESR 153 expected around July 2026.&lt;/p&gt;

&lt;h3&gt;
  
  
  The fix
&lt;/h3&gt;

&lt;p&gt;Claude created a properly bundled version in &lt;code&gt;js/build/timestamp.js&lt;/code&gt; and updated the library configuration to point to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;js&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;js/build/timestamp.js&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;minified&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;core/ckeditor5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Total additional time&lt;/strong&gt;: About 2 minutes.&lt;/p&gt;

&lt;p&gt;Voila! The timestamp button appeared in the toolbar, and clicking it inserted the current date and time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmq8wlugim1ycgekyf0kn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmq8wlugim1ycgekyf0kn.png" alt="Timestamp plugin showcase" width="800" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9qm1zrp69dfehrk3s1rs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9qm1zrp69dfehrk3s1rs.png" alt="Timestamp diagram flow" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What you get
&lt;/h2&gt;

&lt;p&gt;Two files that can help you extend CKEditor:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SKILL.md&lt;/strong&gt; – A comprehensive guide teaching Claude Code how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explore existing CKEditor implementations.&lt;/li&gt;
&lt;li&gt;Ask the right clarifying questions.&lt;/li&gt;
&lt;li&gt;Create all necessary files.&lt;/li&gt;
&lt;li&gt;Handle the DLL bundling requirement.&lt;/li&gt;
&lt;li&gt;Troubleshoot common issues.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;PROMPT.md&lt;/strong&gt; – A template you can customize:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace the plugin requirements with yours.&lt;/li&gt;
&lt;li&gt;Specify your module name.&lt;/li&gt;
&lt;li&gt;Define the UI type you need.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How to use it
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Install Claude Code&lt;/strong&gt;: See the &lt;a href="https://docs.anthropic.com/en/docs/claude-code" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Put the files in your Drupal project&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Adjust PROMPT.md&lt;/strong&gt; with your requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Plugin function: What should it do?&lt;/li&gt;
&lt;li&gt;Module name: your_module_name.&lt;/li&gt;
&lt;li&gt;UI type: Toolbar button, context menu, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ask Claude to run it&lt;/strong&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please create a CKEditor 5 plugin for Drupal following the SKILL.md approach using the requirements in PROMPT.md&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enable and configure&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   drush en your_module_name
   drush cr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then configure the text format in Drupal admin to add your new button.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;

&lt;p&gt;My plugin was straightforward – a simple timestamp inserter. I'm curious how it works for you with more complex requirements.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Did it work on the first try?&lt;/li&gt;
&lt;li&gt;What gotchas did you encounter?&lt;/li&gt;
&lt;li&gt;How complex was your plugin?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can check out the files like &lt;code&gt;PROMPT.md&lt;/code&gt; and &lt;code&gt;SKILL.md&lt;/code&gt; as well as the module files in the &lt;a href="https://github.com/Simply007/drupalcon-chicago-26-ckeditor-ai-playground" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond the plugin
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How the SKILL.md and PROMPT.md came to be
&lt;/h3&gt;

&lt;p&gt;The same "reverse engineering" approach I used for the webpack configuration also created the SKILL.md and PROMPT.md files. After Claude successfully built the plugin, I backtracked through its actions – what did it explore? What questions did it ask? What files did it create? – and distilled that into reusable instructions.&lt;/p&gt;

&lt;p&gt;I do this whenever I need repeatable context. Instead of relying solely on a project-wide CLAUDE.md file, I create focused instruction files for specific tasks. The SKILL.md teaches Claude &lt;em&gt;how&lt;/em&gt; to build CKEditor plugins; the PROMPT.md provides the &lt;em&gt;what&lt;/em&gt; – the specific requirements for each new plugin.&lt;/p&gt;

&lt;h3&gt;
  
  
  CI for the build
&lt;/h3&gt;

&lt;p&gt;Similarly, I asked Claude to generate a GitHub Actions workflow that builds the JavaScript on every push to main. If the bundled output changes, the action commits it automatically. This keeps the repository's &lt;code&gt;js/build/timestamp.js&lt;/code&gt; in sync without manual intervention – useful for contributors who might not have Node.js set up locally.&lt;/p&gt;

&lt;h3&gt;
  
  
  Making it community-friendly
&lt;/h3&gt;

&lt;p&gt;To make this repository truly accessible as a starting point, more work would be needed: proper documentation, contribution guidelines, issue templates, and licensing clarity. I maintain a template for this at &lt;a href="https://github.com/Simply007/os-guidelines" rel="noopener noreferrer"&gt;os-guidelines&lt;/a&gt; – a checklist covering everything from repository naming to CI automation across different tech stacks. If you're publishing your own CKEditor plugin module, consider using it as a starting point.&lt;/p&gt;




&lt;h2&gt;
  
  
  Want to learn more?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create your own plugin&lt;/strong&gt;: Check out the &lt;a href="https://ckeditor.com/docs/ckeditor5/latest/framework/tutorials/creating-simple-plugin-timestamp.html" rel="noopener noreferrer"&gt;CKEditor 5 plugin development guide&lt;/a&gt; for the full tutorial on building custom plugins from scratch. Once you're comfortable with the basics, explore more capabilities – &lt;a href="https://ckeditor.com/docs/ckeditor5/latest/getting-started/setup/toolbar.html" rel="noopener noreferrer"&gt;toolbar customization&lt;/a&gt;, &lt;a href="https://ckeditor.com/docs/ckeditor5/latest/framework/architecture/editing-engine.html" rel="noopener noreferrer"&gt;editor behavior hooks&lt;/a&gt;, and &lt;a href="https://ckeditor.com/docs/ckeditor5/latest/framework/architecture/core-editor-architecture.html#commands" rel="noopener noreferrer"&gt;custom commands&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Try CKEditor AI&lt;/strong&gt;: The &lt;a href="https://ckeditor.com/ckeditor-5/capabilities/ai-features/" rel="noopener noreferrer"&gt;AI capabilities&lt;/a&gt; have been in CKEditor since last year and are gaining adoption across the ecosystem. Drupal support landed just a week before DrupalCon – perfect timing! You can &lt;a href="https://ckeditor.com/ckeditor-5/capabilities/ai-features/" rel="noopener noreferrer"&gt;try the demo&lt;/a&gt; right in your browser, or grab a &lt;a href="https://portal.ckeditor.com/signup/" rel="noopener noreferrer"&gt;free 14-day trial&lt;/a&gt; to test it in your own Drupal installation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Grab the code&lt;/strong&gt;: All the files from this article – SKILL.md, PROMPT.md, the complete module, webpack config, and GitHub Actions workflow – are available in the &lt;a href="https://github.com/Simply007/drupalcon-chicago-26-ckeditor-ai-playground" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enjoy! And if you have any question - the comments section is yours, or find me up on Drupal Slack! 🥑&lt;/p&gt;

</description>
      <category>drupal</category>
      <category>ai</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>AI Conference 2025 - CKEditor in da house</title>
      <dc:creator>Ondřej Chrastina</dc:creator>
      <pubDate>Tue, 07 Oct 2025 12:55:04 +0000</pubDate>
      <link>https://dev.to/ckeditor/ai-conference-2025-ckeditor-in-da-house-m11</link>
      <guid>https://dev.to/ckeditor/ai-conference-2025-ckeditor-in-da-house-m11</guid>
      <description>&lt;p&gt;In the middle of September 2025, the CKEditor team attended &lt;a href="https://aiconference.com" rel="noopener noreferrer"&gt;The AI Conference&lt;/a&gt; in San Francisco. The team engaged with the vibrant AI community, connected with other leaders for potential integrations, and revealed news about the new CKEditor AI suite of capabilities 👻.&lt;/p&gt;

&lt;p&gt;

&lt;iframe class="tweet-embed" id="tweet-1968337657546813612-747" src="https://platform.twitter.com/embed/Tweet.html?id=1968337657546813612"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1968337657546813612-747');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1968337657546813612&amp;amp;theme=dark"
  }





&lt;/p&gt;

&lt;p&gt;I wanted to summarize the conference from the eyes of a developer advocate who has worked in the field for decades and has put particular focus on AI in recent months. Here you go...&lt;/p&gt;

&lt;h2&gt;
  
  
  Conference rundown
&lt;/h2&gt;

&lt;p&gt;It was a busy two days filled with basically non-stop talking to people about CKEditor and &lt;a href="https://ckeditor.com/ckeditor-ai/?utm_campaign=ckeditor_aiconference&amp;amp;utm_source=dev_to_article_aiconference_wrapup" rel="noopener noreferrer"&gt;CKEditor AI (😅 ohh I spoiled it already)&lt;/a&gt;. The overall vibe was more on the business side: lots of CEOs, founders of AI startups, and business professionals. Developers? Probably less than 10% of attendees. Not the standard crowd for the developer advocate part of me, but very exciting for the AI enthusiast part.&lt;/p&gt;

&lt;p&gt;The venue itself was unique. It was an old shed at Pier 39 (Google says &lt;a href="https://maps.app.goo.gl/eYdGTkg5LVuiZLSW7" rel="noopener noreferrer"&gt;Pier 48 - Lot #39&lt;/a&gt;). My guess is it was originally a boat storage or maintenance shed. We arrived to set up our booth the evening before the event: swag arrived on time, the booth looked good, and the stage and the venue were still getting ready. Still partly looking like a shed.&lt;/p&gt;

&lt;p&gt;On the first day of the conference, we encountered a lot of excitement, but also a pinch of hesitance with AI advancing so quickly. Inside, the Pier was nice and shiny: almost unrecognizable from the evening before. The main corridor in the center included two stages on the sides, with the back lined with booths, and finishing with the main stage.&lt;/p&gt;

&lt;p&gt;The morning flew by so quickly that we barely had time to grab breakfast or coffee. Lunch wasn’t much different. We had to take turns just to grab a bite. And right after, I went to deliver my talk (more about that in the next section).&lt;/p&gt;

&lt;p&gt;Day two was quieter, but no less engaging. The slower pace meant more one-on-one conversations and deeper dives into what CKEditor AI can really do.&lt;/p&gt;

&lt;p&gt;

&lt;iframe class="tweet-embed" id="tweet-1968721785777451082-439" src="https://platform.twitter.com/embed/Tweet.html?id=1968721785777451082"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1968721785777451082-439');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1968721785777451082&amp;amp;theme=dark"
  }





&lt;/p&gt;

&lt;h2&gt;
  
  
  The talk — why we went there
&lt;/h2&gt;

&lt;p&gt;I gave a lightning talk during lunch and expected maybe 30 people casually eating. Instead, I ended up speaking to ~300 (my best guess from the photos). That was a surprise, but also a great opportunity.&lt;/p&gt;

&lt;p&gt;The talk focused on the problem of “Bring Your Own AI” chaos (78% of knowledge workers bring their own AI tools) and how CKEditor AI solves it by offering a frictionless, unified AI writing stack inside any application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Outline of the talk
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The Bring Your Own AI (BYOAI) problem: copy/paste friction, compliance risks, and content inconsistency&lt;/li&gt;
&lt;li&gt;What is CKEditor? 

&lt;ul&gt;
&lt;li&gt;Editor (customizable and framework-agnostic)&lt;/li&gt;
&lt;li&gt;Cloud services (including telemetry, logs, compliance, and on-prem or SaaS deployment)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ckeditor.com/ckeditor-ai/?utm_campaign=ckeditor_aiconference&amp;amp;utm_source=dev_to_article_aiconference_wrapup" rel="noopener noreferrer"&gt;&lt;strong&gt;🎉 CKEditor AI Early access announcement&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;The three AI surfaces:

&lt;ul&gt;
&lt;li&gt;AI Chat: An AI writing assistant directly next to your editor&lt;/li&gt;
&lt;li&gt;Quick AI Actions: Sentiment analysis, proofreading, translation, repetitive tasks - anything you use repeatably&lt;/li&gt;
&lt;li&gt;AI Content Review: Handles complex use cases, offering help for suggestion-heavy workflows and advanced AI tasks&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Real-world use case examples: Audits in regulated industries, marketing translations with disclaimers, and support ticket reply generation&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Below is the exclusive preview of the talk (after a bit of post-processing):&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/uic6IdZvnME"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;p&gt;&lt;a href="https://l.ead.me/ai-conference-ckeditor-ai-slides" rel="noopener noreferrer"&gt;🖼️ Slide deck 🔗&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to learn more, check out the &lt;a href="https://ckeditor.com/ckeditor-ai/?utm_campaign=ckeditor_aiconference&amp;amp;utm_source=dev_to_article_aiconference_wrapup" rel="noopener noreferrer"&gt;CKEditor AI Landing page&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>news</category>
      <category>software</category>
    </item>
    <item>
      <title>CKEditor 5 Pitfall: Don't Forget the Paragraph Plugin</title>
      <dc:creator>Ondřej Chrastina</dc:creator>
      <pubDate>Mon, 23 Jun 2025 10:51:07 +0000</pubDate>
      <link>https://dev.to/ckeditor/ckeditor-5-pitfall-dont-forget-the-paragraph-plugin-i91</link>
      <guid>https://dev.to/ckeditor/ckeditor-5-pitfall-dont-forget-the-paragraph-plugin-i91</guid>
      <description>&lt;p&gt;When you're adding &lt;strong&gt;CKEditor 5&lt;/strong&gt; to your platform, chances are you're starting simple—maybe testing in a sandbox project or integrating through the excellent &lt;a href="https://ckeditor.com/ckeditor-5/builder/" rel="noopener noreferrer"&gt;CKEditor Builder&lt;/a&gt;, or diving into the &lt;a href="https://ckeditor.com/docs/ckeditor5/latest/framework/tutorials/crash-course/editor.html" rel="noopener noreferrer"&gt;CKEditor Framework Crash Course&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In my case, I tried both approaches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=V02w3CK8KG4&amp;amp;list=PLKzl1AGxt2J0j2H3xUuFLGO-s_-f0K9eD" rel="noopener noreferrer"&gt;🧱 Using the CKEditor Builder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/PVOdv2Mw02I?feature=shared" rel="noopener noreferrer"&gt;⚙️ Following the CKEditor framework crash course&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Both are fantastic resources. However, there's one small but &lt;strong&gt;crucial&lt;/strong&gt; detail that’s easy to overlook:&lt;br&gt;
&lt;em&gt;💡 You need &lt;strong&gt;two plugins&lt;/strong&gt; to make even a minimal CKEditor 5 setup work:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Essentials&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;🚨 &lt;code&gt;Paragraph&lt;/code&gt; (yes, it's &lt;em&gt;not&lt;/em&gt; included in Essentials!)
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;ClassicEditor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;licenseKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GPL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;Essentials&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// * ✅ Essential&lt;/span&gt;
        &lt;span class="nx"&gt;Paragraph&lt;/span&gt; &lt;span class="c1"&gt;// 🚨 Paragraph 🚨 &lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Pitfall: Only Using Essentials
&lt;/h2&gt;

&lt;p&gt;It might seem like the following setup is enough:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Import the editor.&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;ClassicEditor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Essentials&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ckeditor5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Import the styles.&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ckeditor5/ckeditor5.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Get the HTML element with the ID of 'app'.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Instantiate the editor using the `create` method.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ClassicEditor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;licenseKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GPL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;Essentials&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The editor initializes, &lt;strong&gt;but nothing works&lt;/strong&gt;—no content, no cursor, and no error messages either! 😱&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Yes, the configuration on the image is slightly richer, but still behaves the same.&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F70u7zyfklvfa7w014gjq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F70u7zyfklvfa7w014gjq.png" alt="Creation of the CKEditor withouts the Paragraph plugin being used." width="605" height="915"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take a look at this case:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Are you missing something?”&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;Yes. Yes, you are!&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  YES, it is in the code docs
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;(alias) class Essentials&lt;/code&gt;&lt;br&gt;
&lt;code&gt;import Essentials&lt;/code&gt;&lt;br&gt;
A plugin including all essential editing features. It represents a set of features that enables similar functionalities to a  element.&lt;br&gt;
It includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:ui/editorui/accessibilityhelp/accessibilityhelp~AccessibilityHelp&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:clipboard/clipboard~Clipboard&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:enter/enter~Enter&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:select-all/selectall~SelectAll&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:enter/shiftenter~ShiftEnter&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:typing/typing~Typing&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:undo/undo~Undo&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This plugin set does not define any block-level containers (such as &lt;strong&gt;:paragraph/paragraph~Paragraph&lt;/strong&gt;). If your editor is supposed to handle block content, make sure to include it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Fix: Add the Paragraph Plugin 🎉
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Import the editor.&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;ClassicEditor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Essentials&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Paragraph&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ckeditor5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Import the styles.&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ckeditor5/ckeditor5.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Get the HTML element with the ID of 'app'.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Instantiate the editor using the `create` method.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ClassicEditor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;licenseKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GPL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;Essentials&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;Paragraph&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And voilà:&lt;br&gt;
“Much better!”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6pynght6k45tqi5lymte.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6pynght6k45tqi5lymte.png" alt="Showcase of the working CKEditor with thew Paragraph plugin being defined." width="605" height="915"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🧠 Key Takeaway
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Essentials&lt;/code&gt; plugin ≠ has everything you need for editing.&lt;/li&gt;
&lt;li&gt;For a working CKEditor instance, especially one with block content, &lt;strong&gt;add the Paragraph plugin&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Always double-check the docs—even for plugins that sound... well, essential.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Keep this in mind as you build your rich text editing experiences! 💡&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>devrel</category>
      <category>ckeditor</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How I Turned Kubernetes Into a Fun, Kid-Friendly YouTube Short</title>
      <dc:creator>Ondřej Chrastina</dc:creator>
      <pubDate>Mon, 17 Feb 2025 17:37:27 +0000</pubDate>
      <link>https://dev.to/simply007/how-i-turned-kubernetes-into-a-fun-kid-friendly-youtube-short-268n</link>
      <guid>https://dev.to/simply007/how-i-turned-kubernetes-into-a-fun-kid-friendly-youtube-short-268n</guid>
      <description>&lt;p&gt;Recently, I set out on a mission to simplify one of tech’s more complex concepts—Kubernetes—so that even a five-year-old could grasp it. Imagine having a huge box of LEGO bricks and a magical helper that organizes them into perfect structures every time. That’s Kubernetes in a nutshell!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Crafting the Script
&lt;/h2&gt;

&lt;p&gt;I started by using ChatGPT to generate a script along with detailed scene descriptions. In just minutes, I had a solid foundation that broke down Kubernetes into easy-to-understand, playful ideas. This step was all about making sure the content was accessible and engaging.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Creating the Visuals
&lt;/h2&gt;

&lt;p&gt;After a few rounds of tweaks, I managed to produce some really appealing images for each scene—all while staying within the free image usage limits. These visuals helped turn abstract concepts into something tangible and fun, much like turning LEGO bricks into a masterpiece.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Bringing It to Life with Audio
&lt;/h2&gt;

&lt;p&gt;Next up, I generated the audio using ElevenLabs. I opted for a reel/short video format since it allowed me to find free resources more easily compared to creating a full comic (which was my initial idea). The result was clear, lively narration that tied everything together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Assembling the Video
&lt;/h2&gt;

&lt;p&gt;Finally, I combined the script, images, and audio using Canva. The final video was a seamless blend of creativity and technology, culminating in an engaging YouTube upload that makes learning about Kubernetes a delightful experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;This project is a testament to how modern creative tools can transform complex technical subjects into something both fun and approachable. Whether you're a tech enthusiast or just looking for a simpler way to learn, I hope this video inspires you to see technology from a new, playful perspective. Enjoy the video, and happy learning!&lt;/p&gt;

&lt;p&gt;🎉 And this is the result 🎉&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtube.com/shorts/N85_wB-kkCs?si=BOi0qkA40momwTFg" rel="noopener noreferrer"&gt;https://youtube.com/shorts/N85_wB-kkCs?si=BOi0qkA40momwTFg&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>ai</category>
      <category>promotion</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Build and Deploy a Next.js Blog with Kentico Kontent and Vercel</title>
      <dc:creator>Ondřej Chrastina</dc:creator>
      <pubDate>Fri, 11 Jun 2021 09:23:51 +0000</pubDate>
      <link>https://dev.to/kontent_ai/build-and-deploy-a-next-js-blog-with-kentico-kontent-and-vercel-5cp4</link>
      <guid>https://dev.to/kontent_ai/build-and-deploy-a-next-js-blog-with-kentico-kontent-and-vercel-5cp4</guid>
      <description>&lt;p&gt;&lt;a href="https://kontent.ai"&gt;Kentico Kontent&lt;/a&gt; delivers all the benefits of a headless CMS while empowering your marketing team to manage the experience across your digital channels.&lt;/p&gt;

&lt;p&gt;This guide showcases how to use Kontent with Next.js &lt;a href="https://nextjs.org/docs/basic-features/pages"&gt;Static Generation&lt;/a&gt; to generate static pages from your Kontent data, delivering a lightning-fast experience for your users.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Following text is an extended explanation of the &lt;a href="https://github.com/vercel/next.js/tree/canary/examples/cms-kontent#readme"&gt;Statically generated blog using Next.js and Kontent&lt;/a&gt; repository.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 1: Creating a Kontent + Next.js Project
&lt;/h2&gt;

&lt;p&gt;You can &lt;a href="https://next-blog-kontent.vercel.app/"&gt;view a working demo&lt;/a&gt;, the app you will create is shown in the screenshot below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QKd7iw1r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ggiq905brjnoz8fqjxi5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QKd7iw1r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ggiq905brjnoz8fqjxi5.png" alt="Example screenshot" width="880" height="792"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Next.js + Kontent demo app.
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Register Kontent project
&lt;/h3&gt;

&lt;p&gt;To get started, &lt;a href="https://app.kontent.ai/sign-up"&gt;create an account on Kontent.ai&lt;/a&gt;. After signing up, &lt;a href="https://docs.kontent.ai/tutorials/set-up-kontent/projects/manage-projects#a-creating-projects"&gt;create an empty project&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the content models and fill them with data
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://docs.kontent.ai/tutorials/set-up-kontent/content-modeling/what-is-content-modeling"&gt;content model&lt;/a&gt; defines the data structures of your application/websites. The structures are flexible and you can tailor them to your needs.&lt;/p&gt;

&lt;p&gt;For this example, you need to create a content model that defines an &lt;code&gt;author&lt;/code&gt; and a &lt;code&gt;post&lt;/code&gt; content type.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can &lt;a href="https://github.com/vercel/next.js/blob/canary/examples/cms-kontent/README.md#step-21-optionally-create-the-content-models-manually"&gt;create the content model and fill it with data manually&lt;/a&gt; to familiarize yourself with the Kontent user interface.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To import the content models with their data automatically, follow the next steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enter &lt;a href="https://app.kontent.ai"&gt;Kontent application&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Go to "Project Settings", select API keys&lt;/li&gt;
&lt;li&gt;Activate Management API&lt;/li&gt;
&lt;li&gt;Copy &lt;code&gt;Project ID&lt;/code&gt; and &lt;code&gt;Management API&lt;/code&gt; key&lt;/li&gt;
&lt;li&gt;Install &lt;a href="https://github.com/Kentico/kontent-backup-manager-js"&gt;Kontent Backup Manager&lt;/a&gt; and import data to newly created project from &lt;a href="https://github.com/vercel/next.js/raw/canary/examples/cms-kontent/kontent-backup.zip"&gt;kontent-backup.zip&lt;/a&gt; file (place appropriate values for &lt;code&gt;apiKey&lt;/code&gt; and &lt;code&gt;projectId&lt;/code&gt; arguments):
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i -g @kentico/kontent-backup-manager
kbm --action=restore --apiKey=&amp;lt;Management API key&amp;gt; --projectId=&amp;lt;Project ID&amp;gt; --zipFilename=kontent-backup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;💡 Alternatively, you can use the &lt;a href="https://kentico.github.io/kontent-template-manager/import"&gt;Template Manager UI&lt;/a&gt; for importing the content.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Go to your Kontent project and publish all the imported items.
&amp;gt; You could deactivate the Management API, it is not necessary anymore.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Application initialization
&lt;/h3&gt;

&lt;p&gt;Initialize the application locally with following command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm init next-app --example cms-kontent nextjs-kontent-app &amp;amp;&amp;amp; cd nextjs-kontent-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Initializing a Next.js + Kontent app and entering the project directory.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Step 2: Set up Environment Variables
&lt;/h2&gt;

&lt;p&gt;Copy the &lt;code&gt;.env.local.example&lt;/code&gt; file in this directory to &lt;code&gt;.env.local&lt;/code&gt; (which will be ignored by Git):&lt;/p&gt;



&lt;p&gt;Then set each variable on &lt;code&gt;.env.local&lt;/code&gt; using the keys &lt;code&gt;Project settings&lt;/code&gt; &amp;gt; &lt;code&gt;API keys&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;KONTENT_PROJECT_ID&lt;/code&gt; - Should be the Project ID in &lt;code&gt;Project settings&lt;/code&gt; &amp;gt; &lt;code&gt;API keys&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;KONTENT_PREVIEW_API_KEY&lt;/code&gt; - One of the Preview API keys in &lt;code&gt;Project settings&lt;/code&gt; &amp;gt; &lt;code&gt;API keys&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;KONTENT_PREVIEW_SECRET&lt;/code&gt; - Can be any random string (but avoid spaces), like &lt;code&gt;MY_SECRET&lt;/code&gt; - this is used for &lt;a href="https://nextjs.org/docs/advanced-features/preview-mode"&gt;Preview Mode&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After installing the required dependencies, you are now able to run and develop your Next.js + Kontent app locally.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn
yarn dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 3: Understanding the Code
&lt;/h2&gt;

&lt;p&gt;To understand how the app works, there are three main areas to explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Page Setup&lt;/li&gt;
&lt;li&gt;Retrieving Content&lt;/li&gt;
&lt;li&gt;Image Optimization&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Page Setup
&lt;/h3&gt;

&lt;p&gt;Each page displays a single blog post with the dynamic Object &lt;code&gt;slug&lt;/code&gt; and two latest blog posts teasers from Kontent:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ErrorPage&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Container&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../components/container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PostBody&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../components/post-body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MoreStories&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../components/more-stories&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Header&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../components/header&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PostHeader&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../components/post-header&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;SectionSeparator&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../components/section-separator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Layout&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../components/layout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;getAllPostSlugs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;getPostBySlug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;getMorePostsForSlug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../lib/api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PostTitle&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../components/post-title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Head&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/head&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CMS_NAME&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../lib/constants&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;morePosts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;preview&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isFallback&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ErrorPage&lt;/span&gt; &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Layout&lt;/span&gt; &lt;span class="na"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;preview&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isFallback&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PostTitle&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading…&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;PostTitle&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;article&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"mb-32"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; | Next.js Blog Example with &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;CMS_NAME&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coverImage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PostHeader&lt;/span&gt;
                &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="na"&gt;coverImage&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coverImage&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PostBody&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;article&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SectionSeparator&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;morePosts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MoreStories&lt;/span&gt; &lt;span class="na"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;morePosts&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getStaticProps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;preview&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;getPostBySlug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;getMorePostsForSlug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;morePosts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="nx"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getStaticPaths&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;slugs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;getAllPostSlugs&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;slug&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;slugs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;The pages/posts/[slug].js file for your Next.js +&lt;br&gt;
  Kontent app.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Retrieving Content
&lt;/h3&gt;

&lt;p&gt;Kontent data is retrieved in the &lt;code&gt;lib/api.js&lt;/code&gt; file making requests to the Kontent Delivery API using the &lt;a href="https://www.npmjs.com/package/@kentico/kontent-delivery"&gt;Kontent Delivery SDK&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DeliveryClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@kentico/kontent-delivery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../package.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sourceTrackingHeaderName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X-KC-SOURCE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;DeliveryClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;KONTENT_PROJECT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;previewApiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;KONTENT_PREVIEW_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;globalHeaders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_queryConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sourceTrackingHeaderName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`@vercel/next.js/example/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;parseAuthor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;picture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;picture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;parsePost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;post.title.value,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;excerpt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;excerpt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;coverImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cover_image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;parseAuthor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getAllPostSlugs&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;postsResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;elementsParameter&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;slug&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toPromise&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;postsResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getMorePostsForSlug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queryConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;usePreviewMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderByDescending&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;elements.date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;withParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;elements.slug[neq]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;limitParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toPromise&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;parsePost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getPostBySlug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queryConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;usePreviewMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;equalsFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;elements.slug&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toPromise&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getFirstItem&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;parsePost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getAllPosts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queryConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;usePreviewMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderByDescending&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;elements.date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toPromise&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;postsResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;postsResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;parsePost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;The lib/api.js file for your Next.js + Kontent app.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Image Transformation possibilities
&lt;/h2&gt;

&lt;p&gt;If you want to optimize the speed of your site, it is possible to use &lt;a href="https://docs.kontent.ai/reference/image-transformation"&gt;Kontent Image Transformation API&lt;/a&gt; to transform retrieved images and reduce the download time for images. This could be applied to the blog post's cover image or the author's profile picture. The easiest way is to use the &lt;a href="https://github.com/Kentico/kontent-delivery-sdk-js/blob/master/DOCS.md#image-transformation"&gt;Image transformation support in Kontent Delivery SDK&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cn&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;classnames&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ImageUrlBuilder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ImageCompressionEnum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ImageFormatEnum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@kentico/kontent-delivery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;CoverImage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transformedSrc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ImageUrlBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;withCompression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ImageCompressionEnum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Lossless&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;withAutomaticFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ImageFormatEnum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Webp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;withQuality&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getUrl&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
      &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;transformedSrc&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`Cover Image for &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shadow-small&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hover:shadow-medium transition-shadow duration-200&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"-mx-5 sm:mx-0"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`/posts/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/posts/[slug]"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;aria-label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;image&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Possible modification of &lt;code&gt;components/cover-image.js&lt;/code&gt; &lt;br&gt;
  component using Image Transformation API to get images in &lt;br&gt;
    &lt;a href="https://developers.google.com/speed/webp"&gt;modern WebP format&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Step 4: Using Preview Mode
&lt;/h2&gt;

&lt;p&gt;To add the ability to preview content from your Kontent project using &lt;a href="https://docs.kontent.ai/reference/delivery-api#section/Introduction"&gt;Preview Delivery API&lt;/a&gt;, open your Kontent project, go to &lt;strong&gt;Project Settings &amp;gt; Preview URLs&lt;/strong&gt;, and set a new preview URL for the &lt;code&gt;Post&lt;/code&gt; content type to:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:3000/api/preview?secret=&amp;lt;KONTENT_PREVIEW_SECRET&amp;gt;&amp;amp;slug={URLslug}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Replace &lt;code&gt;&amp;lt;KONTENT_PREVIEW_SECRET&amp;gt;&lt;/code&gt; with its respective value in &lt;code&gt;.env.local&lt;/code&gt;:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CVFtDNKU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cotjcv6co14jf3sll4me.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CVFtDNKU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cotjcv6co14jf3sll4me.png" alt="The Preview URL setup for Post content type." width="880" height="260"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once saved, go to one of the posts you've created and:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new version of the post&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Update the title&lt;/strong&gt;. For example, you can add &lt;code&gt;[Draft]&lt;/code&gt; in front of the title.
&amp;gt; Mind the title also regenerates the URL slug, if you want to change any other field that does not influence the URL slug, feel free to do so.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not&lt;/strong&gt; publish it. By doing this, the post will be in the draft workflow step.&lt;/li&gt;
&lt;li&gt;On the menu, you will see the &lt;strong&gt;Preview&lt;/strong&gt; button. Click on it!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0dsHjuEf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n3pdnins9k1ycsct848w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0dsHjuEf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n3pdnins9k1ycsct848w.png" alt="The new Preview button in post detail." width="880" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will now be able to see the updated title. To exit preview mode, you can click on &lt;strong&gt;Click here to exit preview mode&lt;/strong&gt; at the top of the page.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 5: Deploying Your App with Vercel
&lt;/h2&gt;

&lt;p&gt;To deploy your Next.js + Kontent site with a Vercel for Git Integration, make sure it has been pushed to a Git repository.&lt;/p&gt;

&lt;p&gt;During the import process, you will need to add the following environment variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;KONTENT_PROJECT_ID&lt;/li&gt;
&lt;li&gt;KONTENT_PREVIEW_API_KEY&lt;/li&gt;
&lt;li&gt;KONTENT_PREVIEW_SECRET&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Import the project into Vercel using your Git Integration of choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://vercel.com/import/git?env=KONTENT_PROJECT_ID,KONTENT_PREVIEW_API_KEY,KONTENT_PREVIEW_SECRET"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vercel.com/import/git?env=KONTENT_PROJECT_ID,KONTENT_PREVIEW_API_KEY,KONTENT_PREVIEW_SECRET"&gt;GitLab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vercel.com/import/git?env=KONTENT_PROJECT_ID,KONTENT_PREVIEW_API_KEY,KONTENT_PREVIEW_SECRET"&gt;Bitbucket&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After your project has been imported, all subsequent pushes to branches will generate Preview Deployments, and all changes made to the Production Branch (commonly "main") will result in a Production Deployment.&lt;/p&gt;

&lt;p&gt;Once deployed, you will get a URL to see your site live, such as the following: &lt;a href="https://next-blog-kontent.vercel.app/"&gt;https://next-blog-kontent.vercel.app/&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;Set up a Next.js + Kontent site with a few clicks using the Deploy button, and create a Git repository for it in the process for automatic deployments for your updates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://vercel.com/import/git?c=1&amp;amp;s=https://github.com/vercel/next.js/tree/canary/examples/cms-kontent&amp;amp;env=KONTENT_PROJECT_ID,KONTENT_PREVIEW_API_KEY,KONTENT_PREVIEW_SECRET&amp;amp;envDescription=Required%20to%20connect%20the%20app%20with%20Kontent.&amp;amp;envLink=https://github.com/vercel/next.js/tree/canary/examples/cms-kontent#step-3-set-up-environment-variables"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--45UgOyrE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://vercel.com/button" alt="Deploy with Vercel" width="92" height="32"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;blockquote&gt;
&lt;p&gt;If you want to explore a more complex example for Kentico Kontent and Next.js, check out this Corporate Starter.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Kentico"&gt;
        Kentico
      &lt;/a&gt; / &lt;a href="https://github.com/Kentico/kontent-starter-corporate-next-js"&gt;
        kontent-starter-corporate-next-js
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Next.js corporate starter site using Kentico Kontent as a data source.
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;br&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>nextjs</category>
      <category>git</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Get Kontent Project ID from the Management API key</title>
      <dc:creator>Ondřej Chrastina</dc:creator>
      <pubDate>Mon, 22 Mar 2021 14:00:03 +0000</pubDate>
      <link>https://dev.to/kontent_ai/get-kontent-project-id-from-the-management-api-key-71a</link>
      <guid>https://dev.to/kontent_ai/get-kontent-project-id-from-the-management-api-key-71a</guid>
      <description>&lt;p&gt;&lt;em&gt;It is possible to parse out Kontent Project ID out of the &lt;a href="https://docs.kontent.ai/reference/management-api-v2#tag/API-key-scope-and-validity" rel="noopener noreferrer"&gt;Management API Key&lt;/a&gt;. That means no more necessity to ask for two keys for your Kontent tools.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Do you develop any Kontent tool using &lt;a href="https://docs.kontent.ai/reference/management-api-v2#tag/API-key-scope-and-validity" rel="noopener noreferrer"&gt;Management API&lt;/a&gt; and still ask for both - Project ID and Management API key? Following lines will help you to improve your UX as well as cleanout your code.&lt;/p&gt;

&lt;p&gt;The management API key is just a &lt;a href="https://tools.ietf.org/html/rfc7519" rel="noopener noreferrer"&gt;JWT token&lt;/a&gt; containing the payload (in between header with signature). So you could decode it i.e. by using &lt;a href="https://jwt.io/" rel="noopener noreferrer"&gt;JWT.io&lt;/a&gt;, And as a payload, you could see this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"jti"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"b6a9ee86bfdc41c89f20048c3baaba04"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"iat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1612535158"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"exp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1958135158"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"project_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"06c2b8951700013e5f3160283aff1100"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ver"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"uid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"usr_0vMrpCH2TkOK5oK3y3bKNS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"aud"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"manage.kenticocloud.com"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;project_id&lt;/code&gt; could be used to identify the project with one modification. It is necessary to add dashes on appropriate places to respect the &lt;a href="http://guid.one/guid" rel="noopener noreferrer"&gt;GUID format&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;To do all of that, the code would end up looking like that (or any other language alternative) - or you just use a library like &lt;a href="https://github.com/auth0/jwt-decode" rel="noopener noreferrer"&gt;jwt-decode&lt;/a&gt;. But it is always good to know what they do.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;managementApiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ew0KICAiYWxnIjogIkhTMjU2IiwNCiAgInR5cCI6ICJKV1QiDQp9.ew0KICAianRpIjogImI2YTllZTg2YmZkYzQxYzg5ZjIwMDQ4YzNiYWFiYTA0IiwNCiAgImlhdCI6ICIxNjEyNTM1MTU4IiwNCiAgImV4cCI6ICIxOTU4MTM1MTU4IiwNCiAgInByb2plY3RfaWQiOiAiMDZjMmI4OTUxNzAwMDEzZTVmMzE2MDI4M2FmZjExMDAiLA0KICAidmVyIjogIjIuMS4wIiwNCiAgInVpZCI6ICJ1c3JfMHZNcnBDSDJUa09LNW9LM3kzYktOUyIsDQogICJhdWQiOiAibWFuYWdlLmtlbnRpY29jbG91ZC5jb20iDQp9.aEqGajw7e9m13lnID0z9PBCL0MytqYlvoYg_rwPfEJo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payloadBase64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;managementApiKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payloadBase64Cleared&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;payloadBase64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/-/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/_/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jsonPayload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;decodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;atob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payloadBase64Cleared&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;%&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;00&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charCodeAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payloadObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jsonPayload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;projectIdWithoutDashes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;payloadObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;projectId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
    &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;projectIdWithoutDashes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;-\
&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;projectIdWithoutDashes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;-\
&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;projectIdWithoutDashes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;-\
&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;projectIdWithoutDashes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;-\
&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;projectIdWithoutDashes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;If you want to play with it - &lt;a href="https://codepen.io/simply007-the-sasster/pen/xxRvNoX" rel="noopener noreferrer"&gt;check out this Codepen&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;...and of course, I invalidated the showcased API key 🤞&lt;/em&gt;&lt;/p&gt;

</description>
      <category>jwt</category>
      <category>api</category>
      <category>decode</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Jamstack on .NET: From zero to hero with Statiq and Kontent</title>
      <dc:creator>Ondřej Chrastina</dc:creator>
      <pubDate>Mon, 30 Nov 2020 11:21:13 +0000</pubDate>
      <link>https://dev.to/kontent_ai/jamstack-on-net-from-zero-to-hero-with-statiq-and-kontent-p4m</link>
      <guid>https://dev.to/kontent_ai/jamstack-on-net-from-zero-to-hero-with-statiq-and-kontent-p4m</guid>
      <description>&lt;p&gt;&lt;strong&gt;Are you interested in Jamstack, but sad you can't practice it with .NET? The times have changed, and .NET developers are now able to build Jamstack apps using the new static site generator Statiq. This article walks you through the setup of a ready-to-use boilerplate! If you are new to Jamstack on .NET, follow the steps below to wrap your head around the basics. If you know the drill, skip that part and use the boilerplate.&lt;/strong&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kontent-ai" rel="noopener noreferrer"&gt;
        kontent-ai
      &lt;/a&gt; / &lt;a href="https://github.com/kontent-ai/boilerplate-statiq-net" rel="noopener noreferrer"&gt;
        boilerplate-statiq-net
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Boilerplate utilizing Statiq and Kontent.ai to provide a starting point in the Jamstack world for .NET developers.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Statiq boilerplate for Kontent.ai&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/kontent-ai/boilerplate-statiq-net/workflows/Publish/badge.svg"&gt;&lt;img src="https://github.com/kontent-ai/boilerplate-statiq-net/workflows/Publish/badge.svg" alt="Build and publish"&gt;&lt;/a&gt;
&lt;a href="https://kontent-ai.github.io/boilerplate-statiq-net" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1d1d8650db9796b696756e451a4942b3ec2676b79d3851e80beae16165d11af5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6976652d44454d4f2d627269676874677265656e2e7376673f6c6f676f3d676974687562266c6f676f436f6c6f723d7768697465" alt="Live Demo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Boilerplate utilizing &lt;a href="https://statiq.dev/" rel="nofollow noopener noreferrer"&gt;Statiq&lt;/a&gt; and &lt;a href="https://kontent.ai" rel="nofollow noopener noreferrer"&gt;Kontent.ai&lt;/a&gt; to provide a starting point in the Jamstack world for .NET developers.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/kontent-ai/boilerplate-statiq-net./screenshot.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fkontent-ai%2Fboilerplate-statiq-net.%2Fscreenshot.png" alt="Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Get started&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Requirements&lt;/h3&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dotnet.microsoft.com/download" rel="nofollow noopener noreferrer"&gt;.NET 6&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Clone the codebase&lt;/h3&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Click the &lt;a href="https://github.com/petrsvihlik/statiq-starter-kontent-lumen/generate" rel="noopener noreferrer"&gt;"Use this template"&lt;/a&gt; button to &lt;a href="https://help.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-from-a-template" rel="noopener noreferrer"&gt;create your own repository from this template&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Running locally&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;dotnet run -- preview&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;🎊🎉 &lt;strong&gt;Visit &lt;a href="http://localhost:5080" rel="nofollow noopener noreferrer"&gt;http://localhost:5080&lt;/a&gt; and start exploring the code base!&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;By default, the content is loaded from a shared Kontent.ai project. If you want to use your own clone of the project so that you can customize it and experiment with Kontent, continue to the next section.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Create a content source&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Application itself is configured to use shared alvawys avalable Kontent-ai project.&lt;/p&gt;
&lt;p&gt;If you want to generate the clone of the project in order to be able to edit the content, use &lt;a href="https://app.kontent.ai/sample-site-configuration" rel="nofollow noopener noreferrer"&gt;Sample site generator&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use "CREATE A NEW SAMPLE PROJECT" for generating the project.&lt;/li&gt;
&lt;li&gt;Access the project listing on…&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kontent-ai/boilerplate-statiq-net" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Technologies
&lt;/h2&gt;

&lt;p&gt;Let's briefly introduce &lt;a href="https://jamstack.org" rel="noopener noreferrer"&gt;Jamstack&lt;/a&gt;. It is a web architecture based on the pre-rendered assets (HTML files, images, CSS, etc.) that are generated at the build time based on templates and data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fteslw1iuy256t4fa8fvc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fteslw1iuy256t4fa8fvc.png" alt="Technologies puzzle" width="640" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let's jump right to the available technologies. First is Statiq, a generation platform providing the .NET based &lt;a href="https://statiq.dev/framework" rel="noopener noreferrer"&gt;Statiq.Framework&lt;/a&gt; for creating a static site generator infrastructure and a set of modules called &lt;a href="https://statiq.dev/web" rel="noopener noreferrer"&gt;Statiq.Web&lt;/a&gt; that will make the initial configuration of the framework easier.&lt;/p&gt;

&lt;p&gt;The next pieces of the puzzle are the &lt;strong&gt;templates and data storage&lt;/strong&gt;. I have chosen &lt;strong&gt;Razor as a template engine&lt;/strong&gt; since it is the most known one in the .NET world. &lt;strong&gt;Data&lt;/strong&gt; will be provided by a &lt;strong&gt;headless CMS—Kentico Kontent&lt;/strong&gt;. It provides more flexibility and collaboration features in comparison with markdown files, and it has a Statiq module out of the box.&lt;/p&gt;

&lt;p&gt;The last piece is to get all the assets and &lt;a href="https://statiq.dev/web/deployment/netlify" rel="noopener noreferrer"&gt;deploy them to Netlify.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's start
&lt;/h2&gt;

&lt;p&gt;The whole boilerplate creation is split into three parts—an application skeleton, a content source, and a connector that allows Statiq to generate pages.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Before you do anything else,&lt;/em&gt; &lt;a href="https://dotnet.microsoft.com/download" rel="noopener noreferrer"&gt;&lt;em&gt;download and install a .NET 5&lt;/em&gt;&lt;/a&gt; &lt;em&gt;if you haven't already.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Prepare the application
&lt;/h3&gt;

&lt;p&gt;First, use &lt;a href="https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-new" rel="noopener noreferrer"&gt;dotnet CLI&lt;/a&gt; to create a new console application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;FromZeroToHero&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then, navigate to the application folder and install a &lt;code&gt;Statiq.Web&lt;/code&gt; Nuget package (which will also download &lt;code&gt;Statiq.Framework&lt;/code&gt; as a dependency).&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;FromZeroToHero&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Statiq.Web&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;1.0.0-&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And then configure &lt;code&gt;Statiq.Framework&lt;/code&gt; in &lt;code&gt;Program.cs&lt;/code&gt; to use the default configuration of the &lt;code&gt;Statiq.Web&lt;/code&gt; modules.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Statiq.App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Statiq.Web&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;FromZeroToHero&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Bootstrapper&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Factory&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateWeb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;💡 &lt;em&gt;At this point, if you run&lt;/em&gt; &lt;code&gt;dotnet run -- preview&lt;/code&gt; &lt;em&gt;, you can browse your empty site at&lt;/em&gt; &lt;code&gt;http://localhost:5080&lt;/code&gt; 💡&lt;/p&gt;
&lt;h3&gt;
  
  
  Prepare content
&lt;/h3&gt;

&lt;p&gt;As the title mentioned, the boilerplate is about going "from zero to hero". This means creating a "Hero" content model that consists of a headline, summary, and CTA. Plus creating one content item based on that model. We'll do all that in a headless CMS &lt;a href="//hrrps://kontent.ai"&gt;Kentico Kontent&lt;/a&gt; as it already features Statiq integration.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;First, &lt;a href="https://app.kontent.ai/sign-up?utm_source=nextjs_docs_example&amp;amp;utm_medium=devrel&amp;amp;utm_campaign=extended_trial" rel="noopener noreferrer"&gt;create an account at Kontent.ai&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;The link above will provide you with a 90-day trial. Once you finish the trial, or even during the trial period, you can switch to the&lt;/em&gt; &lt;a href="https://kontent.ai/developer-plan" rel="noopener noreferrer"&gt;&lt;em&gt;Developer plan&lt;/em&gt;&lt;/a&gt; &lt;em&gt;, which is&lt;/em&gt; &lt;em&gt;free of charge&lt;/em&gt; &lt;em&gt;and lets you run small projects with a $0 budget.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After signing up, &lt;a href="https://docs.kontent.ai/tutorials/set-up-kontent/projects/manage-projects#a-creating-projects" rel="noopener noreferrer"&gt;create an empty project&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;From your Kontent project, go to &lt;em&gt;Content models&lt;/em&gt; and add a new Content type called "Hero" with these text fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Headline&lt;/li&gt;
&lt;li&gt;Summary&lt;/li&gt;
&lt;li&gt;CTA label&lt;/li&gt;
&lt;li&gt;CTA URL&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Faihx7797ess1e36jrtqj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Faihx7797ess1e36jrtqj.png" alt="Hero model" width="800" height="709"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Go to &lt;em&gt;Content &amp;amp; Assets&lt;/em&gt; section in your project and click &lt;em&gt;Create new&lt;/em&gt; on the &lt;em&gt;Content_tab and select _Hero&lt;/em&gt; content type and fill the elements&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Content Item Name:&lt;/em&gt; Hero&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Headline:&lt;/em&gt; From zero to hero with Statiq and Kontent&lt;/li&gt;
&lt;li&gt;_Summary:_How to start with the .NET Jamstack app utilizing Statiq as a Static generation platform and Kentico Kontent as a data source.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;CTA label:&lt;/em&gt; Explore&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;CTA URL:&lt;/em&gt; &lt;a href="https://github.com/Kentico/kontent-boilerplate-statiq-net" rel="noopener noreferrer"&gt;https://github.com/Kentico/kontent-boilerplate-statiq-net&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Publish the changes&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa61ilshcqgylk7tm353b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa61ilshcqgylk7tm353b.png" alt="Hero item" width="800" height="573"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Connect content and the site
&lt;/h3&gt;

&lt;p&gt;Now let's load the content from the headless CMS using &lt;a href="https://www.nuget.org/packages/Kontent.Statiq" rel="noopener noreferrer"&gt;Kontent.Statiq&lt;/a&gt; module and render it with the Razor engine.&lt;/p&gt;

&lt;p&gt;First, install Kontent.Statiq module:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Kontent.Statiq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;1.0.0-&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Copy the Project ID from the Kontent application.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enter &lt;a href="https://app.kontent.ai/" rel="noopener noreferrer"&gt;Kontent application&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Go to "Project Settings" and select "API keys"&lt;/li&gt;
&lt;li&gt;Copy "Project ID"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fibskvxxmym5nybclgbxn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fibskvxxmym5nybclgbxn.png" alt="Prikect ID selection" width="697" height="493"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then install the &lt;a href="https://www.nuget.org/packages/Kentico.Kontent.ModelGenerator" rel="noopener noreferrer"&gt;Kontent Model Generator for .NET&lt;/a&gt; and generate our Hero model.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tool-manifest&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Kentico.Kontent.ModelGenerator&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;KontentModelGenerator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--projectid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;projectid&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FromZeroToHero.Models"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--outputdir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Models"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--generatepartials&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--structuredmodel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;em&gt;For more specific information about the model generator configuration,&lt;/em&gt; &lt;a href="https://github.com/Kentico/kontent-generators-net#readme" rel="noopener noreferrer"&gt;&lt;em&gt;follow the generator's Readme&lt;/em&gt;&lt;/a&gt; &lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After generation, you will end up with three files &lt;code&gt;Models/Hero.Generated.cs&lt;/code&gt;, which is a POCO model class, then &lt;code&gt;Models/Hero.cs&lt;/code&gt; that allows extending the model class, and the last one is &lt;code&gt;Models/CustomTypeProviders.cs&lt;/code&gt; that will be used to provide model mapping information.&lt;/p&gt;

&lt;p&gt;The next step is to initialize the Kontent Delivery SDK client for dependency injection. Extend &lt;code&gt;Program.cs&lt;/code&gt; file with &lt;code&gt;ConfigureServices&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;FromZeroToHero.Models&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Kentico.Kontent.Delivery.Abstractions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Kentico.Kontent.Delivery.Extensions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.DependencyInjection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Statiq.App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Statiq.Common&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Statiq.Web&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;FromZeroToHero&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Bootstrapper&lt;/span&gt;
              &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Factory&lt;/span&gt;
              &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateWeb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
              &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConfigureServices&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="c1"&gt;// Add the type provider&lt;/span&gt;
                  &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ITypeProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CustomTypeProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
                  &lt;span class="c1"&gt;// Configure Delivery SDK&lt;/span&gt;
                  &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDeliveryClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
                      &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithProjectId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;projectid&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseProductionApi&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
              &lt;span class="p"&gt;})&lt;/span&gt;
              &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;All of your assets and templates should be placed in the &lt;code&gt;/input&lt;/code&gt; folder. Create a view file &lt;code&gt;_Hero.cshtml&lt;/code&gt; in the &lt;code&gt;/input&lt;/code&gt; folder then and use the generated &lt;code&gt;FromZeroToHero.Models.Hero&lt;/code&gt; class as a model for the template.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;@model FromZeroToHero.Models.Hero;

  &lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;@Model.Headline&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;@Model.Headline&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
      @Model.Summary
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"@Model.CtaUrl"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@Model.CtaLabel&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And finally,  to connect the configured client to load the data to the model and pass them to the Razor engine, we will define a new &lt;a href="https://statiq.dev/framework/pipelines" rel="noopener noreferrer"&gt;Statiq Pipeline&lt;/a&gt;. The pipeline is like a Controller from MVC. Create a new file in &lt;code&gt;Pipelines/HeroPipeline.cs&lt;/code&gt;. By inheriting from &lt;code&gt;Statiq.Core.Pipeline&lt;/code&gt;, Statiq automatically includes your pipeline in the generation process.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;FromZeroToHero.Models&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Kentico.Kontent.Delivery.Abstractions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Kentico.Kontent.Delivery.Urls.QueryParameters&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Kentico.Kontent.Delivery.Urls.QueryParameters.Filters&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Kontent.Statiq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Statiq.Common&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Statiq.Core&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Statiq.Razor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;FromZeroToHero&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// &amp;lt;see href="https://statiq.dev/framework/pipelines"&amp;gt;Pipelines documentation&amp;lt;/see&amp;gt;&lt;/span&gt;
      &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HeroPipeline&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Pipeline&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;HeroPipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IDeliveryClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="n"&gt;ProcessModules&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ModuleList&lt;/span&gt;
              &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="c1"&gt;// Load the "Hero" item and transfer it into IDocument.&lt;/span&gt;
                  &lt;span class="c1"&gt;// &amp;lt;see href="https://github.com/alanta/Kontent.Statiq"&amp;gt;Kontent.Statiq&amp;lt;/see&amp;gt;&lt;/span&gt;
                  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Kontent&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Hero&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                          &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;EqualsFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"system.codename"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"hero"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                          &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;LimitParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                      &lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="c1"&gt;// Load Razor template to IDocument content.&lt;/span&gt;
                  &lt;span class="c1"&gt;// &amp;lt;see href="https://github.com/statiqdev/Statiq.Framework/blob/main/src/core/Statiq.Core/Modules/Content/MergeContent.cs"&amp;gt;MergeContent&amp;lt;/see&amp;gt;.&lt;/span&gt;
                  &lt;span class="c1"&gt;// &amp;lt;see href="https://statiq.dev/web/content-and-data/content/"&amp;gt;Content propery of IDocument&amp;lt;/see&amp;gt;&lt;/span&gt;
                  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MergeContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                      &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ReadFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;patterns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"_Hero.cshtml"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                  &lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="c1"&gt;// Render HTML file from Razor template and document typed as Hero model.&lt;/span&gt;
                  &lt;span class="c1"&gt;// &amp;lt;see href="https://github.com/statiqdev/Statiq.Framework/blob/main/src/extensions/Statiq.Razor/RenderRazor.cs"&amp;gt;RenderRazor&amp;lt;/see&amp;gt;&lt;/span&gt;
                  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RenderRazor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KontentConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Hero&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()),&lt;/span&gt;
                  &lt;span class="c1"&gt;// Set file system destionation for the document.&lt;/span&gt;
                  &lt;span class="c1"&gt;// &amp;lt;see href="https://github.com/statiqdev/Statiq.Framework/blob/main/src/core/Statiq.Core/Modules/IO/SetDestination.cs"&amp;gt;SetDestination&amp;lt;/see&amp;gt;&lt;/span&gt;
                  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SetDestination&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NormalizedPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"index.html"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
                  &lt;span class="c1"&gt;// Flush the the output.&lt;/span&gt;
                  &lt;span class="c1"&gt;// &amp;lt;see href="https://github.com/statiqdev/Statiq.Framework/blob/main/src/core/Statiq.Core/Modules/IO/WriteFiles.cs"&amp;gt;WriteFiles&amp;lt;/see&amp;gt;.&lt;/span&gt;
                  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;WriteFiles&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
              &lt;span class="p"&gt;};&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;🚀 &lt;em&gt;Done! Now run&lt;/em&gt; &lt;code&gt;dotnet build -- preview&lt;/code&gt; &lt;em&gt;and see your first hero page at&lt;/em&gt; &lt;code&gt;http://localhost:5080&lt;/code&gt; &lt;em&gt;🚀&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Raw boilerplate is on GitHub under&lt;/em&gt; &lt;a href="https://github.com/Kentico/kontent-boilerplate-statiq-net/tree/raw-boilerplate" rel="noopener noreferrer"&gt;&lt;em&gt;raw-boilerplate tag&lt;/em&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Fine-tuning
&lt;/h2&gt;

&lt;p&gt;The following sections describe how to extend a boilerplate with Razor layout standards, basic styling, and configuration settings. These changes are already included in the boilerplate.&lt;/p&gt;
&lt;h3&gt;
  
  
  Razor conventions
&lt;/h3&gt;

&lt;p&gt;Razor works the standard way in the Statiq environment. By creating &lt;code&gt;_Layout.cshtml&lt;/code&gt; in the &lt;code&gt;input&lt;/code&gt; folder and specifying the default layout in &lt;code&gt;_ViewStart.cshtml&lt;/code&gt; like below, you prepare the standard setup for adding the pages with the same layout (as was done in &lt;a href="https://github.com/Kentico/kontent-boilerplate-statiq-net/commit/8c6a99a018be817aa2776371a8aef847625993b9" rel="noopener noreferrer"&gt;this commit&lt;/a&gt; with &lt;code&gt;_Hero.cshtml&lt;/code&gt; template).&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@{
    Layout = "_Layout";
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Sass
&lt;/h3&gt;

&lt;p&gt;Since the &lt;a href="https://sass-lang.com" rel="noopener noreferrer"&gt;Sass&lt;/a&gt; (as well as Less) is already pre-configured in &lt;code&gt;Statiq.Web&lt;/code&gt; default modules, it is possible to create a sass file in the &lt;code&gt;input&lt;/code&gt; folder and then reference it by the same name with &lt;code&gt;.css&lt;/code&gt; extension. Create &lt;code&gt;main.scss&lt;/code&gt; file and reference its transpiled version in the Razor view using &lt;code&gt;@IExecutionContext.Current.GetLink("/main.css")&lt;/code&gt; and add some basic styling (see the &lt;a href="https://github.com/Kentico/kontent-boilerplate-statiq-net/commit/a8a7f03ea5db9737d69636828dde923500acc334" rel="noopener noreferrer"&gt;implementation&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjpqpyb5ons9qz2c7dlx4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjpqpyb5ons9qz2c7dlx4.png" alt="Styles boilerplate visual" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Extract Project ID
&lt;/h3&gt;

&lt;p&gt;It is a good idea and a &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-5.0#default-configuration" rel="noopener noreferrer"&gt;.NET best practice to extract configuration to settings files&lt;/a&gt;. To extract the Kontent delivery client configuration to this file, create an &lt;code&gt;appsettings.json&lt;/code&gt; file with the &lt;code&gt;DeliveryOptions&lt;/code&gt; section containing only one property &lt;code&gt;ProjectId&lt;/code&gt;. Then in &lt;code&gt;Project.cs&lt;/code&gt; configure the delivery client to dependency injection (see the &lt;a href="https://github.com/Kentico/kontent-boilerplate-statiq-net/commit/92f2d802fd66b4878b7299a2b8932bed84e3953c" rel="noopener noreferrer"&gt;implementation&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDeliveryClient&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;IConfiguration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That action also opens the door for you to use different sets of configurations depending on the environment i.e. use configuration with a preview API key for your local development environment.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, I showed you how to build a simple Jamstack site using .NET and static site generator Statiq. We created a new content type with some content in a headless CMS, connected the CMS to our application, and converted the data into generated static pages. Find the complete implementation here:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kontent-ai" rel="noopener noreferrer"&gt;
        kontent-ai
      &lt;/a&gt; / &lt;a href="https://github.com/kontent-ai/boilerplate-statiq-net" rel="noopener noreferrer"&gt;
        boilerplate-statiq-net
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Boilerplate utilizing Statiq and Kontent.ai to provide a starting point in the Jamstack world for .NET developers.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Statiq boilerplate for Kontent.ai&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/kontent-ai/boilerplate-statiq-net/workflows/Publish/badge.svg"&gt;&lt;img src="https://github.com/kontent-ai/boilerplate-statiq-net/workflows/Publish/badge.svg" alt="Build and publish"&gt;&lt;/a&gt;
&lt;a href="https://kontent-ai.github.io/boilerplate-statiq-net" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1d1d8650db9796b696756e451a4942b3ec2676b79d3851e80beae16165d11af5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6976652d44454d4f2d627269676874677265656e2e7376673f6c6f676f3d676974687562266c6f676f436f6c6f723d7768697465" alt="Live Demo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Boilerplate utilizing &lt;a href="https://statiq.dev/" rel="nofollow noopener noreferrer"&gt;Statiq&lt;/a&gt; and &lt;a href="https://kontent.ai" rel="nofollow noopener noreferrer"&gt;Kontent.ai&lt;/a&gt; to provide a starting point in the Jamstack world for .NET developers.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/kontent-ai/boilerplate-statiq-net./screenshot.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fkontent-ai%2Fboilerplate-statiq-net.%2Fscreenshot.png" alt="Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Get started&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Requirements&lt;/h3&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dotnet.microsoft.com/download" rel="nofollow noopener noreferrer"&gt;.NET 6&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Clone the codebase&lt;/h3&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Click the &lt;a href="https://github.com/petrsvihlik/statiq-starter-kontent-lumen/generate" rel="noopener noreferrer"&gt;"Use this template"&lt;/a&gt; button to &lt;a href="https://help.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-from-a-template" rel="noopener noreferrer"&gt;create your own repository from this template&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Running locally&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;dotnet run -- preview&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;🎊🎉 &lt;strong&gt;Visit &lt;a href="http://localhost:5080" rel="nofollow noopener noreferrer"&gt;http://localhost:5080&lt;/a&gt; and start exploring the code base!&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;By default, the content is loaded from a shared Kontent.ai project. If you want to use your own clone of the project so that you can customize it and experiment with Kontent, continue to the next section.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Create a content source&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Application itself is configured to use shared alvawys avalable Kontent-ai project.&lt;/p&gt;
&lt;p&gt;If you want to generate the clone of the project in order to be able to edit the content, use &lt;a href="https://app.kontent.ai/sample-site-configuration" rel="nofollow noopener noreferrer"&gt;Sample site generator&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use "CREATE A NEW SAMPLE PROJECT" for generating the project.&lt;/li&gt;
&lt;li&gt;Access the project listing on…&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kontent-ai/boilerplate-statiq-net" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;If you want to see a more complex example, check out the &lt;a href="https://github.com/Kentico/statiq-starter-kontent-lumen" rel="noopener noreferrer"&gt;Kentico Kontent Statiq - Lumen Starter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>jamstack</category>
      <category>dotnet</category>
      <category>webdev</category>
      <category>csharp</category>
    </item>
  </channel>
</rss>
