<?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: Jeannie</title>
    <description>The latest articles on DEV Community by Jeannie (@jeaniscoding).</description>
    <link>https://dev.to/jeaniscoding</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%2F3034676%2F0885adfd-4f17-4d5e-a46e-f12edbced8e0.png</url>
      <title>DEV Community: Jeannie</title>
      <link>https://dev.to/jeaniscoding</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jeaniscoding"/>
    <language>en</language>
    <item>
      <title>☁️ How to Host Your Side Projects for $0: The Ultimate GCP Free Tier Guide</title>
      <dc:creator>Jeannie</dc:creator>
      <pubDate>Sat, 13 Dec 2025 18:53:49 +0000</pubDate>
      <link>https://dev.to/jeaniscoding/how-to-host-your-side-projects-for-0-the-ultimate-gcp-free-tier-guide-3p07</link>
      <guid>https://dev.to/jeaniscoding/how-to-host-your-side-projects-for-0-the-ultimate-gcp-free-tier-guide-3p07</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;How-to guide for configuring regions, disk types, and network tiers to build a forever-free Linux server.&lt;/p&gt;
&lt;/blockquote&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%2Fov3dbpbakls7elhufkwf.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%2Fov3dbpbakls7elhufkwf.png" alt="GCP Official Doc on Free Tier Specifications" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Hello, Dev Community! 👋&lt;/p&gt;

&lt;p&gt;I'm excited to kick off a new series where I’ll be building an &lt;strong&gt;AI-Powered News &amp;amp; Insight App&lt;/strong&gt;. But before we dive into "Vibe Coding," LLMs, and Python scripts, we need a home for our application.&lt;/p&gt;

&lt;p&gt;While tools like Vercel and Replit are fantastic, sometimes you just need a raw Linux server (VM) to have full control over your environment—whether it's for hosting a Docker container, running a cron job, or just experimenting with Linux.&lt;/p&gt;

&lt;p&gt;In this article, I’ll walk you through how to provision a &lt;strong&gt;Google Cloud Platform (GCP) Compute Engine&lt;/strong&gt; instance that stays within the "Always Free" tier limits. I'll share exactly which settings to tweak to avoid those surprise bills! 💸&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Step-by-Step Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A Google Cloud Platform account with billing enabled, but it won't incurred cost because it's covered by free tier quota.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1: Machine Configuration
&lt;/h3&gt;

&lt;p&gt;Navigate to &lt;strong&gt;Compute Engine&lt;/strong&gt; &amp;gt; &lt;strong&gt;Create an instance&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The "Always Free" tier has strict requirements regarding location and hardware.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Region:&lt;/strong&gt; Select &lt;code&gt;us-west1&lt;/code&gt;, &lt;code&gt;us-east1&lt;/code&gt;, or &lt;code&gt;us-central1&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;My Choice:&lt;/em&gt; I picked &lt;code&gt;us-west1&lt;/code&gt; (Oregon) because it is physically nearer to my location in Asia compared to the other free options, offering slightly better latency.
&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%2Foe1r4quhqtrnd2j1rbea.png" alt="VM Region" width="800" height="522"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Machine Type:&lt;/strong&gt; Select &lt;strong&gt;e2-micro&lt;/strong&gt; (2 vCPU, 1 core, 1 GB memory).

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Note:&lt;/em&gt; This is a shared-core machine, perfect for low-traffic apps or development environments.
&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%2Fnswzwhsvfxm0mo6g8ezc.png" alt="VM Machine Type" width="800" height="522"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 2: OS and Storage (Crucial!)
&lt;/h3&gt;

&lt;p&gt;This is where many people accidentally incur costs. By default, GCP might select a "Balanced" disk, which is not free.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Click &lt;strong&gt;Change&lt;/strong&gt; under "Boot disk".&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Boot disk type:&lt;/strong&gt; Change this to &lt;strong&gt;Standard persistent disk&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Size:&lt;/strong&gt; Set this to &lt;strong&gt;30 GB&lt;/strong&gt;.

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Why?&lt;/em&gt; You get 30GB of &lt;em&gt;Standard&lt;/em&gt; persistent disk usage per month for free.
&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%2F04zd3j810kazp16t8gcn.png" alt="VM Boot Disk Type" width="800" height="523"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 3: Data Protection &amp;amp; Observability
&lt;/h3&gt;

&lt;p&gt;We need to strip away the paid add-ons.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Backups:&lt;/strong&gt; In the "Data protection" section, select &lt;strong&gt;No backups&lt;/strong&gt;. Backups and snapshots cost extra.
&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%2F0un1tz2gvv46317x7dej.png" alt="VM No Backup" width="800" height="523"&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Observability:&lt;/strong&gt; In the "Observability" section, &lt;strong&gt;uncheck&lt;/strong&gt; "Install Ops Agent".

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Reason:&lt;/em&gt; The Ops Agent consumes precious RAM. On a 1GB &lt;code&gt;e2-micro&lt;/code&gt; instance, we need every megabyte for our application.
&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%2Fzu51ygr5nkb5suf3x2ut.png" alt="VM No Observability" width="800" height="522"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 4: Networking
&lt;/h3&gt;

&lt;p&gt;Finally, let's configure traffic and network pricing.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Firewall:&lt;/strong&gt; Check &lt;strong&gt;Allow HTTP traffic&lt;/strong&gt; and &lt;strong&gt;Allow HTTPS traffic&lt;/strong&gt; so we can access our web apps later.
&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%2Ffa2fdvyhb7mefn3rdm9p.png" alt="VM Networking Allow Traffic" width="800" height="523"&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Network Interface:&lt;/strong&gt; Expand the "Network interfaces" section and click on &lt;code&gt;nic0&lt;/code&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%2Fm8vrhd93uohq489zo8s4.png" alt="VM Networking Interface 1" width="800" height="523"&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Network Service Tier:&lt;/strong&gt; Change this from &lt;em&gt;Premium&lt;/em&gt; to &lt;strong&gt;Standard&lt;/strong&gt;.

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Pro Tip:&lt;/em&gt; Premium tier routes traffic over Google's global backbone (faster but costlier). Standard tier uses the public internet (free/cheaper for low usage).
&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%2Fsx5e1jjyzx1gjjywi7x9.png" alt="VM Networking Interface 2" width="800" height="523"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  📊 Quick Reference: The "Golden Config" Decision Table
&lt;/h2&gt;

&lt;p&gt;Here is a summary of the choices I made versus the defaults, to help you understand &lt;em&gt;why&lt;/em&gt; we configured it this way.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Configuration&lt;/th&gt;
&lt;th&gt;Default GCP Setting (Costly 💸)&lt;/th&gt;
&lt;th&gt;Our Free Tier Choice (Free 🆓)&lt;/th&gt;
&lt;th&gt;Reason&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Region&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Often defaults to local region&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;us-west1&lt;/code&gt; (or &lt;code&gt;us-east1&lt;/code&gt;/&lt;code&gt;central1&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Only specific US regions are Free Tier eligible.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Machine Type&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;e2-medium&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;e2-micro&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The specific instance type covered by the program.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Disk Type&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Balanced Persistent Disk&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Standard Persistent Disk&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Only "Standard" is covered by the 30GB free allowance.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Network Tier&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Premium&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Standard&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Premium costs extra per GB; Standard is budget-friendly.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Observability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Ops Agent Enabled&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Disabled&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Saves RAM resources on the small &lt;code&gt;e2-micro&lt;/code&gt; instance.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  ✅ Verification
&lt;/h2&gt;

&lt;p&gt;Before hitting "Create," look at the &lt;strong&gt;Monthly Estimate&lt;/strong&gt; on the right side of the screen (highlighted in green rectangle).&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%2Fzu51ygr5nkb5suf3x2ut.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%2Fzu51ygr5nkb5suf3x2ut.png" alt="Final check" width="800" height="522"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It should look remarkably clean, listing only:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;code&gt;2 vCPU + 1 GB memory&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; &lt;code&gt;30 GB standard persistent disk&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you see &lt;em&gt;anything&lt;/em&gt; else (like "Snapshot schedule" or "Ops Agent"), go back and double-check the steps above.&lt;/p&gt;

&lt;p&gt;Once verified, click &lt;strong&gt;Create&lt;/strong&gt;! 🚀&lt;/p&gt;




&lt;h2&gt;
  
  
  🔮 What's Next?
&lt;/h2&gt;

&lt;p&gt;Congratulations! You now have a running Linux server in the cloud for $0/month.&lt;/p&gt;

&lt;p&gt;I will be using this VM as the foundation for my upcoming side projects, specifically the &lt;strong&gt;AI News &amp;amp; Insight App&lt;/strong&gt; I mentioned earlier. In the next few posts, I'll be sharing how I:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Set up the environment on this VM.&lt;/li&gt;
&lt;li&gt; Use "Vibe Coding" tools to generate the application code.&lt;/li&gt;
&lt;li&gt; Deploy the app to this very server.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Stay tuned for the next part of this series!&lt;/strong&gt; If you have any tips for optimizing free-tier VMs, let me know in the comments below! 👇&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>free</category>
      <category>gcp</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>💡 My First Look: Docker's New MCP Catalog &amp; Toolkit for AI Developers! 🐳</title>
      <dc:creator>Jeannie</dc:creator>
      <pubDate>Thu, 24 Apr 2025 18:08:35 +0000</pubDate>
      <link>https://dev.to/jeaniscoding/my-first-look-dockers-new-mcp-catalog-toolkit-for-ai-developers-3klk</link>
      <guid>https://dev.to/jeaniscoding/my-first-look-dockers-new-mcp-catalog-toolkit-for-ai-developers-3klk</guid>
      <description>&lt;p&gt;Hey fellow cloud enthusiasts! 👋&lt;/p&gt;

&lt;p&gt;Last week, Docker dropped some exciting news that caught my eye: the &lt;a href="https://www.docker.com/blog/introducing-docker-mcp-catalog-and-toolkit/" rel="noopener noreferrer"&gt;announcement&lt;/a&gt; of their &lt;strong&gt;MCP Catalog and Toolkit&lt;/strong&gt;! I immediately dived in and understand what this means for developers working with AI tools. &lt;/p&gt;

&lt;p&gt;This post is my "first look" exploration – sharing what I've gathered and my initial thoughts on its potential impact. Let's journey through this together! 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  TLDR; ✅
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;  Docker is launching a centralized &lt;strong&gt;MCP Catalog&lt;/strong&gt; for discovering and distributing AI tools.&lt;/li&gt;
&lt;li&gt;  The &lt;strong&gt;MCP Toolkit&lt;/strong&gt; (a Docker Desktop extension) aims to simplify managing, authenticating, and running these tools locally.&lt;/li&gt;
&lt;li&gt;  This initiative focuses on improving developer experience, security, and standardization in the AI tooling space.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;So, What's MCP Anyway?&lt;/li&gt;
&lt;li&gt;My First Look: The MCP Catalog&lt;/li&gt;
&lt;li&gt;
My First Look: The MCP Toolkit

&lt;ul&gt;
&lt;li&gt;Toolkit vs. Traditional Methods&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;What This Could Mean for AI Development&lt;/li&gt;

&lt;li&gt;How to Explore Yourself&lt;/li&gt;

&lt;li&gt;Final Thoughts &amp;amp; Your Turn!&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  So, What's MCP Anyway? 🤔
&lt;/h2&gt;

&lt;p&gt;Before diving into Docker's new toys, let's quickly touch on MCP, the &lt;strong&gt;Model Context Protocol&lt;/strong&gt;. Think of it as a standardized way for AI models and specialized tools (like code interpreters, data analyzers, search functions, etc.) to communicate and share context securely. As AI agents become more sophisticated, needing to use multiple tools, managing these interactions becomes crucial. MCP aims to provide that common language.&lt;/p&gt;




&lt;h2&gt;
  
  
  My First Look: The MCP Catalog 🗂️
&lt;/h2&gt;

&lt;h3&gt;
  
  
  (Your AI Tool Hub!)
&lt;/h3&gt;

&lt;p&gt;Docker announced the upcoming &lt;strong&gt;&lt;a href="https://hub.docker.com/u/mcp" rel="noopener noreferrer"&gt;MCP Catalog&lt;/a&gt;&lt;/strong&gt;, and the analogy that springs to mind is &lt;strong&gt;Docker Hub, but for MCP tools&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Purpose:&lt;/strong&gt; The core idea seems to be creating a &lt;strong&gt;centralized hub&lt;/strong&gt; for discovering, sharing, and managing MCP-compatible tools. Much like package managers (npm, pip) or Docker Hub itself revolutionized software distribution, this catalog aims to do the same for the growing ecosystem of AI tools.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Benefits:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Discovery:&lt;/strong&gt; For developers (like us!), it promises a single place to find and evaluate verified MCP tools, saving time hunting through scattered resources. 🕵️‍♀️&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Distribution:&lt;/strong&gt; For tool authors, it offers a dedicated channel to increase the visibility and reach of their creations. 📢&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Containerization:&lt;/strong&gt; Leveraging Docker's strengths, these tools can be packaged with their dependencies, ensuring consistency. 📦&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Security:&lt;/strong&gt; Docker emphasizes security features like potential credential management (centralized &amp;amp; encrypted) and adherence to zero-trust principles (least privilege access, audit trails). This is HUGE for building trustworthy AI applications. 🔒&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;It looks like a significant step towards bringing order and trust to the burgeoning world of AI components.&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%2F8iktfx4ocbwofsbyfcy6.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%2F8iktfx4ocbwofsbyfcy6.png" alt="Docker MCP Catalog" width="468" height="394"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  My First Look: The MCP Toolkit 🛠️
&lt;/h2&gt;

&lt;h3&gt;
  
  
  (Your Local AI Gateway!)
&lt;/h3&gt;

&lt;p&gt;Complementing the Catalog is the &lt;strong&gt;MCP Toolkit&lt;/strong&gt;, delivered as a &lt;a href="https://open.docker.com/extensions/marketplace?extensionId=docker/labs-ai-tools-for-devs" rel="noopener noreferrer"&gt;Docker Desktop Extension&lt;/a&gt;. I see this as the local management layer – the control panel on your machine.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Role:&lt;/strong&gt; It acts as a &lt;strong&gt;"Gateway MCP Server"&lt;/strong&gt; on your local machine. Instead of running multiple MCP tools directly with potentially broad permissions, the Toolkit provides a managed, secure interface.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Benefits:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Simplified Authentication:&lt;/strong&gt; Handles credential management (built-in, OAuth) for various tools, making it easier to connect securely and revoke access centrally. No more juggling API keys in multiple places! 🔑&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Dynamic Tool Exposure:&lt;/strong&gt; Allows you to easily enable or disable specific tools (via toggle switches in the extension UI) and exposes &lt;em&gt;only&lt;/em&gt; the enabled ones to compatible clients. ✨&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Resource Management:&lt;/strong&gt; Offers built-in memory capabilities.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Isolation:&lt;/strong&gt; Provides network and disk isolation, enhancing security by limiting the tool's access to your host system. 🛡️&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Docker Toolkit Installation&lt;/strong&gt;:&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%2Fiqfhvcvlvd8ma4p0q76f.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%2Fiqfhvcvlvd8ma4p0q76f.png" alt="Docker Toolkit Installation" width="468" height="343"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Tools page&lt;/strong&gt; to enable or disable tools with toggle switch:&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%2Fahji9fatm4d3klscgtn2.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%2Fahji9fatm4d3klscgtn2.png" alt="Docker Toolkit - Tools page" width="468" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Clients page&lt;/strong&gt; to connect to existing clients on your laptop:&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%2F2cldaz4xxga8tmudmkdd.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%2F2cldaz4xxga8tmudmkdd.png" alt="Docker Toolkit - Clients page" width="468" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Toolkit vs. Traditional Methods
&lt;/h3&gt;

&lt;p&gt;How does this compare to current practices? Let's break it down:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Docker MCP Toolkit Approach&lt;/th&gt;
&lt;th&gt;Traditional Approach (e.g., npx, manual servers)&lt;/th&gt;
&lt;th&gt;Benefit of Toolkit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Execution&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Managed execution within Docker Desktop&lt;/td&gt;
&lt;td&gt;Direct execution (e.g., &lt;code&gt;npx&lt;/code&gt;, &lt;code&gt;uvx&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Network/disk isolation, controlled permissions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Configuration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Centralized via Extension UI&lt;/td&gt;
&lt;td&gt;Manual config per tool/server&lt;/td&gt;
&lt;td&gt;Reduces manual error, saves time ⏱️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Authentication&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Built-in credential store, OAuth management&lt;/td&gt;
&lt;td&gt;Manual key handling per tool&lt;/td&gt;
&lt;td&gt;Easier &amp;amp; more secure auth, simple revocation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Discovery&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Integrates with MCP Catalog&lt;/td&gt;
&lt;td&gt;Manual searching&lt;/td&gt;
&lt;td&gt;Streamlined discovery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Centralized enable/disable, updates via Docker&lt;/td&gt;
&lt;td&gt;Decentralized, manual updates/management&lt;/td&gt;
&lt;td&gt;Simplified oversight, easier lifecycle management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Host Access&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Isolated, least privilege principle&lt;/td&gt;
&lt;td&gt;Potentially full host access&lt;/td&gt;
&lt;td&gt;Enhanced security 🔒&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Setup Complexity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Potentially simpler via Extension&lt;/td&gt;
&lt;td&gt;Can be complex, error-prone&lt;/td&gt;
&lt;td&gt;Lower barrier to entry, faster setup&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This approach seems geared towards significantly reducing the friction and security concerns associated with integrating multiple AI tools into development workflows.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Could Mean for AI Development 🌍
&lt;/h2&gt;

&lt;p&gt;My initial take? This could be a significant step forward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Standardization:&lt;/strong&gt; Pushing towards more standardized ways to package, distribute, and interact with AI tools.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Improved Developer Experience:&lt;/strong&gt; Reducing the setup and management overhead allows developers to focus more on building innovative AI applications.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Enhanced Security:&lt;/strong&gt; Addressing security concerns head-on with isolation and centralized credential management is crucial for enterprise adoption.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Accelerated Innovation:&lt;/strong&gt; A thriving ecosystem facilitated by the Catalog could lead to faster development and adoption of new AI capabilities.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Of course, the success will depend on adoption by both tool creators and developers, the quality and variety of tools in the catalog, and how seamlessly the Toolkit integrates into real-world workflows.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Explore Yourself 🧭
&lt;/h2&gt;

&lt;p&gt;Want to check it out?&lt;/p&gt;

&lt;h3&gt;
  
  
  🐳 Docker MCP Catalog:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://hub.docker.com/u/mcp" rel="noopener noreferrer"&gt;https://hub.docker.com/u/mcp&lt;/a&gt;&lt;br&gt;
&lt;em&gt;(Keep an eye on this as it populates!)&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🐳 Docker MCP Toolkit:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://open.docker.com/extensions/marketplace?extensionId=docker/labs-ai-tools-for-devs" rel="noopener noreferrer"&gt;https://open.docker.com/extensions/marketplace?extensionId=docker/labs-ai-tools-for-devs&lt;/a&gt;&lt;br&gt;
&lt;em&gt;(Install it via Docker Desktop)&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts &amp;amp; Your Turn! 🗣️
&lt;/h2&gt;

&lt;p&gt;Docker's move into the MCP space with the Catalog and Toolkit feels like a natural extension of their mission to simplify developer lives. By tackling discovery, management, and security for AI tools, they're addressing real pain points I've started to feel as I experiment more with agentic AI.&lt;/p&gt;

&lt;p&gt;I'm genuinely excited to see how this evolves, which tools become available, and how the community embraces it. It feels like a step towards making sophisticated AI integration more accessible and secure.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;But what do &lt;em&gt;you&lt;/em&gt; think?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Are you excited about the MCP Catalog and Toolkit?&lt;/li&gt;
&lt;li&gt;  What challenges do you currently face when working with AI tools?&lt;/li&gt;
&lt;li&gt;  Are there specific MCP tools you'd love to see in the Catalog?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Let me know your thoughts in the comments below! Let's discuss! 👇 And if you found this exploration helpful, consider following for more tech deep dives and learning journeys!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>mcp</category>
      <category>registry</category>
      <category>ai</category>
    </item>
    <item>
      <title>✨ JAMstack Blogging Made Easy: Nuxt.js, Sanity.io &amp; Cloudflare Pages Explained</title>
      <dc:creator>Jeannie</dc:creator>
      <pubDate>Tue, 22 Apr 2025 11:51:07 +0000</pubDate>
      <link>https://dev.to/jeaniscoding/building-a-modern-blog-my-journey-with-nuxtjs-sanityio-cloudflare-pages-1gi</link>
      <guid>https://dev.to/jeaniscoding/building-a-modern-blog-my-journey-with-nuxtjs-sanityio-cloudflare-pages-1gi</guid>
      <description>&lt;p&gt;Hey fellow cloud enthusiasts! 👋 Ever wanted to build a fast, modern blog using some of the coolest technologies out there? &lt;/p&gt;

&lt;p&gt;I recently embarked on a journey to do just that, combining the power of &lt;strong&gt;Nuxt.js&lt;/strong&gt; for the frontend, &lt;strong&gt;Sanity.io&lt;/strong&gt; as a headless CMS, and &lt;strong&gt;Cloudflare Pages&lt;/strong&gt; for seamless deployment.&lt;/p&gt;

&lt;p&gt;Why this stack? It offers an amazing developer experience, incredible flexibility, and blazing-fast performance. But like any real-world project, the path wasn't always straight! 😉&lt;/p&gt;

&lt;p&gt;In this post, I'll share my step-by-step process, including the &lt;strong&gt;inevitable troubleshooting moments&lt;/strong&gt; (especially navigating Nuxt 3 updates!), hoping it helps you learn and maybe even inspire your next project.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Heads up: The specific commands and steps worked for Nuxt.js v3.16.2 and Sanity.io v3.85.1. Future versions might require adjustments due to potential changes in dependencies.)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  📌 Key Takeaways:
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;  Understand the roles of Nuxt.js, Sanity.io, and Cloudflare Pages in a modern web JAMstack.&lt;/li&gt;
&lt;li&gt;  Learn how to set up and connect Sanity.io (headless CMS) with a Nuxt.js frontend.&lt;/li&gt;
&lt;li&gt;  See practical examples of fetching and displaying data using GROQ and Portable Text.&lt;/li&gt;
&lt;li&gt;  Walk through deploying a Nuxt application globally via Cloudflare Pages.&lt;/li&gt;
&lt;li&gt;  Gain insights from real troubleshooting steps encountered during development.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  📜 Table of Contents:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Why This Tech Stack? (Nuxt + Sanity + Cloudflare)&lt;/li&gt;
&lt;li&gt;Part 1: Setting Up Your Content Backend with Sanity.io&lt;/li&gt;
&lt;li&gt;Part 2: Building the Blog Frontend with Nuxt.js&lt;/li&gt;
&lt;li&gt;Part 3: Connecting Nuxt.js to Sanity &amp;amp; Displaying Posts (incl. Troubleshooting!)&lt;/li&gt;
&lt;li&gt;Part 4: Deploying to the World with Cloudflare Pages&lt;/li&gt;
&lt;li&gt;Bonus: Understanding GROQ &amp;amp; Nuxt DevTools&lt;/li&gt;
&lt;li&gt;Wrapping Up &amp;amp; Your Turn!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's dive in!&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Tech Stack? (Nuxt + Sanity + Cloudflare)
&lt;/h2&gt;

&lt;p&gt;Before we jump into the code, let's briefly touch upon &lt;em&gt;why&lt;/em&gt; these tools work so well together. We're essentially building a &lt;strong&gt;3-tier application&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Presentation Tier (Frontend):&lt;/strong&gt; What the user sees and interacts with. We're using &lt;strong&gt;Nuxt.js&lt;/strong&gt;, a powerful and intuitive framework built on Vue.js, known for features like server-side rendering (SSR), static site generation (SSG), file-system routing, and auto-imports, which simplify development.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Logic Tier (Processing):&lt;/strong&gt; Handles the business logic. In our case, &lt;strong&gt;Sanity.io&lt;/strong&gt; handles much of this through its APIs and query language (GROQ).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Data Tier (Storage):&lt;/strong&gt; Where the content lives. &lt;strong&gt;Sanity.io&lt;/strong&gt; acts as our headless Content Management System (CMS), providing a structured content platform hosted in the cloud. It gives us a customizable editing interface (Sanity Studio) and APIs to fetch content.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Benefits:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Decoupled Architecture:&lt;/strong&gt; Frontend and backend are separate, allowing independent development, scaling, and technology choices (JAMstack principles!).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Developer Experience:&lt;/strong&gt; Nuxt and Sanity are designed to be developer-friendly.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Content Flexibility:&lt;/strong&gt; Sanity's structured content approach is highly adaptable.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Performance &amp;amp; Scalability:&lt;/strong&gt; Nuxt can generate static sites or use SSR for speed, while Cloudflare Pages provides global CDN deployment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a simplified view of the architecture:&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%2Firz6ivju7h3s6bj8pgsq.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%2Firz6ivju7h3s6bj8pgsq.png" alt="JAMstack blog architecture" width="800" height="215"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Part 1: Setting Up Your Content Backend with Sanity.io
&lt;/h2&gt;

&lt;p&gt;First, we need a place to store and manage our blog posts. That's where Sanity.io comes in.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1: Install Sanity Locally
&lt;/h3&gt;

&lt;p&gt;This command scaffolds a new Sanity project, setting up the Sanity Studio (your content editing interface) and configuration files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx sanity init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow the prompts to log in or create a Sanity account, choose a project template (like 'Blog'), and configure dataset access.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Run Local Dev Server
&lt;/h3&gt;

&lt;p&gt;To test the Sanity Studio locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx sanity dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Note:&lt;/strong&gt; You'll likely need to log in via the browser window that opens. This local dev server (&lt;code&gt;localhost:3333&lt;/code&gt; by default) is private to your authenticated user.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For production builds (though we'll rely on the hosted Sanity service):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Build the static Sanity Studio files&lt;/span&gt;
sanity build
&lt;span class="c"&gt;# Start a local server for the built studio&lt;/span&gt;
sanity start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Test Access and Add Content
&lt;/h3&gt;

&lt;p&gt;Navigate to &lt;code&gt;http://localhost:3333&lt;/code&gt; in your browser. You should see the Sanity Studio interface.&lt;/p&gt;

&lt;p&gt;You can either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Manually add content types (like 'Author' and 'Post') and create some sample entries.&lt;/li&gt;
&lt;li&gt;  Import sample data if your chosen template included an import script (e.g., &lt;code&gt;npm run import-sample-data&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I manually added one author and one blog post to proceed with testing the frontend integration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: Building the Blog Frontend with Nuxt.js
&lt;/h2&gt;

&lt;p&gt;Now, let's create the Nuxt.js application that will display our blog content.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Allow Nuxt.js Access via CORS
&lt;/h3&gt;

&lt;p&gt;Since our Nuxt app (running locally on &lt;code&gt;http://localhost:3000&lt;/code&gt; initially) needs to fetch data from Sanity's API, we must tell Sanity to trust requests from this origin.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Go to &lt;a href="https://manage.sanity.io" rel="noopener noreferrer"&gt;manage.sanity.io&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt; Select your project.&lt;/li&gt;
&lt;li&gt; Navigate to the &lt;strong&gt;API&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt; Under &lt;strong&gt;CORS origins&lt;/strong&gt;, click &lt;strong&gt;Add CORS origin&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Enter &lt;code&gt;http://localhost:3000&lt;/code&gt; and check the &lt;strong&gt;Allow credentials&lt;/strong&gt; box.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 2: Create Nuxt Project
&lt;/h3&gt;

&lt;p&gt;Use the Nuxt CLI to create a new project. I named mine &lt;code&gt;blog&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-nuxt-app blog
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;During setup, I selected:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Programming language: &lt;strong&gt;TypeScript&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  Package manager: &lt;strong&gt;npm&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  UI framework: &lt;strong&gt;None&lt;/strong&gt; (can add later if needed)&lt;/li&gt;
&lt;li&gt;  Nuxt.js modules: &lt;strong&gt;None&lt;/strong&gt; (we'll add Sanity manually)&lt;/li&gt;
&lt;li&gt;  Linting tools: (Your preference)&lt;/li&gt;
&lt;li&gt;  Testing framework: &lt;strong&gt;None&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  Rendering mode: &lt;strong&gt;Universal (SSR / SSG)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  Deployment target: &lt;strong&gt;Static (Static/JAMstack hosting)&lt;/strong&gt; (Important for Cloudflare Pages)&lt;/li&gt;
&lt;li&gt;  Development tools: (Your preference)&lt;/li&gt;
&lt;li&gt;  Version control: &lt;strong&gt;Initialize git repository&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 3: Run Local Dev Server
&lt;/h3&gt;

&lt;p&gt;Navigate into your new project directory and start the development server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;blog
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Test Access
&lt;/h3&gt;

&lt;p&gt;Open &lt;code&gt;http://localhost:3000&lt;/code&gt; in your browser. You should see the default Nuxt welcome page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Configure Sanity.io Integration
&lt;/h3&gt;

&lt;p&gt;Install the necessary packages to connect Nuxt with Sanity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @nuxtjs/sanity @sanity/client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the Sanity module to your Nuxt configuration using the Nuxt CLI helper:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx nuxi@latest module add sanity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command should automatically update your &lt;code&gt;nuxt.config.ts&lt;/code&gt;. Now, you need to tell the module your Sanity project ID.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Find your &lt;code&gt;projectId&lt;/code&gt; in the &lt;code&gt;sanity.config.ts&lt;/code&gt; file within your &lt;em&gt;Sanity project folder&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt; Add it to your &lt;em&gt;Nuxt project's&lt;/em&gt; &lt;code&gt;nuxt.config.ts&lt;/code&gt; file like this:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// nuxt.config.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineNuxtConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;modules&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;@nuxtjs/sanity&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;sanity&lt;/span&gt;&lt;span class="p"&gt;:&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;YOUR_SANITY_PROJECT_ID&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// Replace with your actual project ID&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// other config...&lt;/span&gt;
  &lt;span class="na"&gt;devtools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;enabled&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="c1"&gt;// Ensure Nuxt DevTools are enabled&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Detailed doc: &lt;a href="https://sanity.nuxtjs.org/getting-started/quick-start/" rel="noopener noreferrer"&gt;https://sanity.nuxtjs.org/getting-started/quick-start/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 3: Connecting Nuxt.js to Sanity &amp;amp; Displaying Posts (incl. Troubleshooting!)
&lt;/h2&gt;

&lt;p&gt;With setup complete, let's fetch and display our blog posts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create the Index Page (Listing Posts)
&lt;/h3&gt;

&lt;p&gt;This page will fetch all posts from Sanity and list their titles as links.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Create a &lt;code&gt;pages&lt;/code&gt; directory in the root of your Nuxt project if it doesn't exist.&lt;/li&gt;
&lt;li&gt; Create a file named &lt;code&gt;index.vue&lt;/code&gt; inside the &lt;code&gt;pages&lt;/code&gt; directory.&lt;/li&gt;
&lt;li&gt; Add the following code:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&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;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;My Blog&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;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"posts"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;"post in posts"&lt;/span&gt; &lt;span class="na"&gt;:key=&lt;/span&gt;&lt;span class="s"&gt;"post._id"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- Use NuxtLink for internal routing --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&amp;lt;NuxtLink&lt;/span&gt; &lt;span class="na"&gt;:to=&lt;/span&gt;&lt;span class="s"&gt;"`/$&lt;/span&gt;{post.slug.current}`"&amp;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="nt"&gt;&amp;lt;/NuxtLink&amp;gt;&amp;lt;/h2&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;/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;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;// Define the GROQ query to fetch all documents of type 'post'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`*[_type == "post"]`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Use the useSanityQuery composable provided by @nuxtjs/sanity&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;useSanityQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Basic error handling or loading state could be added here&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;min-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.posts&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2rem&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;/* Basic styling for links */&lt;/span&gt;
&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;text-decoration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#007bff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;text-decoration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;underline&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, visiting &lt;code&gt;localhost:3000&lt;/code&gt; should show the titles of the blog posts you created in Sanity. Clicking a title will change the URL (e.g., to &lt;code&gt;/my-first-post&lt;/code&gt;), but the page content won't change yet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Create Dynamic Blog Post Pages
&lt;/h3&gt;

&lt;p&gt;We need a way for Nuxt to dynamically create a page for each blog post based on its unique identifier (the "slug" generated by Sanity). Nuxt 3 uses file-based dynamic routing.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Inside the &lt;code&gt;pages&lt;/code&gt; directory, create a file named &lt;code&gt;[slug].vue&lt;/code&gt;. The square brackets indicate a dynamic route parameter.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Troubleshooting Moment 1: Nuxt 2 vs Nuxt 3 Routing &amp;amp; Data Fetching 😅
&lt;/h4&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%2Flzwf87ay8zvddjh4ypym.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%2Flzwf87ay8zvddjh4ypym.png" alt="Nuxt.js 404 error page" width="468" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My &lt;em&gt;initial&lt;/em&gt; attempt used conventions from Nuxt 2 and older examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Filename:&lt;/strong&gt; I first named the file &lt;code&gt;_slug.vue&lt;/code&gt; (Nuxt 2 convention). This resulted in a &lt;strong&gt;404 Not Found&lt;/strong&gt; error because Nuxt 3 uses &lt;code&gt;[slug].vue&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Accessing Route Params:&lt;/strong&gt; My first script attempt tried to access &lt;code&gt;params.slug&lt;/code&gt; directly within the &lt;code&gt;script setup&lt;/code&gt; block, like this (simplified):&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// INCORRECT for Nuxt 3 script setup&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`*[_type == "post" &amp;amp;&amp;amp; slug.current == "&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="s2"&gt;"][0]`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&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;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;useSanityQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This caused a &lt;strong&gt;500 Internal Server Error&lt;/strong&gt; with the message &lt;code&gt;params is not defined&lt;/code&gt;. In Nuxt 3's &lt;code&gt;script setup&lt;/code&gt;, you need to explicitly import and use &lt;code&gt;useRoute()&lt;/code&gt; to access route parameters.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Correct Code for &lt;code&gt;pages/[slug].vue&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This version uses the correct filename (&lt;code&gt;[slug].vue&lt;/code&gt;) and properly accesses the route parameter using &lt;code&gt;useRoute()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;v-if=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt;&lt;span class="nt"&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;&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="c"&gt;&amp;lt;!-- Content will be rendered here in the next step --&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;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;v-else&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
       &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Loading post or post not found...&lt;span class="nt"&gt;&amp;lt;/p&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;h4&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- Use NuxtLink for client-side navigation --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;NuxtLink&lt;/span&gt; &lt;span class="na"&gt;to=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;← Go back&lt;span class="nt"&gt;&amp;lt;/NuxtLink&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/h4&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;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;// Import useRoute to access route parameters&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;useRoute&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;#imports&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// or from 'vue-router' in Nuxt 3&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRoute&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// Construct the GROQ query using the slug from the route params&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`*[_type == "post" &amp;amp;&amp;amp; slug.current == "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;route&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="s2"&gt;"][0]`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Fetch the specific post data&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&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;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;useSanityQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Optional: Add better error handling for post not found&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;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&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;server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// Check if post is null/undefined after fetch&lt;/span&gt;
   &lt;span class="c1"&gt;// throw createError({ statusCode: 404, statusMessage: 'Post Not Found' });&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Post with slug "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;route&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="s2"&gt;" not found.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Useful for debugging during development&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Current 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;route&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;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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Fetched Post Data:&lt;/span&gt;&lt;span class="dl"&gt;'&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;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;min-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.content&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2rem&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;38rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* Adjust as needed */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;h4&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when you click a blog post link on the index page, Nuxt should navigate to the correct URL (e.g., &lt;code&gt;/your-post-slug&lt;/code&gt;) and display the title of that specific post. The content area is still empty, though.&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%2Fg31ptp0bgkhemrovugtf.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%2Fg31ptp0bgkhemrovugtf.png" alt="Blog post title success" width="468" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Render Blog Post Content (Portable Text)
&lt;/h3&gt;

&lt;p&gt;Sanity stores rich text content in a structured format called &lt;a href="https://www.sanity.io/docs/portable-text" rel="noopener noreferrer"&gt;Portable Text&lt;/a&gt;. We need a component to render this structured data into HTML.&lt;/p&gt;

&lt;h4&gt;
  
  
  Troubleshooting Moment 2: Portable Text Component for Nuxt 3 😵‍💫
&lt;/h4&gt;

&lt;p&gt;Again, following older tutorials led me down the wrong path initially.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Incorrect Package:&lt;/strong&gt; Some guides mentioned &lt;code&gt;sanity-blocks-vue-component&lt;/code&gt;. I installed it and tried setting it up via a Nuxt plugin (&lt;code&gt;plugins/sanity-blocks.js&lt;/code&gt;) as suggested for Nuxt 2.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;The Error:&lt;/strong&gt; This resulted in a dreaded &lt;strong&gt;"Hydration completed but contains mismatches"&lt;/strong&gt; error in the browser console. This often happens in SSR frameworks like Nuxt when the server-rendered HTML doesn't match the client-side virtual DOM, usually due to incompatible components or incorrect setup for the framework version.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Correct Approach for Nuxt 3 using &lt;code&gt;@portabletext/vue&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Install the Correct Package:&lt;/strong&gt; Use the official Vue 3 compatible package.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @portabletext/vue
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create a Nuxt Plugin:&lt;/strong&gt; Create a file named &lt;code&gt;portable-text.js&lt;/code&gt; (or similar) inside the &lt;code&gt;plugins&lt;/code&gt; directory.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// plugins/portable-text.js&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;PortableText&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;@portabletext/vue&lt;/span&gt;&lt;span class="dl"&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="nf"&gt;defineNuxtPlugin&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;nuxtApp&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="c1"&gt;// Register the PortableText component globally&lt;/span&gt;
  &lt;span class="nx"&gt;nuxtApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vueApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PortableText&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PortableText&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;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Register the Plugin:&lt;/strong&gt; Add the plugin path to your &lt;code&gt;nuxt.config.ts&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// nuxt.config.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineNuxtConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// ... other config&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/plugins/portable-text.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// Path to your plugin file&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="c1"&gt;// ... sanity config etc.&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Update &lt;code&gt;[slug].vue&lt;/code&gt; to Use &lt;code&gt;&amp;lt;PortableText&amp;gt;&lt;/code&gt;:&lt;/strong&gt; Modify the template section of &lt;code&gt;pages/[slug].vue&lt;/code&gt; to render the &lt;code&gt;post.body&lt;/code&gt; (assuming 'body' is the field name for your Portable Text content in Sanity).&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- pages/[slug].vue --&amp;gt;
&amp;lt;template&amp;gt;
  &amp;lt;div class="container"&amp;gt;
    &amp;lt;div v-if="post"&amp;gt;
      &amp;lt;h1 class="title"&amp;gt;{{ post.title }}&amp;lt;/h1&amp;gt;
      &amp;lt;div class="content"&amp;gt;
         &amp;lt;!-- Use the globally registered PortableText component --&amp;gt;
         &amp;lt;PortableText :value="post.body" /&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
     &amp;lt;div v-else&amp;gt;
       &amp;lt;p&amp;gt;Loading post or post not found...&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;h4&amp;gt;
      &amp;lt;NuxtLink to="/"&amp;gt;← Go back&amp;lt;/NuxtLink&amp;gt;
    &amp;lt;/h4&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup&amp;gt;
// ... (script setup remains the same as previous step) ...
import { useRoute } from '#imports';
const route = useRoute();
const query = `*[_type == "post" &amp;amp;&amp;amp; slug.current == "${route.params.slug}"][0]`;
const { data: post } = await useSanityQuery(query);
if (!post.value &amp;amp;&amp;amp; process.server) {
   console.error(`Post with slug "${route.params.slug}" not found.`);
}
console.log('Current Slug:', route.params.slug);
console.log('Fetched Post Data:', post.value);
&amp;lt;/script&amp;gt;

&amp;lt;style&amp;gt;
/* ... (styles remain the same) ... */
.container { margin: 2rem; min-height: 100vh; }
.content { margin: 2rem 0; max-width: 38rem; }
.content p { margin: 1rem 0; } /* Example style for paragraphs within portable text */
.content h2 { margin-top: 1.5rem; margin-bottom: 0.5rem; } /* Example style */
h4 { margin-top: 2rem; }
&amp;lt;/style&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;End Result:&lt;/strong&gt; Success! 🎉 Now, clicking a post link on the index page should take you to the individual post page, displaying both the title and the rich text content rendered correctly from Sanity.&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%2Fym6wta9f1a0wgx9htwjx.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%2Fym6wta9f1a0wgx9htwjx.png" alt="Blog title and content success" width="468" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 4: Deploying to the World with Cloudflare Pages
&lt;/h2&gt;

&lt;p&gt;Our blog works locally, but let's make it publicly accessible using Cloudflare Pages, which integrates beautifully with Git repositories for continuous deployment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits of Cloudflare Pages:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Automatic Deployments:&lt;/strong&gt; Deploys a new version each time you push to your Git repository.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Preview Deployments:&lt;/strong&gt; Creates preview URLs for pull requests, perfect for testing changes.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Global CDN:&lt;/strong&gt; Serves your static site from Cloudflare's edge network for speed.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Free Tier:&lt;/strong&gt; Generous free tier for static sites.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1: Create GitHub Repo and Push Code
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; Make sure your Nuxt.js project is a Git repository (&lt;code&gt;git init&lt;/code&gt; if you didn't during &lt;code&gt;create-nuxt-app&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; Create a new repository on GitHub (public or private).&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the GitHub repository as a remote and push your code:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote add origin &amp;lt;your-github-repo-url.git&amp;gt;
git branch &lt;span class="nt"&gt;-M&lt;/span&gt; main
git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin main
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;em&gt;(Alternatively, use the GitHub CLI (&lt;code&gt;gh&lt;/code&gt;) as shown in the original draft if you have it installed and configured).&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Note:&lt;/strong&gt; You only need to push your &lt;strong&gt;Nuxt.js project code&lt;/strong&gt;, not the Sanity project folder. Sanity is hosted separately.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 2: Publish to Cloudflare Pages
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; Log in to your Cloudflare dashboard: &lt;a href="https://dash.cloudflare.com/" rel="noopener noreferrer"&gt;https://dash.cloudflare.com/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; Navigate to &lt;strong&gt;Workers &amp;amp; Pages&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Create application&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Pages&lt;/strong&gt; tab -&amp;gt; &lt;strong&gt;Connect to Git&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Select the GitHub repository you just created.&lt;/li&gt;
&lt;li&gt; In the &lt;strong&gt;Set up builds and deployments&lt;/strong&gt; section:

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Production branch:&lt;/strong&gt; &lt;code&gt;main&lt;/code&gt; (or your default branch).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Framework preset:&lt;/strong&gt; Select &lt;strong&gt;Nuxt&lt;/strong&gt;. Cloudflare should automatically detect it and fill in the build settings.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Build command:&lt;/strong&gt; Should be &lt;code&gt;npm run generate&lt;/code&gt; or &lt;code&gt;nuxt generate&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Build output directory:&lt;/strong&gt; Should be &lt;code&gt;.output/public&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;(Optional) Root Directory:&lt;/strong&gt; If your Nuxt project is inside a subfolder in your repo, specify the path here. Otherwise, leave it blank.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Save and Deploy&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cloudflare will now pull your code, build the Nuxt application (generating static files), and deploy it to its global network.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Test Access
&lt;/h3&gt;

&lt;p&gt;Once the deployment is complete, Cloudflare will provide you with a unique URL (e.g., &lt;code&gt;&amp;lt;your-project&amp;gt;.pages.dev&lt;/code&gt;). Visit this URL to see your live blog!&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%2Fm74bqeh7fjeb2i5q4sf2.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%2Fm74bqeh7fjeb2i5q4sf2.png" alt="Deploy to CloudFlare success" width="468" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Don't forget! You might need to add your new Cloudflare Pages URL (e.g., &lt;code&gt;https://&amp;lt;your-project&amp;gt;.pages.dev&lt;/code&gt;) to your Sanity project's CORS origins list, just like you did for &lt;code&gt;localhost:3000&lt;/code&gt;, so the live site can fetch data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: Understanding GROQ &amp;amp; Nuxt DevTools
&lt;/h2&gt;

&lt;p&gt;Two extra bits of knowledge that are super helpful:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. What is GROQ? 🤔
&lt;/h3&gt;

&lt;p&gt;You saw queries like &lt;code&gt;*[_type == "post"]&lt;/code&gt; in the code. That's GROQ!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;GROQ&lt;/strong&gt; stands for &lt;strong&gt;Graph-Relational Object Queries&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;  It's Sanity's powerful, flexible query language designed specifically for JSON documents.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Why?&lt;/strong&gt; Traditional SQL or even GraphQL can be cumbersome for the deeply nested, flexible schemas often used in headless CMSs.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Value:&lt;/strong&gt; GROQ lets you easily:

&lt;ul&gt;
&lt;li&gt;  Filter documents (&lt;code&gt;[_type == "post"]&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;  Select specific fields (projections).&lt;/li&gt;
&lt;li&gt;  Follow references between documents (e.g., fetching author details along with a post).&lt;/li&gt;
&lt;li&gt;  Shape the returned JSON data exactly how your frontend needs it.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;It's worth learning the basics if you work heavily with Sanity!&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Nuxt DevTools 🛠️
&lt;/h3&gt;

&lt;p&gt;Nuxt comes with fantastic built-in developer tools that can significantly speed up debugging directly in your browser.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;How to access:&lt;/strong&gt; While your local dev server (&lt;code&gt;npm run dev&lt;/code&gt;) is running, press &lt;strong&gt;Shift + Option + D&lt;/strong&gt; (Mac) or &lt;strong&gt;Shift + Alt + D&lt;/strong&gt; (Windows/Linux) in your browser tab showing &lt;code&gt;localhost:3000&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Authentication:&lt;/strong&gt; The first time, you might see a prompt asking for an authentication code. Check the terminal where you ran &lt;code&gt;npm run dev&lt;/code&gt; – Nuxt usually prints the code there. Paste it into the browser prompt.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Features:&lt;/strong&gt; Explore components, check routes, inspect state, view composable usage, analyze payloads, and much more! It's incredibly useful for understanding what's happening under the hood. (Make sure &lt;code&gt;devtools: { enabled: true }&lt;/code&gt; is in your &lt;code&gt;nuxt.config.ts&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrapping Up &amp;amp; Your Turn!
&lt;/h2&gt;

&lt;p&gt;And there you have it! We've journeyed from setting up a Sanity.io backend and a Nuxt.js frontend to connecting them, navigating some troubleshooting, and finally deploying our blog globally using Cloudflare Pages. ✨&lt;/p&gt;

&lt;p&gt;We saw how powerful this combination is for building modern web applications, offering flexibility for content management (thanks, Sanity!), a great developer experience (go Nuxt!), and effortless, performant deployment (kudos, Cloudflare!). We also navigated a few bumps along the road, reminding us that troubleshooting is a key part of the learning process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Learnings Recap:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Sanity.io provides a flexible headless CMS experience.&lt;/li&gt;
&lt;li&gt;  Nuxt.js makes building Vue-based frontends efficient, especially with Nuxt 3 features.&lt;/li&gt;
&lt;li&gt;  Cloudflare Pages offers simple, fast, and integrated deployment for static/JAMstack sites.&lt;/li&gt;
&lt;li&gt;  GROQ is a powerful language for querying Sanity data.&lt;/li&gt;
&lt;li&gt;  Always check framework/package compatibility (Nuxt 2 vs Nuxt 3, Vue 2 vs Vue 3 components)!&lt;/li&gt;
&lt;li&gt;  Nuxt DevTools are your friend for debugging!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope this walkthrough was helpful and demystified the process a bit. Building projects like this is one of the best ways to learn!&lt;/p&gt;

&lt;p&gt;Ref:&lt;a href="https://developers.cloudflare.com/pages/tutorials/build-a-blog-using-nuxt-and-sanity" rel="noopener noreferrer"&gt;https://developers.cloudflare.com/pages/tutorials/build-a-blog-using-nuxt-and-sanity&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Now, over to you!&lt;/strong&gt; 🤔&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  What are your favorite tools for building blogs or static sites?&lt;/li&gt;
&lt;li&gt;  Have you used Nuxt.js, Sanity.io, or Cloudflare Pages before? What was your experience?&lt;/li&gt;
&lt;li&gt;  Did you encounter similar troubleshooting hurdles, especially with framework upgrades? Share your tips!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Let me know your thoughts in the comments below – I'd love to spark a discussion! Happy coding! 💻&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nuxt</category>
      <category>sanityio</category>
      <category>cloudflare</category>
      <category>webdev</category>
    </item>
    <item>
      <title>⚡️ From Zero to Deployed Portfolio &lt; 1 Hour: My Experience with Vercel &amp; Cursor</title>
      <dc:creator>Jeannie</dc:creator>
      <pubDate>Tue, 15 Apr 2025 20:00:41 +0000</pubDate>
      <link>https://dev.to/jeaniscoding/from-zero-to-deployed-portfolio-in-under-an-hour-my-experience-with-vercel-cursor-5c3i</link>
      <guid>https://dev.to/jeaniscoding/from-zero-to-deployed-portfolio-in-under-an-hour-my-experience-with-vercel-cursor-5c3i</guid>
      <description>&lt;p&gt;We've all been there: wanting to spin up a project—maybe a portfolio, a blog, or a hands-on lab for CI/CD—but dreading the initial setup slog. I recently set out to build my online portfolio, aiming to use it as a real-world IaC and CI/CD practice ground. Kill two birds with one stone, right?&lt;/p&gt;

&lt;p&gt;My plan seemed simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Create a portfolio app (fast!) using templates or AI.&lt;/li&gt;
&lt;li&gt; Get it on GitHub.&lt;/li&gt;
&lt;li&gt; Configure the infra.&lt;/li&gt;
&lt;li&gt; Build the CI/CD pipeline.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The catch? I wanted it &lt;em&gt;live&lt;/em&gt; quickly. 💥 Spoiler alert: thanks to Vercel and Cursor, I went from zero to a deployed, personalized site in about an hour. Here’s how I did it, the tools I compared, and what I learned along the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR - Key Takeaways 🎯
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vercel is FAST for Deployment:&lt;/strong&gt; It dramatically cuts down deployment time, especially for template-based projects using frameworks like Next.js.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Templates Beat Pure AI (For Now):&lt;/strong&gt; High-quality, human-designed templates often provide a better starting point for aesthetics and structure than current AI generation tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cursor Supercharges Refinement:&lt;/strong&gt; AI code editors like Cursor can significantly speed up content updates by understanding context (like reading your resume!) and suggesting code changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Killer Combo:&lt;/strong&gt; Pairing a seamless deployment platform (Vercel) with an AI-powered editor (Cursor) makes for a remarkably efficient workflow.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The Initial Goal: Portfolio Meets Practice&lt;/li&gt;
&lt;li&gt;
Choosing the Right Launchpad: Vercel vs. The World

&lt;ul&gt;
&lt;li&gt;Quick Tool Comparison&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Liftoff! Deploying with Vercel

&lt;ul&gt;
&lt;li&gt;What Vercel Handles Automatically&lt;/li&gt;
&lt;li&gt;Visualizing the Flow (Eraser.io Diagram)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Personalization Power-Up: Editing with Cursor&lt;/li&gt;

&lt;li&gt;Bonus Round: AI-Generated Favicon via ChatGPT&lt;/li&gt;

&lt;li&gt;Landed: Portfolio Live and Customized&lt;/li&gt;

&lt;li&gt;The Specific Template I Used&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Initial Goal: Portfolio Meets Practice
&lt;/h2&gt;

&lt;p&gt;My main driver was practical learning in CI/CD and IaC. Building an online portfolio offered the perfect sandbox. It's a tangible project that benefits from automation and proper infrastructure setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the Right Launchpad: Vercel vs. The World
&lt;/h2&gt;

&lt;p&gt;The first hurdle was getting the basic app structure up quickly. I looked into several options, including AI-driven platforms like Replit and Bolt, and template marketplaces like Dora. Then I stumbled upon Vercel.&lt;/p&gt;

&lt;p&gt;Initially, I browsed Vercel's templates just for inspiration, but I was quickly impressed by the quality and the ridiculously easy deployment process.&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%2Fpj3st1kdngwcmqhd8lpn.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%2Fpj3st1kdngwcmqhd8lpn.png" alt="vercel-select-template" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick Tool Comparison ⚙️
&lt;/h3&gt;

&lt;p&gt;While AI tools that generate code from descriptions are promising, I found a practical limitation: AI isn't great (yet) at grasping visual appeal or matching &lt;em&gt;my&lt;/em&gt; specific aesthetic sense, no matter how detailed the prompt. Selecting from Vercel's contributor templates felt much more efficient.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;AI Generation Focus (e.g., Replit, Bolt)&lt;/th&gt;
&lt;th&gt;Vercel Template Focus&lt;/th&gt;
&lt;th&gt;My Pick &amp;amp; Reasoning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;App Creation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Generates code based on text descriptions.&lt;/td&gt;
&lt;td&gt;Offers high-quality, curated templates from contributors.&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Vercel.&lt;/strong&gt; Templates gave a better, more aesthetically pleasing starting point for &lt;em&gt;my&lt;/em&gt; needs than the AI output I experimented with.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Efficiency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Can require significant prompt tuning &amp;amp; refinement for visuals.&lt;/td&gt;
&lt;td&gt;Quick visual selection from appealing, pre-built options.&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Vercel.&lt;/strong&gt; Faster to find a template I liked than to iterate with AI prompts to achieve the desired look and feel.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ease of Use&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Varies by platform.&lt;/td&gt;
&lt;td&gt;Exceptionally clean UI/UX, focused on a simple "Demo" -&amp;gt; "Deploy" workflow.&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Vercel.&lt;/strong&gt; The minimal clicks to deploy felt incredibly intuitive and aligned with my goal of speed.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Liftoff! Deploying with Vercel
&lt;/h2&gt;

&lt;p&gt;Vercel's process is refreshingly simple: Find a template you like, preview the "Demo," and hit "Deploy". That's it. ⚡️🚀&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%2Furrg2258r1c03rr3i1vp.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%2Furrg2258r1c03rr3i1vp.png" alt="vercel-demo-deploy" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What Vercel Handles Automatically
&lt;/h3&gt;

&lt;p&gt;Behind that single click, Vercel orchestrates a whole sequence:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Clones Repo:&lt;/strong&gt; Copies the template's GitHub repo to your account.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Builds App:&lt;/strong&gt; Runs the build process for the codebase.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Installs Dependencies:&lt;/strong&gt; Fetches and installs necessary packages.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Deploys:&lt;/strong&gt; Pushes the built app to their servers.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Assigns URL:&lt;/strong&gt; Makes the app live on the internet via DNS.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Sets up CI/CD:&lt;/strong&gt; Configures automatic deployments on pushes to the main branch.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Integrates Monitoring:&lt;/strong&gt; Provides options for analytics and performance tracking.&lt;/li&gt;
&lt;/ol&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%2F6vgurspzavj543b027se.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%2F6vgurspzavj543b027se.png" alt="vercel-deploy-result" width="800" height="916"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The deployment confirmation page even suggests potential next steps and enhancements. Exploring the dashboard reveals a rich ecosystem of integrations (MANY FREE! 🆓), like Vercel Analytics, which I enabled immediately.&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%2Fmi1nqyrp5p1j12odbky8.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%2Fmi1nqyrp5p1j12odbky8.png" alt="vercel-dashboard" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Have you explored Vercel's integrations? Which ones do you find most valuable? Let me know below! 👇&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Personalization Power-Up: Editing with Cursor ✏️
&lt;/h2&gt;

&lt;p&gt;Okay, the site was live, but it wasn't mine yet. It had placeholder text and images. Time for customization. Enter Cursor, the AI-assisted code editor.&lt;/p&gt;

&lt;p&gt;I fed Cursor my resume and asked it to update the portfolio template's content sections. It parsed the document and intelligently suggested code changes in the right places.   &lt;/p&gt;

&lt;p&gt;To maintain control and ensure accuracy (and for my own learning!), I used Cursor's diff view. This let me review each AI suggestion side-by-side with the original code, approving or rejecting changes individually before committing. It struck a great balance between AI speed and human oversight. After handling the text, I swapped out the profile picture manually. &lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus Round: AI-Generated Favicon via ChatGPT 🖼️
&lt;/h2&gt;

&lt;p&gt;One last touch: the favicon. I uploaded my new profile picture to ChatGPT and asked it to generate some favicon options with different styles. Thanks to recent advancements in AI image generation, the results were surprisingly good and gave my site a unique browser tab icon.&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%2Fml67xcthvcw6c1fglrsj.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%2Fml67xcthvcw6c1fglrsj.png" alt="chatgpt-favicon" width="800" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Landed: Portfolio Live and Customized 🎉
&lt;/h2&gt;

&lt;p&gt;The result? In roughly one hour—including the time I spent exploring the tools—I had a personalized, deployed web portfolio. Vercel handled the deployment heavy lifting, while Cursor streamlined the content integration.&lt;/p&gt;

&lt;p&gt;Check it out 👉🏻: &lt;a href="https://jean-magic-portfolio-for-next-js.vercel.app/" rel="noopener noreferrer"&gt;https://jean-magic-portfolio-for-next-js.vercel.app/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Specific Template I Used
&lt;/h2&gt;

&lt;p&gt;If you're curious, the template I started with is Magic Portfolio (&lt;a href="https://magic-portfolio.com/" rel="noopener noreferrer"&gt;https://magic-portfolio.com/&lt;/a&gt;). It's built with Next.js and uses a component library called "once-ui," which offers a modular design that makes tweaking content, layout, and visuals relatively easy. ✨ Definitely worth checking out if you need a quick portfolio base.&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%2Fyw6m4u2hw9fs0q3awpv9.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%2Fyw6m4u2hw9fs0q3awpv9.png" alt="magic-portfolio" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;I hope sharing this rapid deployment experience is helpful! It shows how combining the right tools can significantly accelerate getting projects off the ground. 🌈&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What are your favorite tools for quickly launching web apps? Share your experiences in the comments!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>vercel</category>
      <category>cursor</category>
      <category>portfolio</category>
      <category>chatgpt</category>
    </item>
    <item>
      <title>🚀 RHCSA Prep #2 - Setting Up SSH for Remote Access to RHEL</title>
      <dc:creator>Jeannie</dc:creator>
      <pubDate>Mon, 14 Apr 2025 11:33:54 +0000</pubDate>
      <link>https://dev.to/jeaniscoding/rhcsa-prep-2-setting-up-ssh-for-remote-access-to-rhel-m76</link>
      <guid>https://dev.to/jeaniscoding/rhcsa-prep-2-setting-up-ssh-for-remote-access-to-rhel-m76</guid>
      <description>&lt;p&gt;No more waiting for the GUI to load! This approach saves valuable time and creates a more authentic server management experience.&lt;/p&gt;

&lt;p&gt;One of the biggest productivity boosters in my RHEL learning journey has been setting up SSH access to my virtual machine directly from my MacBook Pro terminal. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🎯 &lt;strong&gt;In this article, you'll learn:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to configure SSH access to a RHEL virtual machine&lt;/li&gt;
&lt;li&gt;Two networking approaches: NAT with port forwarding vs. bridged networking&lt;/li&gt;
&lt;li&gt;Instructions for registering your RHEL server &lt;em&gt;(required for setup SSH daemon)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Step-by-step walkthrough on setting up SSH&lt;/li&gt;
&lt;li&gt;Troubleshooting tips for common SSH connection issues&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;Registering Your RHEL Server&lt;/li&gt;
&lt;li&gt;
Setting Up SSH on RHEL

&lt;ul&gt;
&lt;li&gt;Step 1: Install OpenSSH Server&lt;/li&gt;
&lt;li&gt;Step 2: Configure VM Networking&lt;/li&gt;
&lt;li&gt;Step 3: Test SSH Connection&lt;/li&gt;
&lt;li&gt;Step 4: Generate SSH Key&lt;/li&gt;
&lt;li&gt;Step 5: Copy SSH Key to the Remote Server&lt;/li&gt;
&lt;li&gt;Step 6: Connect to VM via SSH&lt;/li&gt;
&lt;li&gt;Step 7: Config Shortcut&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Networking Options Compared&lt;/li&gt;

&lt;li&gt;Troubleshooting Tips&lt;/li&gt;

&lt;li&gt;What's Next&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;RHEL installed in VirtualBox&lt;/li&gt;
&lt;li&gt;A MacBook Pro (though these instructions work for any host OS)&lt;/li&gt;
&lt;li&gt;Basic terminal familiarity&lt;/li&gt;
&lt;li&gt;Red Hat developer account (free)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Registering Your RHEL Server
&lt;/h2&gt;

&lt;p&gt;Before installing any packages, you'll need to register your RHEL server to access Red Hat's package repositories:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a &lt;a href="https://developers.redhat.com/" rel="noopener noreferrer"&gt;Red Hat developer account&lt;/a&gt; if you don't already have one&lt;/li&gt;
&lt;li&gt;Log into your RHEL server&lt;/li&gt;
&lt;li&gt;Run the registration command:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;subscription-manager register
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting Up SSH on RHEL
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Install OpenSSH Server
&lt;/h3&gt;

&lt;p&gt;First, we need to install and enable the SSH server on our RHEL system:&lt;/p&gt;

&lt;p&gt;Ref: &lt;a href="https://www.redhat.com/en/blog/access-remote-systems-ssh" rel="noopener noreferrer"&gt;https://www.redhat.com/en/blog/access-remote-systems-ssh&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install the OpenSSH server package&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nb"&gt;install &lt;/span&gt;openssh-server

&lt;span class="c"&gt;# Enable and start the SSH service&lt;/span&gt;
systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; sshd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This installs the SSH server and configures it to start automatically on boot.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Note:&lt;/strong&gt; I encountered an error during registration: &lt;code&gt;"Error: sqlite failure: PRAGMA optimize: database disk image is malformed"&lt;/code&gt;. Despite this, I was able to proceed with the SSH setup without issues. If you encounter similar errors, try continuing with the next steps anyway.&lt;/p&gt;
&lt;/blockquote&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%2Fr87rfv270gub8dv605md.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%2Fr87rfv270gub8dv605md.png" alt="error-after-install-openssh" width="800" height="646"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Configure VM Networking
&lt;/h3&gt;

&lt;p&gt;For SSH access, you'll need to configure networking in VirtualBox. There are two main approaches:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Port forwarding with NAT&lt;/strong&gt; (what I chose)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bridged networking&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;See difference between these two options&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I opted for port forwarding because I only need to access the VM from my MacBook, not from other devices on my network. Here's how to set it up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open VirtualBox&lt;/li&gt;
&lt;li&gt;Select your RHEL VM&lt;/li&gt;
&lt;li&gt;Go to Settings → Network → Adapter 1&lt;/li&gt;
&lt;li&gt;Make sure "NAT" is selected&lt;/li&gt;
&lt;li&gt;Click on "Port Forwarding"&lt;/li&gt;
&lt;li&gt;Add a new rule with these settings:

&lt;ul&gt;
&lt;li&gt;Protocol: TCP&lt;/li&gt;
&lt;li&gt;Host Port: Choose a port (e.g., 2222)&lt;/li&gt;
&lt;li&gt;Guest Port: 22 (standard SSH port)&lt;/li&gt;
&lt;li&gt;Leave other fields at their defaults&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&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%2F9ui4zks0120f6xveb3ox.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%2F9ui4zks0120f6xveb3ox.png" alt="virtualbox-setting-port-forwarding" width="800" height="513"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Test SSH Connection
&lt;/h3&gt;

&lt;p&gt;Now for the moment of truth! Open your terminal on your MacBook and connect to your RHEL VM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-p&lt;/span&gt; 2222 username@localhost &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;2222&lt;/code&gt; with whatever host port you configured in the port forwarding rule, and &lt;code&gt;username&lt;/code&gt; with your RHEL username.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;-v&lt;/code&gt; flag enables verbose output, which is incredibly helpful for troubleshooting if anything goes wrong. Once you've confirmed everything works, you can omit this flag for cleaner output.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Below steps are extra and for my best practice on security and working efficiency:&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Generate SSH Key
&lt;/h3&gt;

&lt;p&gt;On your host/local machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; rsa &lt;span class="nt"&gt;-b&lt;/span&gt; 4096 &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"student@loca-rhel-vm1"&lt;/span&gt;  &lt;span class="nt"&gt;-f&lt;/span&gt; ~/.ssh/student@local-rhel-vm1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-C&lt;/code&gt; flag for the comment for key file, which will be append at the end of the whole key value. You can &lt;code&gt;cat&lt;/code&gt; the key file to check.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-f&lt;/code&gt; flag for the file name you wish it to appear in your file system for easier recognization. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Check where the keys are generated. You may move the key to desired location. My practice is to under &lt;code&gt;~/.ssh&lt;/code&gt;. You will need the location in next commands.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 5: Copy SSH Key to the Remote Server
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-copy-id &lt;span class="nt"&gt;-p&lt;/span&gt; 2222 &lt;span class="nt"&gt;-i&lt;/span&gt; &amp;lt;location/filename of private key file&amp;gt; student@localhost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will prompt you for password, input the password for that user account. &lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Connect to VM via SSH
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-p&lt;/span&gt; 2222 student@localhost &lt;span class="nt"&gt;-i&lt;/span&gt; &amp;lt;location/filename of private key file&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 7: Config Shortcut
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Optional and for extra efficiency!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Create or edit &lt;code&gt;~/.ssh/config&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Host rhel-vm-student
  HostName localhost
  User student
  Port 2222
  IdentityFile &amp;lt;location of your private key generated&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then SSH with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh rhel-vm-student
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Networking Options Compared
&lt;/h2&gt;

&lt;p&gt;Here's a quick comparison of the networking options to help you decide which is best for your use case:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;NAT + Port Forwarding&lt;/th&gt;
&lt;th&gt;Bridged Networking&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Host IP used?&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;td&gt;❌ No — VM has its own IP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Needs port forwarding?&lt;/td&gt;
&lt;td&gt;✅ Yes (manually per port)&lt;/td&gt;
&lt;td&gt;❌ No (direct access)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Connect from other devices?&lt;/td&gt;
&lt;td&gt;❌ Difficult (only via host IP/port)&lt;/td&gt;
&lt;td&gt;✅ Yes (use VM's IP directly)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;td&gt;🔒 More isolated&lt;/td&gt;
&lt;td&gt;❗ Exposed to LAN/network&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Personal dev/testing, local services&lt;/td&gt;
&lt;td&gt;Network testing, server hosting&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Troubleshooting Tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Connection refused?&lt;/strong&gt; Make sure the SSH service is running: &lt;code&gt;systemctl status sshd&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication issues?&lt;/strong&gt; Verify your username and check SSH key permissions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Can't reach server?&lt;/strong&gt; Double-check your port forwarding configuration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slow connection?&lt;/strong&gt; Try disabling DNS lookups in the SSH server config&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;Success! I now have a streamlined workflow where I can connect directly to my RHEL environment from my terminal without launching the VirtualBox GUI. This setup will make all future labs and exercises much more efficient.&lt;/p&gt;

&lt;p&gt;In the next post of this series, I'll dive into essential RHEL operations and system administration tasks. Stay tuned!&lt;/p&gt;




&lt;p&gt;In this second post of my RHEL learning series, I walked through the exact steps I took to configure SSH access to a RHEL virtual machine running in VirtualBox. Whether you're studying for RHCSA certification or just exploring Red Hat's enterprise environment, this setup will make your life much easier. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Follow me for the complete RHEL Learning Journey series.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>redhat</category>
      <category>rhel</category>
      <category>rhcsa</category>
      <category>ssh</category>
    </item>
    <item>
      <title>🚀 RHCSA Prep #1 - Installing RHEL 9 VM on VirtualBox with External SSD</title>
      <dc:creator>Jeannie</dc:creator>
      <pubDate>Mon, 14 Apr 2025 10:39:18 +0000</pubDate>
      <link>https://dev.to/jeaniscoding/rhcsa-prep-1-installing-rhel-9-vm-on-virtualbox-with-external-ssd-ebc</link>
      <guid>https://dev.to/jeaniscoding/rhcsa-prep-1-installing-rhel-9-vm-on-virtualbox-with-external-ssd-ebc</guid>
      <description>&lt;p&gt;Hello, Dev Community! 👋&lt;/p&gt;

&lt;p&gt;I'm excited to kick off a new series documenting my learning journey on taking &lt;strong&gt;Red Hat Certified System Administrator&lt;/strong&gt;, with Red Hat Enterprise Linux (RHEL). &lt;/p&gt;

&lt;p&gt;I aim to make this learning journey more interactive and connect with other practitioners who share similar interests.&lt;/p&gt;

&lt;p&gt;In this series, I'll cover my experiences, challenges, solutions, and insights while exploring RHEL. Let's dive right into the first step—setting up my environment!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🎯 &lt;strong&gt;In this article, you'll learn:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to set up RHEL 9 on VirtualBox using an external SSD&lt;/li&gt;
&lt;li&gt;Solutions to common VirtualBox storage issues&lt;/li&gt;
&lt;li&gt;Practical alternatives and decision-making process&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;p&gt;⚠️ Attempt #1: VirtualBox + External SSD Storage&lt;br&gt;
🌥️ Attempt #2: Oracle Cloud Free Tier (Rocky Linux)&lt;br&gt;
🔄 Attempt #3: VMware Fusion &amp;amp; Revisiting VirtualBox&lt;br&gt;
💡 The Solution&lt;br&gt;
📋 Quick Reference &amp;amp; Decision Table&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ 1. VM Initial Setup on RHEL
&lt;/h2&gt;

&lt;p&gt;Here's what I'm working with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Host Machine&lt;/strong&gt;: MacBook Pro 13" (2020, Intel Chip)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Host OS&lt;/strong&gt;: macOS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Virtualization Tool&lt;/strong&gt;: VirtualBox 7.1.6&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guest OS&lt;/strong&gt;: RHEL 9 (x86 architecture, compatible with Intel-based Macs)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Due to limited internal storage (512GB SSD, almost full), I decided to store the ISO and Virtual Disk Image (VDI) externally on an SSD, while keeping VirtualBox installed internally.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚠️ Attempt #1: VirtualBox + External SSD Storage
&lt;/h3&gt;

&lt;p&gt;Initially, I faced a significant hurdle. After configuring VirtualBox to use the external SSD for ISO and VDI storage, the virtual machine refused to boot properly. I tried various compute and storage settings, but none resolved the issue. My suspicion was that using external storage might be causing compatibility problems within VirtualBox.&lt;/p&gt;

&lt;h3&gt;
  
  
  🌥️ Attempt #2: Oracle Cloud Free Tier (Rocky Linux)
&lt;/h3&gt;

&lt;p&gt;Frustrated with local virtualization, I explored cloud options. Oracle Cloud offers a generous Free Cloud Tier, allowing installation of Rocky Linux—a downstream rebuild of RHEL that's fully binary-compatible (1:1 compatibility).&lt;/p&gt;

&lt;p&gt;Unfortunately, I encountered another roadblock: account creation. Oracle's address and payment verification repeatedly failed. After researching online, I found this to be a common issue among many users.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔄 Attempt #3: VMware Fusion &amp;amp; Revisiting VirtualBox
&lt;/h3&gt;

&lt;p&gt;Determined, I planned to use &lt;strong&gt;VMware Fusion&lt;/strong&gt; (another popular virtualization tool for macOS). While installing VMware Fusion, curiosity led me back to troubleshooting my initial VirtualBox setup again.&lt;/p&gt;

&lt;p&gt;That's when I stumbled upon this helpful post on SuperUser: &lt;a href="https://superuser.com/questions/87221/how-can-i-mount-an-external-hard-drive-in-a-virtualbox-machine" rel="noopener noreferrer"&gt;How can I mount an external hard drive in a VirtualBox machine?&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  💡 The Solution
&lt;/h3&gt;

&lt;p&gt;Following this advice, I did the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Opened VirtualBox settings.&lt;/li&gt;
&lt;li&gt;Navigated to &lt;strong&gt;USB&lt;/strong&gt; settings.&lt;/li&gt;
&lt;li&gt;Enabled the option &lt;strong&gt;"Enable USB Controller"&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Added a new &lt;strong&gt;USB Device Filter&lt;/strong&gt; (clicking the green plus icon and selecting my external SSD).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After rebooting the virtual machine...&lt;/p&gt;

&lt;p&gt;🎉 &lt;strong&gt;IT WORKED!&lt;/strong&gt; 🎉&lt;/p&gt;

&lt;p&gt;Interestingly, the initial error messages still briefly appeared, but the VM booted successfully and RHEL 9 installation proceeded smoothly.&lt;/p&gt;

&lt;h3&gt;
  
  
  📋 Quick Reference &amp;amp; Decision Table
&lt;/h3&gt;

&lt;p&gt;Here's a detailed overview of my setup decisions along with the available alternatives, my choices, and key considerations:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Criteria&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Options Available&lt;/th&gt;
&lt;th&gt;My Choice &amp;amp; Reasoning&lt;/th&gt;
&lt;th&gt;Points to Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Host Platform&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Where to host the VM&lt;/td&gt;
&lt;td&gt;- &lt;strong&gt;On-premise&lt;/strong&gt; (local machine)&lt;br&gt;- &lt;strong&gt;Public Cloud&lt;/strong&gt; (AWS, Azure, GCP, Oracle Cloud)&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;On-premise (local)&lt;/strong&gt; – prefer local control, convenience, and no additional costs&lt;/td&gt;
&lt;td&gt;Oracle Cloud faced verification issues&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Host Machine&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hardware used&lt;/td&gt;
&lt;td&gt;- &lt;strong&gt;MacBook Pro (Intel/Apple Silicon)&lt;/strong&gt;&lt;br&gt;- &lt;strong&gt;Virtual Server Hardware&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;MBP 13" 2020 Intel&lt;/strong&gt; – available hardware, Intel-compatible with RHEL x86&lt;/td&gt;
&lt;td&gt;Intel-based Macs compatible with RHEL x86&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compute Settings&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;CPU and RAM allocation&lt;/td&gt;
&lt;td&gt;- &lt;strong&gt;Minimal&lt;/strong&gt; (e.g., 1 CPU, 2GB RAM)&lt;br&gt;- &lt;strong&gt;Recommended&lt;/strong&gt; (e.g., 2-4 CPUs, 4-8GB RAM)&lt;br&gt;- &lt;strong&gt;High-performance&lt;/strong&gt; (e.g., 4+ CPUs, 16GB+ RAM)&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;Minimal initial setup&lt;/strong&gt; – balanced performance, adjust later based on use&lt;/td&gt;
&lt;td&gt;Initial setup chosen&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Storage Settings&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;VM storage location&lt;/td&gt;
&lt;td&gt;- &lt;strong&gt;Internal SSD/HDD&lt;/strong&gt; (built-in storage)&lt;br&gt;- &lt;strong&gt;External SSD/HDD&lt;/strong&gt; (via USB/Thunderbolt)&lt;br&gt;- &lt;strong&gt;Network-attached Storage (NAS)&lt;/strong&gt;&lt;br&gt;- &lt;strong&gt;Cloud Storage&lt;/strong&gt; (remote)&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;External SSD&lt;/strong&gt; – limited internal storage availability&lt;/td&gt;
&lt;td&gt;Requires USB controller and device filter setup in VirtualBox&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Virtualization Tool&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Software for virtualization&lt;/td&gt;
&lt;td&gt;- &lt;strong&gt;VirtualBox&lt;/strong&gt; (free, cross-platform)&lt;br&gt;- &lt;strong&gt;VMware Fusion&lt;/strong&gt; (macOS specific, paid/free personal license)&lt;br&gt;- &lt;strong&gt;Hyper-V&lt;/strong&gt; (Windows-specific, built-in)&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;VirtualBox 7.1.6&lt;/strong&gt; – Free, widely adopted, extensive community support&lt;/td&gt;
&lt;td&gt;vmWare Fusion considered as alternative backup option&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Guest OS Image&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;OS and version&lt;/td&gt;
&lt;td&gt;- &lt;strong&gt;RHEL 9&lt;/strong&gt; (official Red Hat distribution)&lt;br&gt;- &lt;strong&gt;Rocky Linux 9&lt;/strong&gt; (community-supported, RHEL compatible)&lt;br&gt;- &lt;strong&gt;AlmaLinux 9&lt;/strong&gt; (community-supported, RHEL compatible)&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;RHEL 9 (x86)&lt;/strong&gt; – Official, stable, supported, free Developer Subscription&lt;/td&gt;
&lt;td&gt;Rocky Linux as alternative if RHEL licensing becomes restrictive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;License&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Licensing for OS&lt;/td&gt;
&lt;td&gt;- &lt;strong&gt;Official RHEL Subscription&lt;/strong&gt; (enterprise, paid)&lt;br&gt;- &lt;strong&gt;Developer Subscription&lt;/strong&gt; (free for personal/development use)&lt;br&gt;- &lt;strong&gt;Community-supported alternatives&lt;/strong&gt; (Rocky Linux, AlmaLinux, CentOS Stream)&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;RHEL Developer Subscription&lt;/strong&gt; – Official, free for personal/development purposes&lt;/td&gt;
&lt;td&gt;Easy registration via Red Hat Developer account&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;I'm aware there are many tools for setting up VMs, and I'd love to hear your recommendations! What virtualization tools or operating systems do you suggest? Let me know in the comments, and I'll be sure to check them out! 🐧 &lt;/p&gt;

&lt;p&gt;Stay tuned for the next post in this series, where I'll cover the detailed installation process and initial configuration of RHEL 9!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Follow me for the complete RHEL Learning Journey series! 🚀&lt;/em&gt;&lt;/p&gt;

</description>
      <category>redhat</category>
      <category>rhel</category>
      <category>rhcsa</category>
      <category>virtualbox</category>
    </item>
  </channel>
</rss>
