<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Emeruche Ikenna - Senior Frontend Web and Mobile Developer</title>
    <link>https://coleruche.com</link>
    <description>Explore expert insights and in-depth tutorials on web and mobile development.</description>
    <language>en</language>
    <lastBuildDate>Wed, 16 Sep 2026 13:10:49 GMT</lastBuildDate>
    <atom:link href="https://coleruche.com/feed.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <guid>https://coleruche.com/post/run-claude-code-free-with-cloud-models</guid>
      <title>How to Run Claude Code for Free (OpenRouter + Ollama Cloud Models)</title>
      <link>https://coleruche.com/post/run-claude-code-free-with-cloud-models</link>
      <description>In this guide, you&apos;ll learn how to run Claude Code for free by pointing it at OpenRouter&apos;s free model tier or Ollama&apos;s new cloud-hosted models.</description>
      <pubDate>Fri, 24 Apr 2026 14:55:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>Claude Code is one of the most capable AI coding tools available right now. It reads your entire codebase, writes real changes to your files, runs terminal commands, and reasons through multi-step problems all from your command line.</p>
<p>The catch is cost. Claude Code runs against Anthropic's API by default, and an agentic coding session burns through tokens fast. Every file it reads, every edit it makes, every command it runs is all being billed.</p>
<p>But then, Claude Code doesn't actually need to talk to Anthropic. It just needs something that speaks its API format. And there's a free tool that does exactly that.</p>
<h2>Option 1: Run Claude Code for Free Using OpenRouter</h2>
<h3>What is OpenRouter?</h3>
<p>OpenRouter is a platform that gives you access to dozens of AI models from different companies — Meta, Google, Alibaba, Mistral — through a single API. Many of these models have a free tier, meaning you can use them without spending anything.</p>
<p>The reason this works with Claude Code is that OpenRouter already speaks Anthropic's message format. So instead of pointing Claude Code at Anthropic's servers, you redirect it to OpenRouter, pick a free model, and everything works the same way.</p>
<p>Same interface. Same agentic workflows. Someone else's compute budget.</p>
<h2>What You'll Need</h2>
<ul>
<li>Claude Code installed (<code>npm install -g @anthropic-ai/claude-code</code>)</li>
<li>A free OpenRouter account at <a href="https://openrouter.ai">openrouter.ai</a></li>
<li>A terminal</li>
</ul>
<p>That's it. No special hardware. No GPU. Works on any machine.</p>
<h2>Step 1: Create an OpenRouter Account</h2>
<p>Go to <a href="https://openrouter.ai">openrouter.ai</a> and sign up. Verification is quick.</p>
<p>Once you're in, navigate to the <strong>API Keys</strong> section in your dashboard and create a new key. Copy it — you'll need it shortly.</p>
<h2>Step 2: Pick a Free Model</h2>
<p>In your OpenRouter dashboard, go to the <strong>Models</strong> section and filter by free. Free models are marked with a <code>:free</code> suffix in their model ID.</p>
<p>Good options for coding tasks:</p>
<ul>
<li><code>meta-llama/llama-3.3-70b-instruct:free</code> — Meta's 70B model, strong at reasoning and code</li>
<li><code>google/gemma-3-27b-it:free</code> — Google's Gemma 3, solid general performance</li>
<li><code>qwen/qwen3-8b:free</code> — Alibaba's Qwen3, good at code specifically</li>
</ul>
<p>For serious coding work, the Llama 3.3 70B free tier is the strongest option available at no cost. It will outperform most small local models by a significant margin.</p>
<p>Copy the full model ID of whichever you choose.</p>
<h2>Step 3: Configure Claude Code</h2>
<p>Open your terminal and run these three export commands, replacing the placeholders with your actual values:</p>
<pre><code class="language-bash">export ANTHROPIC_BASE_URL=https://openrouter.ai/api
export ANTHROPIC_AUTH_TOKEN=your-openrouter-api-key
export ANTHROPIC_API_KEY=""
</code></pre>
<p>A few things worth knowing:</p>
<ul>
<li><code>ANTHROPIC_BASE_URL</code> redirects Claude Code away from Anthropic and toward OpenRouter</li>
<li><code>ANTHROPIC_AUTH_TOKEN</code> is where your OpenRouter key goes</li>
<li><code>ANTHROPIC_API_KEY</code> must be set to empty — this prevents Claude Code from trying to authenticate with Anthropic directly</li>
</ul>
<p>These variables apply only to your current terminal session. If you open a new terminal window, you'll need to run them again. To make them permanent, add the three lines to your <code>~/.zshrc</code> or <code>~/.bashrc</code> file.</p>
<h2>Step 4: Launch Claude Code</h2>
<p>In the same terminal window where you set those variables, navigate to your project folder and run:</p>
<pre><code class="language-bash">claude --model meta-llama/llama-3.3-70b-instruct:free
</code></pre>
<p>Replace the model name with whichever one you chose from OpenRouter's free list.</p>
<p>Claude Code will start up and behave exactly as it normally does. You can ask it to read files, write code, run tests, debug errors — the full workflow.</p>
<h2>What to Expect</h2>
<p>Free tier models on OpenRouter have rate limits. If you hit one, you'll see an error message and need to wait a few minutes or switch to a different free model. Adding even a small credit balance to your OpenRouter account (a few dollars) removes most of this friction.</p>
<p>Performance is real. The 70B models available on OpenRouter's free tier are genuinely capable for most coding tasks. They won't match Claude Opus on complex architectural reasoning, but for writing functions, debugging, refactoring, and explaining code, they hold up well.</p>
<hr>
<h2>Option 2: Run Claude Code for Free Using OpenRouter</h2>
<p>Download Ollana at <a href="ollama.com/download">ollama.com/download</a>. It has cloud-hosted models accessible through the same interface you use for local ones.</p>
<p>Then run Claude Code with:</p>
<ol>
<li>Open Ollama and sign in. Make sure to enable cloud models.</li>
<li>Open your terminal and type in <code>ollama launch claude</code> and hit Enter.</li>
<li>Select a recommended Cloud model, and that is it.</li>
</ol>
<p>You can use Claude Code as normal. And this is a cloud model so it runs fast.</p>
<p>This is the easiest path if Ollama is already part of your workflow. The compute still happens in the cloud. It just routes through Ollama's interface.</p>
<hr>
<h2>The Bottom Line</h2>
<p>Claude Code is designed to work with a variety of models. Features like the agentic interface, file reading, and terminal commands do not depend specifically on Anthropic's models. OpenRouter and Ollama allow you to use this interface with free models that are truly capable of handling real coding tasks.</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/how-to-start-a-blog-as-a-doctor</guid>
      <title>How to Start a Blog as a Doctor</title>
      <link>https://coleruche.com/post/how-to-start-a-blog-as-a-doctor</link>
      <description>And Why It Might Be the Most Important Career Move You Make</description>
      <pubDate>Wed, 11 Mar 2026 14:55:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>There is a quiet shift happening in medicine. Clinicians — doctors, nurses, pharmacists, physiotherapists — are building audiences online. They are writing articles, posting case breakdowns, and sharing hard-won clinical insight with the world. And they are doing it not because they are bored, but because they have figured something out that traditional medical training never taught them: your knowledge has value far beyond the ward.</p>
<p>This article is about how to start a blog as a clinician, why it matters more than ever in 2025, and what happens to your career when you do.</p>
<h2>The Numbers Are Hard to Ignore</h2>
<p>Medical misinformation is at an all-time high. <a href="https://pmc.ncbi.nlm.nih.gov/articles/PMC10722559/">82% of adult social media users now report encountering false or misleading health information online</a>, and <a href="https://pmc.ncbi.nlm.nih.gov/articles/PMC11150891/">1 in 5 Americans turns to TikTok for health advice before speaking to a doctor</a>. The demand for credible clinical voices on the internet has never been greater — and most of the search results people find are written by marketers, not clinicians.</p>
<p>At the same time, research on clinicians and online content creation reveals something striking: <a href="https://journals.sagepub.com/doi/10.1177/1460458214544726">only about 1% of healthcare professionals who are online are actually producing original content</a> — writing blogs, publishing articles, building forums. The other 99% are reading, scrolling, or occasionally commenting. That gap is not closing fast. Which means if you start a blog today, you are still entering a largely uncrowded space.</p>
<p>Meanwhile, the healthtech sector is pulling clinicians into new roles faster than most people realise. <a href="https://www.marketsandmarkets.com/Market-Reports/artificial-intelligence-healthcare-market-54679303.html">The global AI in healthcare market was valued at $21.66 billion in 2025 and is projected to reach $110.61 billion by 2030</a>. These companies need clinicians — not just to advise on products, but to communicate them. They need people who understand medicine and can write, explain, and build trust with healthcare audiences. A blog is how you signal that you are one of those people.</p>
<p>And then there is burnout. <a href="https://www.advisory.com/daily-briefing/2024/01/31/physician-burnout">49% of physicians reported burnout in Medscape's 2024 survey</a> — a number that has remained stubbornly above 45% for over a decade. Many are quietly looking for what comes next, or at least for something alongside clinical practice that doesn't drain them further. Writing, for a lot of clinicians who try it, turns out to be the opposite of draining.</p>
<h2>What a Clinician Blog Actually Does For Your Career</h2>
<p>Let's be specific, because "build your personal brand" is advice that sounds good and means nothing.</p>
<p><strong>It creates a public record of your thinking.</strong> When a healthtech founder Googles your name before a call, or a journal editor looks you up before accepting your pitch, or a conference organiser tries to decide whether to invite you — what do they find? A blog gives them something real to read. It shows how you think, what you care about, and whether you can communicate.</p>
<p><strong>It opens non-traditional clinical roles.</strong> Clinical writing, clinical advising, medical affairs, healthtech consulting, policy advocacy — all of these roles exist, and all of them are growing. Most of them go to clinicians who already have a public presence. A hiring manager at a digital health startup looking for a clinical lead is not posting on LinkedIn hoping an anonymous clinician applies. They are finding the people who are already talking about the problems they are trying to solve.</p>
<p><strong>It builds a patient-facing reputation.</strong> If you run a practice or plan to, your blog is how patients decide whether to trust you before they ever book an appointment. <a href="https://rater8.com/how-patients-choose-their-doctors-2025-report/">84% of patients now check online reviews and information before choosing a new provider</a> — and <a href="https://www.inc.com/peter-roesler/new-research-shows-why-doctors-need-a-strong-online-presence.html">63% will choose one provider over another specifically because of a strong, informative online presence</a>.</p>
<p><strong>It compounds over time.</strong> A well-written article about a topic in your specialty can bring in readers for years. Unlike a tweet that disappears in 48 hours, a blog post is indexed by search engines and continues working for you long after you've moved on to writing the next one.</p>
<h2>Physicians Who Did It — And What Happened Next</h2>
<p>These are not hypothetical outcomes. They are documented stories of clinicians who started writing and watched their careers expand in ways clinical training never made possible.</p>
<p><strong>Dr. Kevin Pho — KevinMD.com</strong></p>
<p>In 2004, Dr. Kevin Pho, a primary care physician in New Hampshire, wrote a short post about a drug recall. A patient reached out to say the article had comforted them. That was the moment he realised clinicians could have a meaningful voice beyond the exam room. He kept writing. Twenty years later, KevinMD is one of the largest physician-written platforms in the world, receiving over 3 million monthly page views. What started as a blog became a speakers bureau, a coaching practice, a podcast, and a co-authored book on physician online reputation. None of that was planned. All of it followed from the decision to write consistently and in public.</p>
<p><strong>Dr. Tammie Chang — Pediatric Oncologist and Community Builder</strong></p>
<p>Dr. Tammie Chang is a practicing pediatric oncologist who used her online writing and platform to do something most clinicians consider impossible: build multiple careers simultaneously. Her work online helped her grow communities of over 125,000 verified physician members, author two bestselling books, and earn coverage in Forbes, CNN, and the Washington Post. She was named a LinkedIn Top Voice in Healthcare in 2020. She did not stop practising medicine. She expanded what medicine meant for her.</p>
<p><strong>The pattern in both stories is the same.</strong> They started writing about what they already knew. They were consistent. They let the audience find them. And opportunities — speaking, publishing, advising, building — followed the visibility.</p>
<h2>What to Write About</h2>
<p>The best clinician blogs are not textbook summaries. They are a clinician's perspective on things people are actually searching for: how a diagnosis feels from the inside, what a test result means in plain language, why a treatment works the way it does, what you would tell a patient if you had more than 10 minutes.</p>
<p>You do not need to write about everything. The most powerful blogs are narrow and consistent. Pick a lane — your specialty, a patient population you care about, the intersection of medicine and technology — and write from inside it.</p>
<p>Some starting points that tend to work:</p>
<ul>
<li>"What I wish patients knew about [condition]"</li>
<li>"What actually happens during [procedure]"</li>
<li>"How I explain [diagnosis] to my patients"</li>
<li>"Why I think AI will / won't change [area of medicine]"</li>
<li>Case discussions (anonymised, with ethical principles applied)</li>
<li>Reflections on clinical training, medical education, or the healthcare system</li>
</ul>
<p>These are not just good for your readers. They are the exact topics people are searching for.</p>
<h2>How to Set Up Your Clinician Blog</h2>
<p>This is where most clinicians get stuck — not from lack of ideas, but from the wrong mental model. A clinician blog is not a technical project. It is a professional home. You want it to look credible, load quickly, and tell visitors exactly who you are and what you do.</p>
<p>Here is what you need:</p>
<p><strong>1. A place to host your profile and writing.</strong> This is your home base. It should include your clinical background, your specialty, your credentials, and a way for people to contact or follow you. The simpler this is to set up, the sooner you will actually use it.</p>
<p><strong>2. A domain that looks like you.</strong> yourname.com or yourname.bio — not a subdomain on a platform you don't control. When you write something good, you want people to remember where it lives.</p>
<p><strong>3. A place to publish articles.</strong> This can be a blog section on your personal site, a Substack newsletter, or both. What matters is that it is yours, that it is easy to update, and that it does not require you to learn to code.</p>
<p><strong>4. A consistent publishing rhythm.</strong> One article a month is enough to start. Two is better. The goal is consistency over volume — a blog with 12 well-written articles is more useful than one with 3 brilliant ones and a year of silence.</p>
<h2>Where Ulna Fits In</h2>
<p>Ulna (ulna.bio) was built specifically for clinicians who want a professional online presence without the friction of building a website from scratch.</p>
<p>You get a personal portfolio page with your credentials, specialty, work history, and links — all in a format designed for healthcare professionals. You can add your publications, your research, your speaking engagements, your blog. You can claim a clean personal URL. And you can set it up in under 30 minutes, without touching code.</p>
<p>Think of it as the clinical equivalent of a developer's GitHub profile — a place that shows what you know, what you've done, and what you're building. When you start a blog, Ulna is where that blog lives alongside everything else that makes you credible.</p>
<p>If you want to see what it looks like, head to <a href="https://ulna.bio">Ulna</a> and set up your profile. It's free to get started, and the first thing it will show you is how complete your professional presence actually is — which, for most clinicians, turns out to be more incomplete than they expected.</p>
<h2>The Cost of Waiting</h2>
<p>Here is the thing about clinician visibility: the window does not stay open forever.</p>
<p>Every specialty has a small number of clinicians who have already built a public presence. They are the ones who get invited to advisory boards, quoted in healthtech press releases, and approached for clinical writing contracts. They are not necessarily smarter or more experienced than their peers. They are just visible.</p>
<p>The gap between "clinician with a blog" and "clinician without one" is not a gap in knowledge. It is a gap in who gets found.</p>
<p>You have spent years building clinical expertise that most people in the world will never have. A blog is how you let that expertise travel further than the rooms you work in.</p>
<p>Start small. Write what you know. Build the thing.</p>
<p><em>Ulna is a portfolio and profile builder for clinicians. If you're ready to build your professional online presence, get started at <a href="https://ulna.bio">ulna.bio</a>.</em></p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/ai-for-doctors</guid>
      <title>AI for Doctors</title>
      <link>https://coleruche.com/post/ai-for-doctors</link>
      <description>The Beginner&apos;s Guide to AI for Doctors.</description>
      <pubDate>Tue, 10 Mar 2026 14:55:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>AI will not replace doctors. But doctors who use AI will have an advantage over those who don't — in speed, in learning, and in career options. This guide gives you everything you need to get started.</p>
<hr>
<h2>1. The Most Important Skill: Prompt Engineering</h2>
<p>Prompt engineering is just knowing how to talk to AI well. The better your question, the better the answer.</p>
<p><strong>The formula: Role + Context + Format</strong></p>
<p><strong>Bad prompt:</strong>
"What's the treatment for malaria?"</p>
<p><strong>Good prompt:</strong>
"You are an infectious disease specialist. My patient is a 28-year-old pregnant woman in her second trimester with uncomplicated falciparum malaria in a chloroquine-resistant region. What is the safest first-line treatment and why? Give your answer in bullet points."</p>
<p>Same question. Completely different output. The second one is actually useful at the bedside.</p>
<p><strong>Tips:</strong></p>
<ul>
<li>Always give the AI a role ("You are a cardiologist...")</li>
<li>Add patient context (age, comorbidities, relevant history)</li>
<li>Tell it the format you want (bullet points, table, plain paragraph)</li>
<li>If the answer isn't good enough, say "be more specific" or "simplify this for a patient"</li>
</ul>
<p>Read more: <a href="https://www.coleruche.com/post/prompt-engineering-for-clinicians">Prompt Engineering for Clinicians</a></p>
<hr>
<h2>2. Tools Worth Knowing</h2>
<h3>General AI Assistants</h3>
<p>Use these for drafting letters, summarising papers, explaining diagnoses to patients, studying, and clinical reasoning.</p>
<ul>
<li><a href="https://chat.openai.com">ChatGPT</a></li>
<li><a href="https://claude.ai">Claude</a></li>
<li><a href="https://gemini.google.com">Gemini</a></li>
</ul>
<p>For clinical-specific questions with referenced literature, use:</p>
<ul>
<li><a href="https://www.openevidence.com">OpenEvidence</a></li>
</ul>
<p>OpenEvidence answers medical questions using real published studies. More reliable than general LLMs for bedside decisions.</p>
<hr>
<h3>AI Medical Scribes</h3>
<p>These tools listen to your consultation and generate a structured clinical note automatically.</p>
<ul>
<li><a href="https://www.nabla.com">Nabla</a></li>
<li><a href="https://www.abridge.com">Abridge</a></li>
<li><a href="https://www.nuance.com/healthcare/dragon-ai-clinical-solutions.html">Nuance DAX</a></li>
</ul>
<p>You stop typing mid-consultation. You look at your patient. The note writes itself.</p>
<hr>
<h3>Vibe Coding Tools (Build Without Coding)</h3>
<p>These let you describe what you want in plain English and the AI builds it for you. No coding knowledge required.</p>
<ul>
<li><a href="https://www.cursor.com">Cursor</a></li>
<li><a href="https://claude.ai">Claude</a></li>
<li><a href="https://lovable.app">Lovable</a> <em>(personal fav)</em></li>
<li><a href="https://bolt.new">Bolt</a></li>
<li><a href="https://replit.com">Replit</a></li>
</ul>
<p><strong>What you can actually build as a doctor:</strong></p>
<ul>
<li>A patient follow-up tracker for your ward</li>
<li>A triage checklist app</li>
<li>A referral letter template generator</li>
<li>A personalised study quiz based on your weak areas</li>
<li>A simple tool to explain diagnoses to patients at different literacy levels</li>
</ul>
<p>You describe it. The AI builds it.</p>
<hr>
<h3>Medical Literature &#x26; Research</h3>
<ul>
<li><a href="https://www.openevidence.com">OpenEvidence</a></li>
<li><a href="https://consensus.app">Consensus</a></li>
<li><a href="https://elicit.com">Elicit</a></li>
<li><a href="https://www.perplexity.ai">Perplexity</a></li>
</ul>
<p>Use these to search research questions and get evidence-backed summaries faster than PubMed.</p>
<hr>
<h2>3. Courses to Take</h2>
<h3>AI 101: A Practical Guide for Clinicians</h3>
<p>Free. Self-paced. Built specifically for clinicians and medical learners getting started with AI.
https://dochobbs.github.io/ai101/index.html</p>
<p>Start here if you want zero fluff and immediate practical value.</p>
<hr>
<h3>Google's Introduction to Generative AI</h3>
<p>Free. 45 minutes. Gives you a solid conceptual foundation.
https://www.cloudskillsboost.google/courses/536</p>
<p>Good for understanding what AI actually is before you start using it.</p>
<hr>
<h3>AI in Healthcare Specialization — Stanford on Coursera</h3>
<p>Paid (Coursera subscription). Structured and clinical. Built by Stanford faculty.
https://www.coursera.org/specializations/ai-healthcare</p>
<p>The most rigorous option on this list. Worth it if you want to go deep.</p>
<hr>
<h2>4. Where to Stay Updated</h2>
<ul>
<li><a href="https://gh.bmj.com/content/3/4/e000798">BMJ Digital Health</a></li>
<li><a href="https://jamanetwork.com">JAMA Network</a> <em>(search "artificial intelligence")</em></li>
<li>LinkedIn — follow clinicians and researchers working at the medicine-tech intersection</li>
</ul>
<p>The conversation is happening in public. You just have to show up to it.</p>
<hr>
<h2>5. One Rule to Never Break</h2>
<p>AI hallucinates. It can sound confident and be completely wrong. Never paste AI output directly into a patient's chart without reading and verifying it. Treat AI like a smart but occasionally unreliable colleague — useful, but not unsupervised.</p>
<hr>
<h2>Build Your Presence as a Clinician Who Gets This</h2>
<p>If you want to start showing up online as a doctor who understands where medicine is going, build a portfolio.</p>
<p><a href="https://ulna.bio?ref=coleruche-ai-for-doctors">Ulna</a> — Free clinician portfolio tool with personal domains and prebuilt templates. Built for doctors.</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/nextjs-caching-explained-03b6432f</guid>
      <title>Next.js Caching Explained</title>
      <link>https://coleruche.com/post/nextjs-caching-explained-03b6432f</link>
      <description>A complete guide to caching in Next.js — covering every layer, every API, and the best practices that actually work in production. Every Strategy You Need to Know (React cache, use cache, cacheTags &amp; More)</description>
      <pubDate>Wed, 04 Mar 2026 11:11:53 GMT</pubDate>
      <content:encoded><![CDATA[<p>Caching in Next.js has always been powerful. But since the App Router, it has also become deeply layered, sometimes confusing, and — if you get it wrong — quietly responsible for stale data, broken UIs, and slow apps.</p>
<p>This guide covers everything: React's <code>cache()</code> function, Next.js's new <code>use cache</code> directive, <code>cacheTag</code>, <code>revalidateTag</code>, <code>unstable_cache</code>, the full request lifecycle, and the mental models you need to reason about all of it confidently.</p>
<p>By the end, you will know exactly what caches exist in Next.js, when each one activates, how they interact, and the practical patterns that separate production-grade apps from the rest.</p>
<blockquote>
<p><strong>Related:</strong> If you want implementation-ready patterns, production-tested snippets, and architectural diagrams specifically for caching in Next.js App Router apps, I go much deeper in the <a href="https://emeruche.gumroad.com/l/nextjs-caching">Next.js Caching Handbook</a> — built for Next.js developers shipping real products.</p>
</blockquote>
<hr>
<h2>Why caching in Next.js is different (and harder) than you think</h2>
<p>Most developers approach caching reactively. Something is slow, so they add a cache. Something is stale, so they bust the cache. This works fine in simple apps but falls apart fast in Next.js, for one reason: <strong>there are multiple caches operating simultaneously at different layers</strong>, and they do not always know about each other.</p>
<p>Here are the four primary caches you are dealing with in a Next.js App Router application:</p>
<ol>
<li><strong>Request Memoization</strong> — deduplicates identical <code>fetch()</code> calls within a single render pass</li>
<li><strong>Data Cache</strong> — persists fetch results across requests (server-side, file-system-backed)</li>
<li><strong>Full Route Cache</strong> — stores rendered HTML + RSC payloads for static routes</li>
<li><strong>Router Cache</strong> — client-side cache of visited route segments in the browser</li>
</ol>
<p>Each one has its own lifetime, its own invalidation mechanism, and its own failure modes. Understanding what each does — and does not — cache is the foundation everything else builds on.</p>
<hr>
<h2>Layer 1: Request Memoization</h2>
<p>Request Memoization is the most misunderstood cache in Next.js, because it looks like a data cache but is not.</p>
<p><strong>What it does:</strong> During a single server render, if you call <code>fetch("https://api.example.com/user/1")</code> in three different components, Next.js only makes one actual HTTP request. The result is shared across all three.</p>
<p><strong>What it does not do:</strong> It does not persist across requests. When the next user loads the page, the memoization table is wiped and fresh fetches happen.</p>
<p><strong>Scope:</strong> Single render tree, single request.</p>
<p><strong>When it activates:</strong> Automatically, for all <code>fetch()</code> calls made with identical URLs and options during a server-side render.</p>
<p>This is why you can safely call <code>getUser()</code> at the top of multiple server components without worrying about N+1 HTTP requests. Next.js deduplicates them for you.</p>
<pre><code class="language-tsx">// Both components call the same URL — only ONE HTTP request is made
async function Header() {
  const user = await fetch('/api/me').then(r => r.json())
  return &#x3C;div>Welcome, {user.name}&#x3C;/div>
}

async function Sidebar() {
  const user = await fetch('/api/me').then(r => r.json())
  return &#x3C;div>Profile: {user.avatar}&#x3C;/div>
}
</code></pre>
<h3>React <code>cache()</code> — manual memoization for non-fetch data</h3>
<p><code>fetch()</code> gets automatic memoization. But what about database queries, SDK calls, or anything that doesn't use <code>fetch()</code>?</p>
<p>That's what <code>React.cache()</code> is for.</p>
<pre><code class="language-tsx">import { cache } from 'react'
import { db } from '@/lib/db'

export const getUser = cache(async (id: string) => {
  return db.user.findUnique({ where: { id } })
})
</code></pre>
<p>Now <code>getUser("abc")</code> called from any server component in the same render will only hit the database once. React deduplicates by function reference + serialized arguments.</p>
<p><strong>Key rules for <code>cache()</code>:</strong></p>
<ul>
<li>Only works in server components and server-side code</li>
<li>The cache is <strong>per-request</strong> — not persistent across requests</li>
<li>Arguments must be serializable (strings, numbers, plain objects)</li>
<li>The function must be defined at module scope, not inside components</li>
</ul>
<p><code>cache()</code> is best used in your data layer — create one <code>getUser</code>, one <code>getPost</code>, one <code>getCart</code>, wrap each with <code>cache()</code>, and call them freely from anywhere in the server component tree.</p>
<hr>
<h2>Layer 2: The Data Cache</h2>
<p>The Data Cache is where things get genuinely persistent. Unlike request memoization, the Data Cache <strong>survives across requests</strong> and is stored on the server (in Next.js's file-system cache or an external cache depending on your deployment).</p>
<p>By default, all <code>fetch()</code> calls in Next.js App Router are cached indefinitely in the Data Cache. This is the behavior that catches most developers off-guard when migrating from the Pages Router.</p>
<pre><code class="language-tsx">// This response is cached indefinitely by default
const data = await fetch('https://api.example.com/posts')

// Opt out of Data Cache entirely
const data = await fetch('https://api.example.com/posts', { cache: 'no-store' })

// Cache but revalidate every 60 seconds
const data = await fetch('https://api.example.com/posts', {
  next: { revalidate: 60 }
})
</code></pre>
<h3>Time-based revalidation</h3>
<p><code>next: { revalidate: N }</code> tells Next.js to treat this cache entry as stale after N seconds. On the next request after expiry, Next.js will serve the stale response immediately (so the user doesn't wait) while revalidating in the background. This is Stale-While-Revalidate behavior.</p>
<pre><code class="language-tsx">async function BlogPosts() {
  // Fresh for 10 minutes, then background-revalidated
  const posts = await fetch('/api/posts', { next: { revalidate: 600 } })
  return &#x3C;PostList posts={await posts.json()} />
}
</code></pre>
<h3>On-demand revalidation with <code>revalidatePath</code> and <code>revalidateTag</code></h3>
<p>Time-based revalidation works, but for content-driven apps you usually want to revalidate when something <em>changes</em>, not on a schedule.</p>
<p><code>revalidatePath('/blog')</code> purges all cached data for that route.</p>
<p><code>revalidateTag('posts')</code> purges all cached entries that were tagged with <code>"posts"</code>.</p>
<p>Tags are more precise and composable. Here is how you assign them:</p>
<pre><code class="language-tsx">const data = await fetch('/api/posts', {
  next: { tags: ['posts'] }
})
</code></pre>
<p>And here is how you invalidate them — typically in a Server Action or API route:</p>
<pre><code class="language-tsx">'use server'
import { revalidateTag } from 'next/cache'

export async function publishPost(id: string) {
  await db.post.update({ where: { id }, data: { published: true } })
  revalidateTag('posts') // purge all cached data tagged 'posts'
}
</code></pre>
<p>This is the pattern to reach for in CMS-backed sites, e-commerce, dashboards — any app where data changes on user action.</p>
<hr>
<h2>Layer 3: The Full Route Cache</h2>
<p>The Full Route Cache stores the <strong>rendered output</strong> of static routes — the HTML and RSC payload — on disk. This is what makes Next.js apps incredibly fast to serve: for static routes, Next.js skips rendering entirely and streams bytes directly from disk.</p>
<p>Static routes are generated at build time unless you opt into dynamic rendering. A route becomes dynamic when it uses:</p>
<ul>
<li><code>cookies()</code>, <code>headers()</code>, or <code>searchParams</code></li>
<li><code>fetch()</code> with <code>cache: 'no-store'</code></li>
<li>Any dynamic function</li>
</ul>
<p>If your route has none of these, it renders once at build time and gets cached forever (until you redeploy or revalidate).</p>
<h3>When the Full Route Cache is invalidated</h3>
<ul>
<li>On every new deployment</li>
<li>When <code>revalidatePath()</code> is called for that route</li>
<li>When a tagged fetch used on that route is invalidated via <code>revalidateTag()</code></li>
</ul>
<p>The Full Route Cache and the Data Cache are <strong>linked</strong>. When the Data Cache for a fetch used in a page is invalidated, Next.js will also regenerate the Full Route Cache for that page on the next request. This is Incremental Static Regeneration (ISR) — updated and alive in the App Router.</p>
<hr>
<h2>Layer 4: The Router Cache</h2>
<p>The Router Cache lives in the browser. When a user navigates between routes in a Next.js app, the prefetched and visited route segments are stored in memory in the client. Navigating back to a previously visited page is instant — no network request.</p>
<p><strong>Default lifetimes:</strong></p>
<ul>
<li>Static route segments: 5 minutes</li>
<li>Dynamic route segments: 30 seconds</li>
</ul>
<p>This cache exists entirely in the browser and cannot be accessed or controlled from the server. It is invalidated when:</p>
<ul>
<li>The user refreshes the page</li>
<li><code>router.refresh()</code> is called from a client component</li>
<li>A Server Action with <code>revalidatePath</code> or <code>revalidateTag</code> runs (Next.js automatically invalidates the relevant router cache entries)</li>
</ul>
<p>A common gotcha: after a Server Action updates data on the server, the Router Cache may still show stale content. Calling <code>revalidatePath()</code> inside the Server Action tells Next.js to expire the relevant router cache entries, which triggers a fresh fetch on the client.</p>
<hr>
<h2>The <code>use cache</code> directive (Next.js 15+)</h2>
<p><code>use cache</code> is the new, unified caching primitive introduced in Next.js 15 as part of the "dynamicIO" model. It is designed to replace the patchwork of <code>fetch</code> options, <code>unstable_cache</code>, and manual cache wrappers with a single, ergonomic API.</p>
<p>You can apply <code>use cache</code> to:</p>
<ul>
<li>An entire file (all exports become cacheable)</li>
<li>An individual async function</li>
<li>An async server component</li>
</ul>
<pre><code class="language-tsx">// Cache a specific function
async function getPosts() {
  'use cache'
  return db.post.findMany({ where: { published: true } })
}

// Cache an entire component
async function BlogList() {
  'use cache'
  const posts = await getPosts()
  return &#x3C;ul>{posts.map(p => &#x3C;li key={p.id}>{p.title}&#x3C;/li>)}&#x3C;/ul>
}
</code></pre>
<h3><code>cacheTag</code> — tagging <code>use cache</code> entries</h3>
<p><code>cacheTag</code> is the companion API to <code>use cache</code>. It lets you attach string tags to cached function results, enabling precise on-demand invalidation with <code>revalidateTag</code>.</p>
<pre><code class="language-tsx">import { unstable_cacheTag as cacheTag } from 'next/cache'

async function getPost(id: string) {
  'use cache'
  cacheTag(`post:${id}`, 'posts')
  return db.post.findUnique({ where: { id } })
}
</code></pre>
<p>Now <code>revalidateTag('posts')</code> invalidates all posts. <code>revalidateTag('post:abc')</code> invalidates only the post with id <code>abc</code>. You can be as granular as your use case demands.</p>
<h3><code>cacheLife</code> — controlling cache duration</h3>
<p><code>cacheLife</code> lets you set the lifetime of a <code>use cache</code> entry using named profiles or explicit values:</p>
<pre><code class="language-tsx">import { unstable_cacheLife as cacheLife } from 'next/cache'

async function getHomepageData() {
  'use cache'
  cacheLife('hours') // built-in profile
  return fetchHeavyData()
}
</code></pre>
<p>Built-in profiles: <code>'seconds'</code>, <code>'minutes'</code>, <code>'hours'</code>, <code>'days'</code>, <code>'weeks'</code>, <code>'max'</code>.</p>
<p>You can also define custom profiles in <code>next.config.ts</code>:</p>
<pre><code class="language-ts">const nextConfig = {
  experimental: {
    cacheLife: {
      editorial: {
        stale: 60 * 60,       // 1 hour
        revalidate: 60 * 60 * 4, // 4 hours
        expire: 60 * 60 * 24 * 7, // 1 week
      }
    }
  }
}
</code></pre>
<p>Then use it: <code>cacheLife('editorial')</code>.</p>
<hr>
<h2><code>unstable_cache</code> — the predecessor to <code>use cache</code></h2>
<p>Before <code>use cache</code>, <code>unstable_cache</code> was the way to cache non-fetch async functions. It is still widely used and supported.</p>
<pre><code class="language-tsx">import { unstable_cache } from 'next/cache'

const getCachedUser = unstable_cache(
  async (id: string) => db.user.findUnique({ where: { id } }),
  ['user'], // cache key segments
  {
    tags: ['users'],
    revalidate: 3600,
  }
)
</code></pre>
<p>The key differences from <code>use cache</code>:</p>
<ul>
<li><code>unstable_cache</code> wraps the function at definition time. <code>use cache</code> is applied inline.</li>
<li><code>unstable_cache</code> requires explicit key segments. <code>use cache</code> derives the key automatically from function arguments.</li>
<li><code>use cache</code> is simpler but requires <code>experimental.dynamicIO: true</code> in <code>next.config.ts</code>.</li>
</ul>
<p>For new projects on Next.js 15, prefer <code>use cache</code>. For existing projects or where <code>dynamicIO</code> is not enabled, <code>unstable_cache</code> is the right tool.</p>
<hr>
<h2>Opting out of caching</h2>
<p>Knowing how to opt out is just as important as knowing how to opt in.</p>
<pre><code class="language-tsx">// Per-fetch opt-out
fetch('/api/data', { cache: 'no-store' })

// Route-level opt-out — makes the entire route dynamic
export const dynamic = 'force-dynamic'

// Revalidation only, no persistent cache
export const revalidate = 0
</code></pre>
<p>When should you opt out?</p>
<ul>
<li>Real-time data (prices, live scores, user-specific dashboards)</li>
<li>Auth-gated pages with personalized content</li>
<li>Any route where stale data would cause functional bugs</li>
</ul>
<hr>
<h2>Common caching mistakes (and how to fix them)</h2>
<p><strong>1. Caching user-specific data globally</strong></p>
<p>Never cache responses that differ per user (session data, personalized feeds, account info) in the Data Cache or with <code>use cache</code> at the page level. Cache the data-fetching layer and pass user context in, or opt those routes out of caching entirely.</p>
<p><strong>2. Forgetting <code>revalidateTag</code> in Server Actions</strong></p>
<p>A Server Action that mutates data without calling <code>revalidateTag</code> or <code>revalidatePath</code> will leave the Data Cache and Router Cache stale. Always pair mutations with cache invalidation.</p>
<p><strong>3. Using <code>cache()</code> for persistent caching</strong></p>
<p><code>React.cache()</code> is per-request memoization, not persistent caching. Using it to "cache" a database result across requests has no effect — the result is thrown away after each render.</p>
<p><strong>4. Tagging too broadly</strong></p>
<p>If you tag every fetch with <code>'all'</code> and call <code>revalidateTag('all')</code> on every mutation, you lose all the benefits of granular invalidation. Tag specifically: <code>post:${id}</code>, <code>user:${id}</code>, <code>category:${slug}</code>.</p>
<p><strong>5. Ignoring the Full Route Cache in production</strong></p>
<p>Static routes work differently locally (<code>next dev</code> always renders dynamically) versus production (<code>next build</code>). Test caching behavior with <code>next build &#x26;&#x26; next start</code>, not just in dev mode.</p>
<hr>
<h2>A practical mental model for Next.js caching</h2>
<p>Think of it as four nested layers:</p>
<pre><code>Request
  └─ Request Memoization     (within a single render, ephemeral)
       └─ Data Cache          (across requests, persistent, server-side)
            └─ Full Route Cache (rendered HTML, per route, server-side)
                 └─ Router Cache   (browser, in-memory, per session)
</code></pre>
<p>Invalidation flows outward: when the Data Cache for a fetch is invalidated, the Full Route Cache that depends on it gets regenerated. When the Full Route Cache is updated, the Router Cache for that route gets expired on the next Server Action or navigation.</p>
<p>Cache as close to the data source as possible. Tag specifically. Invalidate on mutation. Opt out for truly dynamic content.</p>
<hr>
<h2>Summary: when to use what</h2>
<p>| Scenario | Tool |
|---|---|
| Deduplicate DB calls within a render | <code>React.cache()</code> |
| Cache fetch results across requests | <code>fetch()</code> with <code>next: { revalidate }</code> |
| Cache non-fetch async functions | <code>unstable_cache</code> or <code>use cache</code> |
| Tag-based on-demand invalidation | <code>cacheTag</code> + <code>revalidateTag</code> |
| Invalidate a whole route after mutation | <code>revalidatePath</code> |
| Skip caching for real-time data | <code>cache: 'no-store'</code> or <code>dynamic = 'force-dynamic'</code> |
| Control cache lifetime with profiles | <code>cacheLife</code> |</p>
<hr>
<h2>Going deeper</h2>
<p>This guide covers every caching concept in the Next.js App Router. But knowing the concepts and applying them correctly in a production codebase are two different things.</p>
<p>If you're building a real Next.js application and want:</p>
<ul>
<li>Architecture diagrams showing how the four cache layers interact</li>
<li>Production-ready patterns for e-commerce, SaaS, and content sites</li>
<li>Recipes for cache warming, segment-level caching, and multi-tenant apps</li>
<li>A decision tree for every caching choice you'll face</li>
<li>Code snippets you can drop straight into your app</li>
</ul>
<p>...then the <strong><a href="https://emeruche.gumroad.com/l/nextjs-caching">Next.js Caching Handbook</a></strong> is built exactly for that. It's a code-first, production-focused guide for Next.js developers who want to cache correctly from the start.</p>
<hr>
<p><em>Published by <a href="https://coleruche.com">Emeruche Ikenna</a>. If this helped you, share it with a Next.js developer who's been burned by stale cache.</em></p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/understanding-nextjs-rewrites-d207b36d</guid>
      <title>Understanding Next.js Rewrites</title>
      <link>https://coleruche.com/post/understanding-nextjs-rewrites-d207b36d</link>
      <description>Next.js rewrites let you treat URLs as stable interfaces. Learn how they work and why they matter for long-term app design.</description>
      <pubDate>Thu, 26 Feb 2026 18:00:37 GMT</pubDate>
      <content:encoded><![CDATA[<p><img src="https://ofxqeonyelozjixehdyo.supabase.co/storage/v1/object/public/images/user_2wtUuRPT5LK3kNVkguDKHD90vPe/09548a08-e6b0-48fb-98bf-b71db8cb7c08-png.png" alt=""></p>
<p>Most people use Next.js very superficially.</p>
<p>Routing, SSR, maybe API routes — and that’s it. But Next.js is not just a React framework; it’s a routing, request-handling, and application architecture layer. Many of its most powerful features live outside components and never touch JSX.</p>
<p>One of those features is rewrites.</p>
<p>Today, we’re talking about rewrites — what they are, how they work, and why they matter.</p>
<h2>What is a Rewrite in Next.js?</h2>
<p>A rewrite allows you to map an incoming request path to a different destination without changing the URL in the browser.</p>
<p>The user requests one URL.</p>
<p>Your application serves content from another.</p>
<p>The browser never knows.</p>
<p>This is fundamentally different from redirects.</p>
<p>Redirects tell the browser to make a new request.</p>
<p>Rewrites happen entirely inside Next.js.</p>
<h2><strong>Basic Rewrite Example</strong></h2>
<p>Rewrites are defined in <code>next.config.js</code></p>
<pre><code>module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog/:slug',
        destination: '/content/posts/:slug',
      },
    ]
  },
}
</code></pre>
<p>What happens here?</p>
<p>A user visits <code>/blog/nextjs-rewrites</code> and Next.js internally serves <code>/content/posts/nextjs-rewrites</code>.</p>
<p>However, the browser URL remains <code>/blog/nextjs-rewrites</code>.</p>
<p>No redirect. No reload. No visible change.</p>
<h2><strong>Why Rewrites Matter Architecturally</strong></h2>
<p>URLs are a public contract.</p>
<p>Once users, crawlers, or external systems depend on a URL, changing it becomes expensive. Rewrites let you preserve that contract while refactoring everything underneath.</p>
<p>This means:</p>
<ul>
<li>
<p>you can change folder structures freely</p>
</li>
<li>
<p>you can reorganize routes without breaking links</p>
</li>
<li>
<p>you can evolve your app incrementally</p>
</li>
</ul>
<h2><strong>API Proxying With Rewrites</strong></h2>
<p>One of the most practical uses of rewrites is API proxying.</p>
<pre><code>module.exports = {
  async rewrites() {
    return [
      {
        source: '/api/:path*',
        destination: 'https://external-service.com/:path*',
      },
    ]
  },
}
</code></pre>
<p>Now the frontend calls <code>/api/users</code> but the request is actually sent to <code>https://external-service.com/users</code></p>
<p>Why this is powerful:</p>
<ul>
<li>
<p>avoids CORS issues</p>
</li>
<li>
<p>keeps API keys server-side</p>
</li>
<li>
<p>creates a single API surface for the frontend</p>
</li>
<li>
<p>allows backend services to change without frontend changes</p>
</li>
</ul>
<p>From the client’s perspective, everything lives under <code>/api</code></p>
<h2><strong>Rewrites vs Redirects (Critical Difference)</strong></h2>
<p>Redirects:</p>
<ul>
<li>
<p>change the browser URL</p>
</li>
<li>
<p>trigger a second request</p>
</li>
<li>
<p>are visible to the user</p>
</li>
<li>
<p>affect SEO</p>
</li>
</ul>
<p>Rewrites:</p>
<ul>
<li>
<p>keep the original URL</p>
</li>
<li>
<p>resolve internally</p>
</li>
<li>
<p>are invisible to the user</p>
</li>
<li>
<p>do not trigger navigation</p>
</li>
</ul>
<p>If redirects are navigation tools, rewrites are infrastructure tools.</p>
<h2><strong>Rewrites and the Request Lifecycle</strong></h2>
<p>Rewrites run before routing.</p>
<p>This means:</p>
<ul>
<li>
<p>Next.js evaluates rewrites first</p>
</li>
<li>
<p>then resolves the final route</p>
</li>
<li>
<p>then executes page or API logic</p>
</li>
</ul>
<p>Because of this:</p>
<ul>
<li>
<p>req.url may not reflect the final destination</p>
</li>
<li>
<p>middleware logic must be tested carefully</p>
</li>
<li>
<p>assumptions about paths can break if rewrites are ignored</p>
</li>
</ul>
<p>This is one of the few “gotchas” with rewrites — they are powerful precisely because they’re invisible.</p>
<h2><strong>Conditional Rewrites</strong></h2>
<p>Rewrites can also be conditional.</p>
<p>Example based on headers:</p>
<pre><code>{
  source: '/dashboard',
  has: [
    {
      type: 'header',
      key: 'x-admin',
      value: 'true',
    },
  ],
  destination: '/admin/dashboard',
}
</code></pre>
<p>Same URL. Different destination. Different behavior.</p>
<p>This enables:</p>
<ul>
<li>
<p>role-based routing</p>
</li>
<li>
<p>multi-tenant applications</p>
</li>
<li>
<p>internal feature flags</p>
</li>
<li>
<p>environment-based routing</p>
</li>
</ul>
<p><strong>Why Rewrites Are Underrated</strong></p>
<p>Rewrites don’t live in components.</p>
<p>They don’t affect UI.</p>
<p>They don’t announce themselves.</p>
<p>But they:</p>
<ul>
<li>
<p>decouple URLs from implementation</p>
</li>
<li>
<p>enable safe refactors</p>
</li>
<li>
<p>turn Next.js into a lightweight gateway</p>
</li>
<li>
<p>push routing decisions closer to infrastructure</p>
</li>
</ul>
<p>Once you understand rewrites, you stop thinking of URLs as file paths and start treating them as interfaces.</p>
<p><strong>Final Thought</strong></p>
<p>Rewrites allow Next.js apps to grow, migrate, and evolve without breaking users or clients. If you’re building anything beyond a small project, rewrites are not optional — they’re foundational. Most people never go past the surface of Next.js.</p>
<p>Rewrites are one of the first features that show you how deep it actually goes.</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/prompt-engineering-for-clinicians</guid>
      <title>Prompt Engineering for Clinicians: How Doctors Can Get Better, Safer Answers From AI</title>
      <link>https://coleruche.com/post/prompt-engineering-for-clinicians</link>
      <description>A practical guide to prompt engineering for clinicians — how doctors can ask better questions, reduce AI errors, and get safer, more clinically useful answers from AI tools.</description>
      <pubDate>Wed, 28 Jan 2026 14:55:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>AI tools like ChatGPT are increasingly being used by clinicians for learning, documentation support, and clinical preparation. Yet many doctors walk away disappointed, unsure, or sceptical because the answers feel vague, generic, or unsafe.</p>
<p>This usually isn’t because the AI is “bad” but because the questions are underspecified.</p>
<p>This article explains <strong>prompt engineering for clinicians</strong>: what it actually means, why it matters in medical contexts, and how doctors can use AI tools more safely and effectively in everyday clinical workflows.</p>
<h2>What Is Prompt Engineering (Technically)?</h2>
<p>Prompt engineering is <strong>the deliberate structuring of inputs to an AI system to guide its reasoning, scope, and output</strong>.</p>
<p>In simpler terms:</p>
<blockquote>
<p>AI systems respond based on <em>how</em> you ask, <em>what context</em> you provide, and <em>what constraints</em> you set.</p>
</blockquote>
<p>For clinicians, this is critical. Medicine is contextual, probabilistic, and safety-sensitive. A vague prompt can easily lead to:</p>
<ul>
<li>Overly general advice</li>
<li>Missing contraindications</li>
<li>Recommendations that don’t apply to your region or patient population</li>
</ul>
<p>Prompt engineering is not about tricks or shortcuts. It is about translating <strong>clinical reasoning</strong> into a format AI systems can interpret.</p>
<h2>Why This Matters in Clinical Practice</h2>
<p>Clinical decisions are rarely universal. Age, pregnancy status, comorbidities, guideline differences, and resource availability all influence care.</p>
<p>If these factors are not explicitly stated, AI systems will make assumptions. Those assumptions may be incorrect, outdated, or unsafe.</p>
<p>Good prompting reduces this risk by:</p>
<ul>
<li>Narrowing the scope of responses</li>
<li>Improving relevance</li>
<li>Highlighting uncertainty</li>
<li>Making outputs easier to verify</li>
</ul>
<h2>Core Principles of Prompt Engineering for Clinicians</h2>
<p>Below are practical, repeatable guidelines clinicians can apply immediately.</p>
<h3>1. Clearly Define the Role of the AI</h3>
<p>AI systems respond differently depending on how they are positioned. If no role is defined, responses default to general educational explanations.</p>
<p><strong>Instead of asking:</strong></p>
<blockquote>
<p>What is the treatment for asthma?</p>
</blockquote>
<p><strong>Ask:</strong></p>
<blockquote>
<p>You are a clinical decision support assistant helping a practicing physician. Summarise first-line management of asthma.</p>
</blockquote>
<p><strong>Why this works:</strong><br>
Defining the role signals that the response should be clinically framed, concise, and practice-oriented rather than patient-facing or generic.</p>
<hr>
<h3>2. Provide Patient-Specific Context</h3>
<p>Clinical recommendations depend heavily on patient characteristics. Without context, AI systems must guess.</p>
<p><strong>Instead of asking:</strong></p>
<blockquote>
<p>What antibiotics treat UTI?</p>
</blockquote>
<p><strong>Ask:</strong></p>
<blockquote>
<p>Adult female, 28 years old, non-pregnant, no known drug allergies, uncomplicated UTI. Summarise first-line antibiotic options.</p>
</blockquote>
<p><strong>Why this works:</strong><br>
Age, pregnancy status, allergies, and complexity level dramatically change management. Explicit context narrows the response and improves safety.</p>
<hr>
<h3>3. Specify Guidelines and Geographic Context</h3>
<p>Medical practice varies across countries, institutions, and guideline bodies. AI systems do not automatically know which standard applies to you.</p>
<p><strong>Instead of asking:</strong></p>
<blockquote>
<p>What’s the management of hypertension?</p>
</blockquote>
<p><strong>Ask:</strong></p>
<blockquote>
<p>Based on current international guidelines, summarise first-line management of hypertension in adults, and note where practice may vary by region.</p>
</blockquote>
<p><strong>Why this works:</strong><br>
This reduces outdated recommendations and highlights where local practice or resources may change management.</p>
<hr>
<h3>4. Add Constraints and Safety Signals</h3>
<p>Unconstrained prompts can lead to long, unfocused answers that miss clinical red flags.</p>
<p><strong>Instead of asking:</strong></p>
<blockquote>
<p>Explain this lab result.</p>
</blockquote>
<p><strong>Ask:</strong></p>
<blockquote>
<p>Explain this lab result, include normal ranges, common causes, and red flags that require urgent clinical review.</p>
</blockquote>
<p><strong>Why this works:</strong><br>
Constraints structure the output and force the model to surface safety-critical information.</p>
<hr>
<h3>5. Use Follow-Up Prompts to Refine Reasoning</h3>
<p>Clinical reasoning is iterative. One answer is rarely sufficient.</p>
<p>After an initial response, follow up with questions such as:</p>
<ul>
<li>What are common contraindications?</li>
<li>What uncertainties or grey areas exist?</li>
<li>What findings would change management?</li>
</ul>
<p><strong>Why this works:</strong><br>
AI performs best when guided step-by-step, similar to a clinical discussion rather than a single exam-style question.</p>
<hr>
<h2>How Clinicians Should Use AI (and How Not To)</h2>
<p>AI tools should be used as:</p>
<ul>
<li>Learning aids</li>
<li>Documentation support</li>
<li>Clinical preparation tools</li>
<li>Patient education drafting assistants</li>
</ul>
<p>They should <strong>not</strong> replace:</p>
<ul>
<li>Clinical judgement</li>
<li>Local protocols</li>
<li>Formal guidelines</li>
<li>Supervision or escalation pathways</li>
</ul>
<p>Prompt engineering improves usefulness, but verification remains essential.</p>
<h2>Common Mistakes to Avoid</h2>
<ul>
<li>Asking overly broad questions</li>
<li>Omitting patient context</li>
<li>Ignoring geographic or guideline differences</li>
<li>Treating AI output as authoritative</li>
<li>Skipping follow-up clarification prompts</li>
</ul>
<h2>Further Learning</h2>
<ul>
<li><a href="https://medicalfuturist.com/prompt-engineering-11-tips-to-craft-great-chatgpt-prompts">Prompt Engineering For Healthcare: 11 Tips To Craft Great ChatGPT Prompts</a></li>
<li><a href="https://pmc.ncbi.nlm.nih.gov/articles/PMC12439060/">Prompt Engineering in Clinical Practice: Tutorial for Clinicians</a></li>
<li><a href="https://medium.com/ai-disruption/prompt-engineering-in-healthcare-ai-revolutionizing-diagnostics-and-patient-communication-647a1851ac12">Prompt Engineering in Healthcare AI: Revolutionizing Diagnostics and Patient Communication</a></li>
<li><a href="https://www.linkedin.com/posts/robert-pearl-md_doctors-already-know-that-patients-are-asking-activity-7390086228995600384-4g5r/">LinkedIn post by Dr Robert Pearl</a></li>
<li><a href="https://www.nytimes.com/2025/10/30/well/chatgpt-health-questions.html">Asking ChatGPT for Medical Advice? Here’s How to Do It Safely.</a></li>
<li><a href="https://time.com/7321821/chatgpt-ai-how-to-use-for-health-safely/">9 Doctor-Approved Ways to Use ChatGPT for Health Advice</a></li>
</ul>
<h2>Videos</h2>
<ul>
<li><a href="https://www.youtube.com/watch?v=4SEAC2N5S7Q">Prompt Engineering in Medicine: How Doctors Use AI to Work Smarter</a></li>
<li><a href="https://www.youtube.com/watch?v=VmALt0xnbSU">Prompt Engineering for Healthcare by Dr Alex Dummett</a></li>
<li><a href="https://www.youtube.com/watch?v=YdneXI8h_ws">Master Prompt Engineering for Physicians: How to get accurate AI answers every time</a></li>
<li><a href="https://www.youtube.com/watch?v=WJYlv7cnXHA">Prompt Engineering in Healthcare</a></li>
</ul>
<h3>Other notable readings</h3>
<ul>
<li><a href="https://dochobbs.github.io/ai101/index.html">AI 101: A Self-Paced Guide to AI in Medicin</a></li>
<li><a href="https://www.who.int/news/item/18-01-2024-who-releases-ai-ethics-and-governance-guidance-for-large-multi-modal-models">WHO Guidance on Ethics and Governance of AI in Health</a></li>
<li><a href="https://www.fda.gov/medical-devices/software-medical-device-samd/artificial-intelligence-and-machine-learning-software-medical-device">FDA: AI/ML in Medical Software</a></li>
</ul>
<h2>Final Thoughts</h2>
<p>Prompt engineering is simply the skill of translating clinical thinking into structured questions AI systems can respond to safely.</p>
<p>As AI becomes embedded in documentation systems, decision support tools, and patient-facing platforms, <strong>clinical AI literacy will increasingly be part of modern medical practice</strong>.</p>
<p>Learning how to ask better questions is the first step.</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/seo-for-llm-how-to-make-your-website-discoverable-d7e1be60</guid>
      <title>SEO for LLM: How to Make Your Website Discoverable by AI &amp; LLMs</title>
      <link>https://coleruche.com/post/seo-for-llm-how-to-make-your-website-discoverable-d7e1be60</link>
      <description>Optimize your website for AI and LLM discoverability with proven SEO techniques that help search engines and AI models find your content</description>
      <pubDate>Mon, 01 Dec 2025 22:30:56 GMT</pubDate>
      <content:encoded><![CDATA[<p><img src="https://cdn-images-1.medium.com/max/1024/1*2ugdeu2yNJCJNxiD0DRWsQ.png" alt=""></p>
<p>Image generated by nano-banana</p>
<p>Let us address and understand two key concepts:</p>
<h4>Traditional SEO</h4>
<p>Traditional SEO is the practice of optimizing webpages to rank higher on search engines using keywords, metadata, backlinks, and technical performance. Its goal is to improve visibility in SERPs (Search Engine Result Pages) when users type queries into search engines like Google and Bing.</p>
<h4>LLM SEO</h4>
<p>LLM SEO is the practice of structuring content so large language models like ChatGPT, Gemini, Claude, etc can easily understand, recall, and reference it in conversational answers. It emphasizes clarity, semantic richness, and strong entity signals instead of traditional ranking factors.</p>
<p>A couple of years ago, developers, marketers and website owners never had to worry about this topic. But all that has changed since the rise and wide adoption of generative AI and <a href="https://www.redhat.com/en/topics/ai/what-are-large-language-models?ref=coleruche.com">large language models (LLMs)</a>. Before the introduction of LLMs, web users relied primarily on search engines like Google and Bing to find information on the internet, and these returned just links to webpages. For years, developers and marketers have understood and focused more on this: making their sites searchable and indexable by search engine crawlers like Googlebot. But with AI tools like ChatGPT, Perplexity, and Claude, they don’t just search. They <em>answer</em> in human language — and can occasionally cite links as references. And this is why this matters. Users mostly now ask AI instead of Googling.</p>
<p>So now, it is important for web developers and owners to understand and know how to make their sites and pages “findable” by these AI tools. And that is essentially what we are here for.</p>
<blockquote>
<p><strong>Related:</strong> If you’re building with Next.js and want implementation-ready patterns, I go much deeper into dynamic sitemaps, JSON-LD, and llms.txt for the App Router in my <a href="https://store.coleruche.com/l/nextjs-llm-seo-handbook?utm_source=coleruche&#x26;utm_campaign=llm_seo_article">Next.js LLM SEO Handbook</a>.</p>
</blockquote>
<p>But before we proceed, let us take a step back to first understand how search engines differ from LLM-based systems.</p>
<h3>How does LLM search work?</h3>
<p><a href="https://help.openai.com/en/articles/8868588-retrieval-augmented-generation-rag-and-semantic-search-for-gpts?ref=coleruche.com">RAG</a> (Retrieval-Augmented Generation) is the foundational approach powering most AI search tools.<br>
When you ask AI like ChatGPT, Claude, Perplexity, etc a question, search works by combining two powerful operations: <strong>retrieval</strong> and <strong>reasoning</strong>. Unlike traditional search engines, they do not match keywords. Instead, an LLM first interprets your question semantically. This means the model is not just looking at the <em>exact words</em> you typed. It’s trying to understand the <strong>meaning behind your question</strong>. It is trying to understand intent, context, entities, and relationships.</p>
<blockquote>
<p>“Unlike keyword search, which looks for exact word matches, semantic search finds conceptually similar content — even if the exact terms don’t match."</p>
<p>— Open AI on semantic search</p>
</blockquote>
<p>Let’s break it down:</p>
<h4><strong>Understanding intent, not keywords</strong></h4>
<p>Traditional search matches exact words while LLM semantic understanding interprets <em>what you actually want.</em> For e.g., “hypertension guideline update” becomes <em>“latest official hypertension diagnosis or treatment recommendations.”</em> It focuses on intent, not phrasing.</p>
<h4><strong>Understanding context and entities</strong></h4>
<p>LLMs consider the surrounding conversation and real-world entities.<br>
“What are the side effects?” refers to the drug previously discussed.<br>
“What did Apple announce this week?” is understood as a company-related news query, not fruit, and “this week” means recent information.</p>
<h4><strong>Understanding synonyms, relationships and variations</strong></h4>
<p>Semantic search recognizes meaning equivalents:<br>
“update” → “latest changes,”<br>
“guideline” → “recommendation,”<br>
“hypertension” → “high blood pressure.”<br>
This lets it find relevant content even when wording differs.</p>
<h4><strong>Reformulating the query for better retrieval</strong></h4>
<p>After understanding meaning, the LLM generates improved search queries like:<br>
“latest WHO hypertension guideline 2023/2024,”<br>
“recent changes in high blood pressure management,”<br>
“hypertension treatment recommendations site:gov.”<br>
These richer queries only work because the model understands the underlying intent.</p>
<p>It then rewrites your query into multiple optimized forms, firing off parallel searches across the web, databases, or specialized sources. This produces a pool of potentially relevant documents that go far beyond what a single query would surface.</p>
<p><img src="https://cdn-images-1.medium.com/max/645/1*5JbYX831Y698TO_N6ZkCcQ@2x.jpeg" alt="ChatGPT rewrites your questions for better search results"></p>
<h4>Putting it all together</h4>
<p>After gathering results, the system proceeds to aggressively filter for relevance, recency, authority, and uniqueness. Each document is broken into smaller chunks and converted into embeddings (numerical representations of meaning). Using vector similarity search, the system selects the most relevant chunks that match the true intent of your question, and not just your exact words. These chunks are then fed into the LLM alongside your query, allowing the model to read, compare, and synthesize information grounded in actual sources.</p>
<h3>The connection between LLM and Traditional search</h3>
<p>LLM search relies heavily on semantic understanding, entity recognition, and query reformulation. But it can only apply these abilities to <strong>content it can actually retrieve</strong>. If your site isn’t indexed by Google, Bing, or another major traditional search partner, the LLM has nothing to semantically interpret, rewrite, or reason over. In other words, even the smartest AI search systems can’t surface content they can’t access. This is why SEO and proper indexing are essential: <em>if search engines can’t see you, LLMs can’t either</em>.</p>
<h3>Traditional SEO vs “LLM SEO” (AI‑Search Optimization)</h3>
<p>I believe it is important to note that LLM SEO — also called a few other fancy words like GEO (<a href="https://www.coleruche.com/post/what-is-generative-engine-optimization-29b72a24">Generative Engine Optimization</a>), AEO (AI Engine Optimization), LLMO (Large Language Model Optimization) — is basically just traditional SEO but going an extra length to optimize content to be found by LLMs and AI search engines.</p>
<p>You cannot build on LLM SEO without understanding and building on traditional SEO first. And most of the time, if you paid enough attention to getting the traditional SEO for your site right, then you have little to nothing extra to do in order to be discovered by AI.</p>
<p><img src="https://cdn-images-1.medium.com/max/1024/0*2Xe63CKyKTeaM9U4" alt=""></p>
<p>Credit: Vercel</p>
<p>This means the fundamentals of classic SEO remain essential for getting your pages and content discovered in the first place. As explained in Jenny Ouyang’s article <a href="https://buildtolaunch.substack.com/p/seo-for-ai-how-to-make-your-product-discoverable-by-llms"><em>SEO for AI: How to Make Your Product Discoverable by LLMs</em></a>, if your content isn’t indexed by search engines, it’s often invisible to LLMs.</p>
<p>Here are the foundational SEO concepts that LLM SEO builds upon:</p>
<p><strong>1. Crawlability and indexability</strong><br>
Googlebot, Bingbot, and partner crawlers still determine whether your content enters the search index that LLMs borrow from.</p>
<p><strong>2. Clean HTML structure and metadata</strong><br>
Clear titles, meta descriptions, and semantic HTML help both search engines and LLMs interpret your content.</p>
<p><strong>3. Quality, helpful content</strong><br>
Traditional SEO’s “helpful content” guidelines apply strongly in the AI era. LLMs prioritize pages with strong explanations, clear definitions, and well-structured writing.</p>
<p><strong>4. Backlinks and authority signals</strong><br>
Authority still matters. Pages referenced by other reputable websites are more likely to rank in Google and in turn, more likely to be cited by LLMs.</p>
<p><strong>5. Sitemap and <code>robots.txt</code> configuration</strong><br>
Submitting a sitemap to Google and Bing ensures your pages are findable by the search infrastructure that LLMs depend on. Basic robots.txt rules still govern crawler access.</p>
<p><strong>6. Fast page performance</strong><br>
Search engines and AI crawlers both favor pages that load <em>fast</em>. As noted by <a href="https://vercel.com/blog/how-were-adapting-seo-for-llms-and-ai-search?utm_source=coleruche.com">Vercel</a>, slow, JS-heavy pages risk being partially invisible.</p>
<p>If you have these in place, you are almost good to go.</p>
<h3>What are the actionable steps to improve LLM SEO?</h3>
<p>Here are in-depth practices and checklists that will guide you to ensure AI and LLMs can find and reference your content easily:</p>
<h4>1. Ensure your site is crawlable and indexable</h4>
<p>Crawl-ability and index-ability are mostly managed by two files — <code>robots.txt</code> and <code>sitemap.xml</code>.</p>
<p>A <code>robots.txt</code> file is a simple text file placed at the root of a website (e.g https://www.example.com/robots.txt) to tell web crawlers which pages or directories they can or cannot access. It uses rules like User-agent, Disallow, and Allow to guide search engine bots, helping manage crawl budget, reduce server load, and prevent unnecessary crawling of non-public or irrelevant sections. While useful for SEO and site organization, it’s not a security tool and blocked pages can still appear in search results if other sites link to them.<br>
Below is a <code>robots.txt</code> snippet gotten from my <a href="https://coleruche.com/robots.txt">personal website</a>:</p>
<pre><code>User-Agent: *
Allow: /
Sitemap: https://coleruche.com/sitemap.xml
</code></pre>
<p>Above, I am just letting web crawlers know that I am allowing <strong>all user agents/bots</strong> (User-Agent parameter) to crawl <strong>all web pages</strong> on my website (Allow parameter) for any informtion or context. To make it easier for them to know the different pages I have on the website, I am also pointing them to the location of my sitemap.</p>
<p>A <code>sitemap.xml</code> is an XML file that lists all the important pages of a website to help search engines understand its structure and discover content efficiently. It acts like a map of your site, telling crawlers which URLs exist, how often they’re updated, and how important they are relative to other pages. Like a <code>robots.txt</code>, the sitemap file should also be located at the root of the website (e.g <a href="https://www.example.com/sitemap.xml)">https://www.example.com/sitemap.xml)</a></p>
<p>If you have a dynamic website — like a blog or documentation website — where the content and pages change over time (new pages are added, removed or updated frequently), then it is advisable to generate the sitemap dynamically.</p>
<blockquote>
<p><strong>Related:</strong> In the <a href="https://store.coleruche.com/l/nextjs-llm-seo-handbook?utm_source=coleruche&#x26;utm_campaign=llm_seo_article">Next.js LLM SEO Handbook</a>, I show step‑by‑step how to wire up dynamic <code>sitemap.xml</code> and JSON-LD generation from your content so AI crawlers and search engines can reliably discover every page.</p>
</blockquote>
<p>Remember to submit sitemap.xml to both <strong>Google Search Console</strong> and <strong>Bing Webmaster Tools</strong>.</p>
<h4>2. Use SSR or SSG and avoid CSR-only sites</h4>
<p>AI crawlers like ChatGPT and Claude don’t execute JavaScript, and this is important to know because for your content to be discovered by LLMs, it has to be server-rendered.</p>
<blockquote>
<p>“Our research with Vercel highlights that AI crawlers, while rapidly scaling, continue to face significant challenges in handling JavaScript and efficiently crawling content. As the adoption of AI-driven web experiences continues to gather pace, brands must ensure that critical information is server-side rendered and that their sites remain well-optimized to sustain visibility in an increasingly diverse search landscape.”</p>
<p>— Ryan Siddle, Managing Director of MERJ</p>
</blockquote>
<p>You can use rendering techniques like <a href="https://vercel.com/blog/how-to-choose-the-best-rendering-strategy-for-your-app">SSRs and SSGs</a> and avoid React SPAs and CSR by all means, except for non-trivial, supporting content like comments, likes, etc.</p>
<p>To view how crawlers may vie your site, test pages with a simple command:<br>
curl https://yoursite.com<br>
You can also load the page in a browser, open up the browser console and disable JavaScript. Then navigate to the Source tab and reload the page. If no meaningful content shows, AI crawlers won’t see it.</p>
<h4>3. Add structured data (JSON-LD)</h4>
<p><strong>Structured data</strong> is extra, machine-readable information you add to a webpage to help search engines clearly understand what the page is about. It describes key details like the type of content, product information, author, ratings, prices, events, FAQs, etc.</p>
<p><strong>JSON-LD (JavaScript Object Notation for Linked Data)</strong> is the most common and recommended format for adding structured data to web pages. It’s placed inside a  tag in the page’s HTML and doesn’t affect the visible content, making it easy to manage and update. JSON-LD uses clean, nested key-value pairs to describe entities and their relationships, helping search engines like Google, Bing, and AI search systems better understand context and meaning, which ultimately boosts visibility, relevance, and eligibility for AI search features.</p>
<p>Here is a snippet of a JSON-LD for a blog post with schema @BlogPosting</p>
<pre><code>&#x3C;script type="application/ld+json">{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "headline": "How to Make Your Website Discoverable by AI &#x26; LLMs",
  "description": "The articles description goes here",
  "author": {
    "@type": 'Person',
    name: 'Emeruche Ikenna',
  },
}
&#x3C;/script>
</code></pre>
<p>Other schema types include <code>Article</code>, <code>FAQPage</code>, <code>Product</code>, <code>Person</code>.<a href="https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data">Learn more</a> about structured data and <a href="https://json-ld.org/">JSON-LD</a>.</p>
<h4>4. Create clean, semantic HTML</h4>
<p>LLMs prefer content that is:</p>
<ul>
<li>
<p>well-sectioned with <code>&#x3C;h1></code>, <code>&#x3C;h2></code>, <code>&#x3C;h3></code> with good heirarchy</p>
</li>
<li>
<p>logically grouped into topic clusters and avoid large walls of text</p>
</li>
<li>
<p>use bullet points and numbered listings</p>
</li>
<li>
<p>readable even without CSS or JS</p>
</li>
<li>
<p>dense with meaning, low on fluff</p>
</li>
</ul>
<p>Clear structure improves <strong>semantic similarity retrieval</strong>, the core of RAG systems.</p>
<h4>5. Write concise summaries at the top of your pages</h4>
<p>LLMs rely heavily on:</p>
<ul>
<li>
<p>opening paragraphs</p>
</li>
<li>
<p>abstract-like summaries</p>
</li>
<li>
<p>definitions and context at the top</p>
</li>
</ul>
<p>These sections become the “embedding anchor” that determines how your content is recalled.</p>
<h4>6. Build internal linking across related topics</h4>
<p>Internal links help LLMs understand category structure, topic relationships, and conceptual clusters. This increases your retrieval score during AI search.</p>
<p>For example, you should have a “related articles” sections that link to other articles that may be similar, having hyperlinked texts in an article that references another article on your blog, or having interlinked blog series.</p>
<h4>7. Add an llms.txt file (emerging standard)</h4>
<p>An <code>llms.txt</code> file is an emerging, unofficial proposal that aims to give website owners a way to signal how they prefer their content to be used by AI models.</p>
<p>It is similar in spirit to <code>robots.txt</code>, but focused on LLM training, indexing, and dataset inclusion. Although the idea has gained attention after early discussions from projects like <em>llm-api</em> and posts from <em>Hacker News</em> and <em>The Verge</em> examining AI data governance, there is still significant debate about its real-world effectiveness, since no major AI company currently treats it as a binding standard. Regardless, adding an the file carries no downside: it doesn’t interfere with normal SEO, it’s easy to implement, and it publicly documents your preferences around AI usage in a transparent, machine-readable way.</p>
<p>While the ecosystem evolves, <code>llms.txt</code> is seen as a “no harm, no foul” option for creators who want to stake out clear expectations for how their content should be consumed by LLMs.</p>
<p>Here is a sample snippet:</p>
<pre><code>site_title: Your Site Name
site_description: A concise description of your website's purpose.

allow: openai
allow: perplexity

disallow_training: all
allow_snippets: all

require_attribution: true
</code></pre>
<p><a href="https://llmstxt.org/">Learn more</a> about the <code>llms.txt</code> proposal.</p>
<h4>8. Optimize performance and time-to-first-byte</h4>
<p>AI crawlers have much shorter timeouts than browsers. If your server responds slowly, they simply abandon the request, meaning parts of your site may never get indexed.</p>
<p>Improve by focusing on:</p>
<ul>
<li>
<p>caching (CDN, edge functions)</p>
</li>
<li>
<p>HTML delivery speed</p>
</li>
<li>
<p>image compression</p>
</li>
<li>
<p>code-splitting (without harming SSR)</p>
</li>
</ul>
<p>Fast backends lead to more complete crawls.</p>
<h4>9. Maintain content freshness</h4>
<p>LLMs prioritize content that remains current and valuable over time. This means regularly updating pages with new insights or corrections, incorporating the latest statistics, facts, and data points, and maintaining evergreen articles that are periodically refreshed with relevant examples. Consistently fresh content enhances both indexing frequency and retrieval accuracy.</p>
<h4>10. Get external citations and backlinks</h4>
<p>AI-powered systems prioritize content that demonstrates both popularity and relevance, much like traditional SEO. To build this authority involves creating meaningful connections. These connections can be between related pages on your own site (as described in <em>6. Build internal linking across related topics</em>) and gaining references from niche directories, forums, and specialized blogs. Additionally, promoting your content through newsletters, social media, and backlinks from trusted sources amplifies its reach and credibility. While AI may evaluate these signals differently than Google, the underlying principle of trust and authority remains consistent across platforms.</p>
<h4>11. Test your site in AI models regularly</h4>
<p>Ask Perplexity or ChatGPT with browsing enabled to analyze your website by requesting a summary of its content. Ask, specifically, what the page contains, and verifying whether it loads correctly. This process helps ensure that AI models can access and interpret your site’s information accurately, highlighting any potential issues with visibility or rendering. If the model is unable to see the content, it indicates a problem that needs to be addressed, such as server-side rendering, crawlability, or indexing issues. Regular testing with AI tools provides valuable feedback to maintain your site’s accessibility and discoverability.</p>
<h3>In conclusion</h3>
<p>AI-powered search and LLM SEO are transforming how websites and contents are discovered and referenced. Get traditional SEO fundamentals right (crawlability, clean HTML, quality content, and authority), and by building on it, developers can ensure their content remains visible to both search engines and AI systems.</p>
<p>LLM SEO adds an extra layer, emphasizing <strong>structured data, server-side rendering, internal linking, and emerging standards like <code>llm.txt</code></strong> to maximize discoverability. Regular testing with AI tools and maintaining content freshness further strengthen a site’s accessibility in the evolving AI landscape. Integrating these strategies ensures that your content not only reaches a wider audience but also becomes a trusted source for AI-powered answers, keeping your website relevant and authoritative in the age of generative AI.</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/how-to-integrate-medium-in-crosspost-fea7012b</guid>
      <title>How To: Integrate Medium in Crosspost</title>
      <link>https://coleruche.com/post/how-to-integrate-medium-in-crosspost-fea7012b</link>
      <description>Integrate Medium with Crosspost to enable seamless importing and crossposting to Medium.</description>
      <pubDate>Tue, 01 Jul 2025 21:27:17 GMT</pubDate>
      <content:encoded><![CDATA[<p><a href="https://medium.com/">Medium</a> integration in Crosspost enables you to either publish to your Medium account or import your existing Medium articles into your <a href="https://trycrosspost.com/dashboard">Crosspost dashboard</a> for editing, backup, and syndication. There are two ways to connect your Medium account, depending on whether you have a <strong>Medium Integration Token</strong> or not.</p>
<p>🔐 Medium Integration Tokens are no longer issued to new accounts, but if you already have one, you’re in luck!</p>
<h2>If You Have a Medium Integration Token</h2>
<p>You can check if you have an existing Medium token <a href="https://medium.com/me/settings/security">here.</a></p>
<h3>Steps to Connect</h3>
<ol>
<li>
<p>Log in to Crosspost and go to <a href="https://trycrosspost.com/integrations">Integrations</a></p>
</li>
<li>
<p>Select Medium. Locate Medium in the list of supported platforms. If you do not see it at first, click on "Show More".</p>
</li>
<li>
<p>Paste your Medium integration token in the input box provided.</p>
</li>
<li>
<p>Select the default visibility of new posts. By default, all posts will be "Public". And toggle the "Notify users..." switch</p>
</li>
<li>
<p>Click Save and it's done!</p>
<p><img src="https://ofxqeonyelozjixehdyo.supabase.co/storage/v1/object/public/images/user_2wtUuRPT5LK3kNVkguDKHD90vPe/69d703bf-3a6f-4bd5-96c9-1ea9e0834222-png.png" alt=""></p>
<p>Your Medium account is now fully connected. You can:</p>
<ul>
<li>
<p>Publish posts directly from Crosspost to Medium</p>
</li>
<li>
<p>Import any of your Medium posts into Crosspost (including paywalled ones)</p>
</li>
<li>
<p>Enable AI-enhanced formatting before publishing</p>
</li>
</ul>
</li>
</ol>
<h2>If You Don’t Have a Token (New Medium Users)</h2>
<blockquote>
<p>With this method, direct publishing will not be available.</p>
</blockquote>
<p>Even without a token, Crosspost still lets you connect your Medium account via your username — with some important limitations.</p>
<h3>Steps to Connect Without a Token</h3>
<ol>
<li>
<p>Go to the <a href="https://trycrosspost.com/integrations/medium">Medium integration page.</a></p>
</li>
<li>
<p>Click on "I do not have my Medium integration token"</p>
</li>
<li>
<p>Enter your Medium username (e.g., if your profile is <a href="http://medium.com/@johndoe">medium.com/@johndoe</a>, then enter johndoe)</p>
</li>
<li>
<p>Save</p>
<p><img src="https://ofxqeonyelozjixehdyo.supabase.co/storage/v1/object/public/images/user_2wtUuRPT5LK3kNVkguDKHD90vPe/8d19d380-e528-4178-8fd3-ad952edc87ce-png.png" alt=""></p>
</li>
</ol>
<h3>What You Can Do:</h3>
<p>Import all your non-paywalled Medium articles. Crosspost will fetch your publicly visible stories via RSS, with the following benefits:</p>
<ul>
<li>
<p>Tag Optimization: When republishing Medium articles elsewhere, Crosspost helps you auto-optimize tags for each platform.</p>
<ul>
<li>
<p>Avoiding Duplicate SEO: Crosspost auto-detects canonical links and prevents accidental content duplication across platforms.</p>
</li>
<li>
<p>Backup Strategy: Consider importing your Medium content even if you’re not publishing from Crosspost, so you always have a clean backup.</p>
</li>
</ul>
</li>
</ul>
<h3>What You Cannot Do:</h3>
<ul>
<li>
<p>You cannot publish to Medium from Crosspost</p>
</li>
<li>
<p>You cannot import paywalled content (stories behind Medium’s member paywall)</p>
</li>
</ul>
<p>Need help?</p>
<p>Reach out via the in-app chat or email us at <a href="mailto:support@trycrosspost.com">support@trycrosspost.com</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/how-to-integrate-shopify-in-crosspost-3a99edd4</guid>
      <title>How To: Integrate Shopify in Crosspost</title>
      <link>https://coleruche.com/post/how-to-integrate-shopify-in-crosspost-3a99edd4</link>
      <description>Integrate Shopify with Crosspost to enable seamless crossposting to Shopify store blog.</description>
      <pubDate>Fri, 27 Jun 2025 00:11:35 GMT</pubDate>
      <content:encoded><![CDATA[<p><a href="https://trycrosspost.com">Crosspost</a> has now added support for integrating Shopify!</p>
<p>With this, you can now import articles from and publish to your Shopify store blog effortlessly.</p>
<h2>Why You Should Integrate Shopify with Crosspost</h2>
<p>Looking to automate your Shopify content publishing and expand your reach? Integrating Shopify with Crosspost helps you distribute blog posts, product announcements, and promotional updates across platforms like Medium, <a href="http://Dev.to">Dev.to</a>, and LinkedIn effortlessly.</p>
<p>With this, you can:</p>
<ol>
<li>
<p>Automate Shopify blog publishing to save hours of manual work</p>
</li>
<li>
<p>Boost Shopify SEO by syndicating content to high-authority platforms</p>
</li>
<li>
<p>Reach new audiences and drive traffic back to your ecommerce store</p>
</li>
<li>
<p>Maintain consistent messaging across all content channels effortlessly</p>
</li>
</ol>
<p>Whether you’re a Shopify store owner, a content marketer, or a developer building ecommerce automation, this integration helps turn your store into a scalable content marketing engine.</p>
<h2>How to integrate</h2>
<p>To add this integration, you will need your storefront URL as well as your admin API access token.</p>
<p><img src="https://ofxqeonyelozjixehdyo.supabase.co/storage/v1/object/public/images/user_2wtUuRPT5LK3kNVkguDKHD90vPe/7f6c3c07-aeaa-48e9-8090-e145fdc0d441-png.png" alt=""></p>
<h3>Getting your store URL</h3>
<p>The Shopify store URL is pretty straightforward. To find your Shopify storefront URL, log into your Shopify admin, navigate to Settings, then Domains. Your store's URL, typically in the format your-store-name.shopify.com, will be displayed there.</p>
<p><img src="https://ofxqeonyelozjixehdyo.supabase.co/storage/v1/object/public/images/user_2wtUuRPT5LK3kNVkguDKHD90vPe/8bd565be-4128-4955-b2ce-bea2abeb55d3-png.png" alt=""></p>
<p>Alternatively, you can view it in the browser's address bar when logged by clicking "View your online store".</p>
<h3>Getting your store admin API access token</h3>
<p>To obtain a Shopify Admin API access token, you need to create a custom app within your Shopify admin and configure its API access scopes, then install the app to generate the token. This token allows your app to interact with your Shopify store's data.</p>
<p><strong>Here's a step-by-step guide:</strong></p>
<ul>
<li>
<p>Log in to your Shopify Admin: Access your Shopify store's admin dashboard using your credentials.</p>
</li>
<li>
<p>Navigate to App Settings: Go to "Apps" and then "Apps and sales channel settings".</p>
</li>
<li>
<p>Develop Custom Apps: Click on "Develop apps".</p>
</li>
<li>
<p>Create a New App: Click "Create an app", give it a name, and choose an app developer (usually yourself).</p>
</li>
<li>
<p>Configure Admin API Integration: Go to the "Configuration" tab. Find the "Admin API integration" section and click "Configure".</p>
</li>
<li>
<p>Select API Access Scopes: Choose the specific permissions your app needs by selecting the appropriate checkboxes under "Admin API access scopes". For this use case, search for <code>write_content</code> and <code>read_content</code> scopes and select them.</p>
</li>
<li>
<p>Install the App: Click "Install app" on top right. (Reload the page if still disabled after selecting access scopes)</p>
</li>
<li>
<p>Confirm Installation: In the dialog box, click "Install" again.</p>
</li>
<li>
<p>Reveal and Save the Token: Click "Reveal token once" to display the generated access token. Important: Copy and securely store this token, as it will not be displayed again.</p>
</li>
</ul>
<h3>Integrating in Crosspost</h3>
<p>Now that we have both our shop domain URL and access token, we can proceed to connect in Crosspost. Log in and navigate to the Shopify integration page, enter your storefront URL and the access tokens in the specified fields. Then, "Choose" a blog to connect to. If you do not have a blog created, click on "Create new" and you will be redirected to Shopify to create a new blog.</p>
<p>Click on "Save" to finish the integration. Now you can successfully import and publish to Shopify from Crosspost.</p>
<p>As always, kindly reach out to us if you have any questions.</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/how-to-prompt-chatgpt-properly-7e06959b</guid>
      <title>How to Prompt ChatGPT Properly</title>
      <link>https://coleruche.com/post/how-to-prompt-chatgpt-properly-7e06959b</link>
      <description>Here, we will look at the best ways to prompt ChatGPT and best practices for AI prompting</description>
      <pubDate>Fri, 20 Jun 2025 14:27:32 GMT</pubDate>
      <content:encoded><![CDATA[<p><img src="https://ofxqeonyelozjixehdyo.supabase.co/storage/v1/object/public/images/user_2wtUuRPT5LK3kNVkguDKHD90vPe/9683ce5f-3561-496b-bbcb-1ceb7a54ad49-png.png" alt=""></p>
<p>Let’s face it: many of us have used ChatGPT (and other generative AI) with the same finesse as a toddler in a candy store: excited but completely clueless. You type something vague like, "Tell me about space," and what do you get? A meandering lecture about the universe that could put a caffeinated squirrel to sleep. But fear not! With the right tweaks, you can use ChatGPT as a powerful assistant instead of a disappointing chatbot. Buckle up, because we’re diving into six important AI-prompting guidelines that will unlock its full potential!</p>
<h2>1. Be Specific, Not Vague</h2>
<p>The first rule of thumb is simple: if you want quality, be specific.</p>
<p>When you provide precise inputs, ChatGPT can hone in on what you really need. Think of it as giving a chef a recipe versus just asking for food. Specific ingredients make for a much tastier dish!</p>
<h3>Example:</h3>
<ul>
<li>
<p><strong>Vague Prompt:</strong> "How to manage DKA?"</p>
</li>
<li>
<p><strong>Specific Prompt:</strong> "Summarize the DKA protocol for a 15-year-old T1DM patient in ER. Include doses, fluids, and key danger signs."</p>
</li>
</ul>
<p>This specificity improves the relevance of responses and also elevates the quality of information you receive.</p>
<h2>2. Give It a Role or Persona</h2>
<p>Imagine asking a senior backend engineer for advice on coding, and then asking a junior developer the same question. You can guess who’s more likely to provide a better response! By assigning a role or persona to ChatGPT, you help it respond in the right tone, depth, and expertise.</p>
<h3>Examples:</h3>
<ul>
<li>
<p><strong>Prompt:</strong> “You’re a senior backend engineer. Explain how to optimize a database query for speed.”</p>
</li>
<li>
<p><strong>Prompt:</strong> “Act as a med school lecturer and explain the importance of patient history in diagnosis.”</p>
</li>
</ul>
<p>The same question can yield very different results based on the persona you provide. So, put ChatGPT in the right shoes, and watch it strut its stuff!</p>
<h2>3. Add Structure to Your Request</h2>
<p>Clarity is king, and the best way to achieve that is by asking for structured outputs. Let ChatGPT know if you want steps, checklists, or bullet points. Specifying the format can be a game-changer.</p>
<h3>Example:</h3>
<ul>
<li>
<p><strong>Prompt:</strong> “Explain ECG interpretation.”</p>
</li>
<li>
<p><strong>Structured Prompt:</strong> “Break it down in 5 steps like a checklist for medical interns.”</p>
</li>
</ul>
<p>When you lay out your expectations clearly, ChatGPT can deliver a polished, easy-to-understand response that doesn’t leave you scratching your head.</p>
<h2>4. Feed It Context First</h2>
<p>ChatGPT isn’t a mind reader. If your request lacks background, the answer will too. Providing context is like giving ChatGPT a roadmap: it prevents it from ending up in a ditch somewhere.</p>
<h3>Example:</h3>
<ul>
<li><strong>Contextual Prompt:</strong> “I’m working on a chatbot for an e-commerce site that specializes in handmade crafts. Can you help me design its user flow?”</li>
</ul>
<p>By giving it a little background, ChatGPT can craft a response that aligns perfectly with your goals, rather than spitting out a generic answer that’s about as useful as a screen door on a submarine.</p>
<h2>5. Refine With Follow-Up Prompts</h2>
<p>ChatGPT isn't just a magic eight ball—it's more like a conversation partner. Don't settle for the first draft! Follow up with prompts that refine the output.</p>
<h3>Examples:</h3>
<ul>
<li>
<p><strong>Initial Prompt:</strong> “Write a blog post on the benefits of meditation.”</p>
</li>
<li>
<p><strong>Follow-Up Prompt:</strong> “Make it sound less robotic and include personal anecdotes.”</p>
</li>
</ul>
<p>By treating ChatGPT like a dialogue, you can coax out better, more tailored responses. So keep the conversation flowing!</p>
<h2>6. Use Style Anchors &#x26; Examples</h2>
<p>If you want ChatGPT to create something that resonates, give it style anchors or references. When you name-drop styles, brands, or examples, it helps anchor the tone and layout.</p>
<h3>Example:</h3>
<ul>
<li><strong>Prompt:</strong> “Create a landing page copy for a new productivity app. Make it feel like Apple.com, but with buttons like Stripe.”</li>
</ul>
<p>This technique dramatically improves the creative outputs, it aligns them with your vision and makes the final result feel cohesive and compelling.</p>
<h2>7. Quick Recap: Example Prompts That Combine These</h2>
<p>Now, let's put it all together with a couple of final example prompts that incorporate all six habits:</p>
<ul>
<li>
<p><strong>Example Prompt 1:</strong> “Act as a marketing guru and outline a 3-step social media strategy for a small business in the eco-friendly products niche. Use bullet points and include examples.”</p>
</li>
<li>
<p><strong>Example Prompt 2:</strong> “You’re a high school math teacher. Explain the Pythagorean theorem in a fun, engaging way suitable for 14-year-olds. Please provide a real-world example, and keep it casual.”</p>
</li>
</ul>
<p>These prompts work so well because they combine persona, structure, context, tone, and clarity which is essentially everything you need for a juicy, informative response!</p>
<hr>
<h3>Bonus Section: More ChatGPT Prompting Tips to Try</h3>
<p>Here are a few more bite-sized tips to level up your prompting game:</p>
<ul>
<li>
<p><strong>Use Delimiters:</strong> Surround long inputs with delimiters (like <code>"""</code> or Markdown) to keep things organized.</p>
</li>
<li>
<p><strong>Tell It What Not to Do:</strong> Clear instructions like “Don’t sound robotic” help steer the response in the right direction.</p>
</li>
<li>
<p><strong>Ask for Multiple Versions:</strong> Request variations like “Give me 3 tone variations” to explore different styles.</p>
</li>
<li>
<p><strong>Set Token or Word Limits:</strong> Specify limits for concise responses—great for tight deadlines!</p>
</li>
<li>
<p><strong>Reference Prior Messages:</strong> Mention earlier interactions to build context and continuity.</p>
</li>
<li>
<p><strong>Quiz Yourself:</strong> Ask ChatGPT to quiz you on topics you've just learned for deeper retention.</p>
</li>
<li>
<p><strong>Request Citations:</strong> If applicable, ask for citations or evidence to back up claims—because who doesn’t love a good source?</p>
</li>
</ul>
<hr>
<p><strong>Conclusion</strong></p>
<p>So, there you have it! ChatGPT isn’t magic, but with the right inputs, it feels magical. By implementing these six prompting habits (and a few bonus tips), you can transform your interactions from “meh” to “wow.” So bookmark this, share it, or better yet—try one of these prompts right now. Happy chatting!</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/where-to-publish-your-writing-for-maximum-impact-c-caa1a3dc</guid>
      <title>Where to Publish Your Writing for Maximum Impact</title>
      <link>https://coleruche.com/post/where-to-publish-your-writing-for-maximum-impact-c-caa1a3dc</link>
      <description>This guide covers choosing the right online publications and managing your content across them to grow your audience.</description>
      <pubDate>Tue, 10 Jun 2025 17:36:40 GMT</pubDate>
      <content:encoded><![CDATA[<h2>The Case for Multi-Platform Publishing</h2>
<p>In the early days of the internet, a personal blog was a writer's digital island. Today, the most effective creators build bridges, connecting their work to established communities across multiple platforms. Relying on a single platform can create a digital echo chamber, where your work only reaches those who already know you. This approach severely limits growth and discovery.</p>
<p>The primary benefit of multi-platform publishing is tapping into the built-in audiences of established sites. Platforms like Medium or LinkedIn already have millions of active readers searching for quality content. By sharing your work there, you place it directly in their path, which helps to <strong>increase article visibility</strong> far more quickly than a standalone blog ever could. It’s the difference between setting up a shop on a quiet side street versus opening a stall in a busy market.</p>
<p>Furthermore, publishing on high-authority domains offers a distinct SEO advantage. Search engines trust these established sites, giving your content a better chance to rank. With the right techniques, such as using canonical links to point back to your original article, you can consolidate this credibility without being penalised for duplicate content. This strategy ensures your work reaches new readers while strengthening your own digital footprint.</p>
<h2>An Overview of Key Publishing Platforms</h2>
<p><a href="https://blogbuster-blogs.s3.eu-central-1.amazonaws.com/blog_image/writer-choosing-between-different-publishing-paths_1749576976.jpg"><img src="https://blogbuster-blogs.s3.eu-central-1.amazonaws.com/blog_image/writer-choosing-between-different-publishing-paths_1749576976.jpg" alt="Writer choosing between different publishing paths."></a></p>
<p>With a clear understanding of why you should publish widely, the next question is where. Choosing the right platforms depends entirely on your niche, your style, and the audience you want to reach. Not all platforms are created equal, and the <strong>best platforms for writers</strong> are those that align with their specific goals. Think of each one as a different type of venue, each with its own unique crowd and expectations.</p>
<p>Here is a look at some of the key players:</p>
<ul>
<li><strong>Medium:</strong> This platform is known for its broad, general-interest audience and powerful network effects. It’s an excellent place for thought leadership, personal essays, and deep dives on a variety of topics. Its internal distribution system can help your stories find readers you would never have reached otherwise.</li>
<li><strong>Dev.to:</strong> A community built by and for software developers. If you write technical articles, tutorials, or commentary on the tech industry, Dev.to is an essential destination. The audience is engaged, knowledgeable, and appreciates well-explained code snippets and practical insights.</li>
<li><strong>LinkedIn Articles:</strong> This is the definitive platform for professional, industry-specific, and business-oriented content. Publishing here positions you as an expert in your field, reaching an audience of colleagues, potential employers, and industry leaders. It’s ideal for case studies, career advice, and market analysis.</li>
<li><strong>Personal Blogs &#x26; Newsletters (Substack, Ghost):</strong> This is your home base. It is the one space where you have complete control over your content, audience data, and monetization. While other platforms are for discovery, your personal site is where you build a direct relationship with your most loyal readers.</li>
</ul>
<h2>Developing Your Content Distribution Strategy</h2>
<p>Now that you know the venues, it’s time to plan the tour. A successful <strong>content distribution strategy</strong> is not about shouting your message from every rooftop. Spreading yourself too thin across too many platforms can dilute your efforts and lead to burnout. Instead, focus on two or three platforms where your target audience is most active and engaged.</p>
<p>A proven approach is the "Pillar and Post" model. Your personal blog or newsletter acts as the central "pillar" where your original content lives. Other platforms like Medium or LinkedIn then serve as "posts" where you syndicate that content to reach new audiences. This model ensures you are building your own asset while leveraging the reach of others.</p>
<p>This brings us to a critical technical step for anyone wondering <strong>how to publish on multiple platforms</strong> without harming their search engine ranking: the canonical URL. A canonical link (rel="canonical") is a small piece of HTML code that tells search engines which version of an article is the original. As detailed in Google's own Search Central documentation, proper use of canonical tags is fundamental to content syndication. By adding this tag to your syndicated posts, you ensure all SEO authority flows back to your original pillar article, preventing duplicate content issues and consolidating your credibility.</p>
<h2>Adapting Your Content for Each Audience</h2>
<p><a href="https://blogbuster-blogs.s3.eu-central-1.amazonaws.com/blog_image/content-adapting-to-different-platform-environments_1749576986.jpg"><img src="https://blogbuster-blogs.s3.eu-central-1.amazonaws.com/blog_image/content-adapting-to-different-platform-environments_1749576986.jpg" alt="Content adapting to different platform environments."></a></p>
<p>An effective multi-platform strategy requires more than just copying and pasting. Each platform has its own culture, format, and reader expectations. Simply reposting the same content everywhere is like giving the exact same speech at a business conference and a casual meetup. The message gets lost because the delivery is wrong. To truly connect, you must adapt your content for each specific audience.</p>
<p>Here are a few practical ways to tailor your work:</p>
<ol>
<li><strong>Reframe Your Titles and Introductions:</strong> The title that works on your SEO-optimised blog might not perform well on Medium. For LinkedIn, a title might be direct and professional, like "Three Metrics for Measuring Content ROI." On Medium, a more inquisitive or narrative-driven title, such as "What I Learned After Tracking My Content ROI for a Year," often performs better. The first few sentences should also be adjusted to hook each platform's unique readership.</li>
<li><strong>Adjust the Body for Context:</strong> The core of your article can remain the same, but small additions make a big difference. When posting on Dev.to, ensure your article includes well-formatted code snippets. For a LinkedIn audience, you might embed a chart or add a paragraph that ties your topic to current business trends.</li>
<li><strong>Tailor the Call-to-Action (CTA):</strong> What do you want the reader to do next? The answer should change with the platform. On Medium, you might ask readers to follow you for more stories. On LinkedIn, the goal could be to prompt connections or start a professional discussion in the comments. From your syndicated posts, the ultimate CTA should always guide readers back to your home base, perhaps by encouraging them to subscribe to your newsletter.</li>
</ol>
<h2>Tools for Efficient Content Management</h2>
<p>Executing a thoughtful multi-platform strategy sounds great in theory, but the manual work can be overwhelming. Logging into each platform, reformatting your article, adjusting images, and setting canonical links for every single post is a significant drain on a writer's most valuable resource: time. We have all felt that friction, where administrative tasks get in the way of actual creation.</p>
<p>This is where <strong>content syndication tools</strong> become essential. These platforms are designed to automate the repetitive tasks of distribution. Instead of spending hours copying and pasting, you can focus on what you do best. Platforms like <a href="https://trycrosspost.com/">Crosspost</a> are built to solve this exact problem, allowing creators to write once and publish everywhere with the correct formatting and metadata automatically applied.</p>
<p>By integrating these tools into your workflow, you reclaim hours of your week. You are freed from the tedious mechanics of publishing and can invest that time back into writing, researching, and engaging with your growing audience. It transforms your content strategy from a chore into a seamless extension of your creative process.</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/hosting-your-blog-on-a-subdomain-vs-a-subdirectory-194915cd</guid>
      <title>Hosting Your Blog on a Subdomain vs. a Subdirectory – What’s Best for SEO and Beyond?</title>
      <link>https://coleruche.com/post/hosting-your-blog-on-a-subdomain-vs-a-subdirectory-194915cd</link>
      <description>Subdomain or subdirectory? One boosts SEO, the other… not so much.</description>
      <pubDate>Mon, 09 Jun 2025 22:17:17 GMT</pubDate>
      <content:encoded><![CDATA[<p><img src="https://ofxqeonyelozjixehdyo.supabase.co/storage/v1/object/public/images/user_2wtUuRPT5LK3kNVkguDKHD90vPe/c5a29e75-8d66-4c9f-a188-d53b10989454-png.png" alt=""></p>
<p>In the digital landscape of today, bloggers and digital marketers often find themselves at a critical crossroads when setting up their blogs: Should they host their blog on a subdomain or a subdirectory? This choice is not merely a technical one; it bears significant implications for SEO, branding, and overall site management. In this article, we will explore these two options, their advantages and disadvantages, and help you decide the best path for your blog.</p>
<h2>Understanding Subdomains and Subdirectories</h2>
<p>Before diving into the nuances of each approach, let’s clarify what we mean by subdomains and subdirectories:</p>
<ul>
<li>
<p><strong>Subdomain</strong>: This is a distinct part of your main domain, serving as an independent entity. For example, if your main site is <code>domain.com</code>, a blog on a subdomain would be <code>blog.domain.com</code>.</p>
</li>
<li>
<p><strong>Subdirectory</strong>: This is a folder within your main domain. Continuing with our example, a blog in a subdirectory would appear as <code>domain.com/blog</code>.</p>
</li>
</ul>
<p>The decision between these two structures is crucial because it impacts your site’s SEO performance, branding strategy, and technical flexibility.</p>
<h2>Subdomain Overview</h2>
<h3>What is a Subdomain?</h3>
<p>A subdomain is essentially a separate section of your website that can function independently from the main domain. Companies often use subdomains for various reasons, such as to host distinct content types or to target different audiences.</p>
<h3>When to Use Subdomains</h3>
<p>Subdomains are particularly useful for:</p>
<ul>
<li>
<p><strong>Large Companies</strong>: Organizations with diverse offerings (like an e-commerce site, a blog, and a support center) may choose subdomains to separate each function clearly.</p>
</li>
<li>
<p><strong>Different Content Management Systems (CMS)</strong>: If your primary website runs on one CMS and you prefer another for your blog (say, using WordPress for the blog), a subdomain allows you the flexibility to do so.</p>
</li>
<li>
<p><strong>Multilingual Sites</strong>: Companies targeting multiple languages often use subdomains (e.g., <code>fr.domain.com</code> for French content) to organize their content better.</p>
</li>
</ul>
<h3>SEO Considerations</h3>
<p>When it comes to SEO, Google treats subdomains as separate entities. This can be advantageous in some cases, as it allows for focused content targeting. However, it also means that the authority built up on your main domain does not automatically transfer to the subdomain, potentially diluting your SEO efforts.</p>
<h3>Pros and Cons of Subdomains</h3>
<p><strong>Pros</strong>:</p>
<ul>
<li>
<p>Greater flexibility in terms of design and technology.</p>
</li>
<li>
<p>Clear separation of content types, which can enhance user experience.</p>
</li>
</ul>
<p><strong>Cons</strong>:</p>
<ul>
<li>
<p>SEO dilution due to separate domain authority.</p>
</li>
<li>
<p>More complex tracking and analytics setup.</p>
</li>
</ul>
<h2>Subdirectory Overview</h2>
<h3>What is a Subdirectory?</h3>
<p>A subdirectory, on the other hand, is part of your main domain’s structure. It is integrated into your main website and is often perceived as part of the same entity.</p>
<h3>When to Use Subdirectories</h3>
<p>Subdirectories are ideal for:</p>
<ul>
<li>
<p><strong>Small to Mid-Size Businesses</strong>: Companies looking to build their brand and authority can benefit from the shared domain authority.</p>
</li>
<li>
<p><strong>SEO-Focused Sites</strong>: If your main goal is to enhance your SEO performance, utilizing a subdirectory can help consolidate your domain authority.</p>
</li>
<li>
<p><strong>Content Hubs</strong>: If your blog is a central part of your business strategy, keeping it in a subdirectory can help create a more cohesive user experience.</p>
</li>
</ul>
<h3>SEO Benefits</h3>
<p>One of the most significant advantages of using a subdirectory is that it allows your blog to benefit from the domain authority of your main site. This can lead to improved rankings on search engines, as the content can leverage existing backlinks and traffic.</p>
<h3>Pros and Cons of Subdirectories</h3>
<p><strong>Pros</strong>:</p>
<ul>
<li>
<p>Tight integration with the main website enhances brand unity.</p>
</li>
<li>
<p>Easier transfer of SEO benefits and domain authority.</p>
</li>
</ul>
<p><strong>Cons</strong>:</p>
<ul>
<li>
<p>Potential technical limitations based on the main site’s CMS.</p>
</li>
<li>
<p>Changes to the main site could inadvertently affect the blog.</p>
</li>
</ul>
<h2>SEO Implications</h2>
<p>Google treats subdomains and subdirectories differently. While there’s an ongoing debate in the SEO community about which is better, many experts agree that subdirectories generally provide a stronger foundation for SEO performance.</p>
<h3>Key Factors to Consider</h3>
<ol>
<li>
<p><strong>Domain Authority</strong>: A subdirectory shares the main domain's authority, which can significantly enhance its SEO performance.</p>
</li>
<li>
<p><strong>Crawl Efficiency</strong>: Google’s crawlers may find it easier to navigate and index a unified structure than separate domains.</p>
</li>
<li>
<p><strong>Backlink Value</strong>: Backlinks to the main domain also benefit the subdirectory, which is not the case for subdomains.</p>
</li>
</ol>
<h3>Community Insights</h3>
<p>Several studies and discussions in SEO communities, such as those by Moz and Search Engine Journal, support the idea that subdirectories often yield better SEO results, especially for businesses aiming for organic growth.</p>
<h2>Technical &#x26; Operational Considerations</h2>
<p>When deciding between a subdomain and a subdirectory, consider the following operational elements:</p>
<h3>CMS Flexibility</h3>
<p>If you wish to use different technologies for your blog and main site, a subdomain may be more suitable. For example, you could run your main site on a custom-built platform while using WordPress for your blog on a subdomain.</p>
<h3>Tracking and Analytics</h3>
<p>Google Analytics and Search Console handle subdomains and subdirectories differently. While you can track both setups with similar tools, subdomains require more granular setup to ensure you’re capturing data accurately.</p>
<h3>Performance Impact</h3>
<p>In terms of performance, a subdirectory may offer better speed and efficiency due to the shared resources of the main domain, while a subdomain might introduce additional latency.</p>
<h2>Branding &#x26; User Experience</h2>
<p>Brand perception can be influenced significantly by your choice of blog structure. A subdirectory usually provides a sense of unity and cohesiveness across your digital properties. Users may feel more comfortable navigating between the main site and the blog when they appear as part of the same domain, fostering a more seamless experience.</p>
<h3>Navigation Continuity</h3>
<p>While subdomains can serve specialized content, they often require users to adjust to a different URL and interface, which may disrupt the user experience. In contrast, subdirectories maintain a consistent user journey.</p>
<h2>Which Should You Choose? (Decision Guide)</h2>
<p>When making your decision, consider the following checklist:</p>
<ul>
<li>
<p><strong>Do you need flexibility in technology?</strong> → Subdomain</p>
</li>
<li>
<p><strong>Is SEO growth your primary goal?</strong> → Subdirectory</p>
</li>
<li>
<p><strong>Is your blog a significant part of your brand?</strong> → Subdirectory</p>
</li>
<li>
<p><strong>Do you manage multiple sites with distinct purposes?</strong> → Subdomain</p>
</li>
</ul>
<p>In most cases, particularly for smaller to mid-size businesses focused on SEO, subdirectories are preferred unless there’s a compelling reason to opt for a subdomain.</p>
<h2>Conclusion</h2>
<p>Choosing between a subdomain and a subdirectory is a pivotal decision that can impact your blog's performance, user experience, and overall brand perception. By weighing the pros and cons of each option and considering your long-term goals—whether they lean more towards SEO growth or technical flexibility—you can make an informed decision that aligns with your business strategy.</p>
<p>Ultimately, as with many aspects of digital marketing, there is no one-size-fits-all solution. Taking the time to evaluate your needs and objectives will serve you well in the long run.</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/understanding-domain-authority-5b0a39dc</guid>
      <title>Understanding Domain Authority: What It Is and How to Achieve a High Score</title>
      <link>https://coleruche.com/post/understanding-domain-authority-5b0a39dc</link>
      <description>Learn what Domain Authority (DA) means, why it matters for your website’s SEO performance, and discover practical strategies to boost your DA score.</description>
      <pubDate>Sun, 08 Jun 2025 21:46:13 GMT</pubDate>
      <content:encoded><![CDATA[<p>In the ever-evolving landscape of digital marketing, the quest for online visibility is relentless. As businesses strive to climb the search engine rankings, they often find themselves exploring various strategies to enhance their reach. One such strategy that has gained significant traction in recent years is crossposting articles across different platforms. This practice not only amplifies content reach but also offers several SEO benefits that can dramatically improve online visibility and traffic. In this article, we will delve into the nuances of crossposting and explore how it can be an invaluable tool in your digital marketing arsenal.</p>
<h2>Understanding Crossposting</h2>
<p>Crossposting refers to the practice of publishing the same content across multiple platforms or websites. This can include social media, personal blogs, third-party websites, or content syndication networks. While it may sound counterintuitive at first, the benefits often outweigh the potential drawbacks when done strategically.</p>
<h2>The SEO Advantages of Crossposting</h2>
<h3>1. <strong>Increased Content Reach</strong></h3>
<p>One of the most immediate benefits of crossposting is the increased reach your content can achieve. By sharing your articles on various platforms, you expose your brand to different audiences. Each platform has its own user base, and by crossposting, you can attract readers who may not have encountered your content otherwise.</p>
<p>For instance, sharing a blog post on LinkedIn can reach a professional audience, while posting the same article on Facebook might attract a more casual, general audience. This broader reach can lead to a higher number of backlinks and social shares, both of which are essential for improving SEO.</p>
<h3>2. <strong>Boosting Domain Authority</strong></h3>
<p>Domain authority (DA) is a critical factor in how search engines rank your website. Crossposting can enhance your website's DA in several ways. First, when your content is shared across multiple reputable platforms, it signals to search engines that your content is valuable and trustworthy. This can lead to increased recognition from search engines, which often results in improved rankings.</p>
<p>Furthermore, crossposting can generate backlinks to your primary domain, especially if you are sharing your content on platforms that allow for a link back to your original article. These backlinks are crucial for SEO as they help to establish your site as a credible source of information.</p>
<h3>3. <strong>Enhanced Keyword Visibility</strong></h3>
<p>Crossposting can also improve your keyword visibility. By sharing your articles on multiple platforms, you create more opportunities for your target keywords to be indexed by search engines. Each platform may rank differently for specific terms, so crossposting can help your content appear in various search results.</p>
<p>For example, if your article is optimized for the keyword "digital marketing strategies," crossposting it on platforms that cater to marketing professionals can increase the chances of your content being discovered by users searching for that specific term. This diversified approach can lead to increased organic traffic over time.</p>
<h3>4. <strong>Social Signals and Engagement</strong></h3>
<p>Search engines consider social signals (such as likes, shares, and comments) as indicators of content quality. When you crosspost articles, you can tap into the engagement mechanics of various platforms. The more interaction your content receives, the more likely search engines are to view it as valuable, which can, in turn, boost your rankings.</p>
<p>Engaging with users on different platforms can also lead to discussions around your content, creating a sense of community. This engagement can result in additional shares and backlinks, further enhancing your SEO efforts.</p>
<h3>5. <strong>Repurposing Content for Different Audiences</strong></h3>
<p>Crossposting allows brands to repurpose content, tailoring it for different audiences without starting from scratch. You can modify your articles slightly to suit the tone and preferences of each platform. For instance, a detailed blog post may be condensed into a series of social media posts or adapted into an infographic for visual platforms like Pinterest.</p>
<p>By repurposing content, you maximize your investment in content creation while simultaneously catering to diverse audience segments. This targeted approach can lead to higher engagement rates, driving more traffic back to your primary site.</p>
<h3>6. <strong>Establishing Thought Leadership</strong></h3>
<p>Regularly crossposting valuable content positions your brand as a thought leader in your industry. When you consistently share insightful articles across various platforms, it builds credibility and trust among your audience. This trust can translate into organic traffic as users seek out your content as a reliable source of information.</p>
<p>Over time, being recognized as a thought leader can lead to speaking engagements, partnerships, and other opportunities that further enhance your brand's visibility and traffic.</p>
<h2>Best Practices for Crossposting</h2>
<p>While the benefits of crossposting are evident, it’s essential to approach this strategy thoughtfully to avoid potential pitfalls such as duplicate content penalties. Here are some best practices to ensure that your crossposting efforts are effective:</p>
<ol>
<li>
<p><strong>Use Canonical Tags:</strong> If you are crossposting the same article on multiple platforms, use canonical tags to indicate the original source. This informs search engines which version to prioritize in rankings.</p>
</li>
<li>
<p><strong>Modify Content Slightly:</strong> Instead of posting the exact same article everywhere, consider modifying it for different platforms. Adjust the tone, format, or even the headline to better fit the audience of each platform.</p>
</li>
<li>
<p><strong>Promote Engagement:</strong> Encourage readers to engage with your content by asking questions or inviting comments. This not only boosts social signals but can also lead to meaningful discussions.</p>
</li>
<li>
<p><strong>Track Performance:</strong> Utilize analytics tools to monitor the performance of your crossposted articles. Track metrics like traffic sources, engagement rates, and conversions to evaluate the effectiveness of your strategy.</p>
</li>
<li>
<p><strong>Choose Platforms Wisely:</strong> Not all platforms will be suitable for every piece of content. Consider your target audience and select the platforms where they are most active.</p>
</li>
</ol>
<h2>Conclusion</h2>
<p>Crossposting articles is a powerful strategy in the digital marketing toolkit, offering numerous SEO benefits that can significantly enhance online visibility and traffic. By strategically distributing content across various platforms, businesses can boost their reach, improve domain authority, and establish themselves as thought leaders. As the digital landscape continues to evolve, embracing crossposting could be the key to staying ahead of the competition and maximizing the impact of your content. In the end, it’s not just about creating great articles; it’s about ensuring they reach the right audience in the right places.</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/autoblogging-build-a-hands-free-autopilot-blogging-bfce377f</guid>
      <title>Autoblogging: Build a Hands-Free Autopilot Blogging System with Blogbuster + Crosspost</title>
      <link>https://coleruche.com/post/autoblogging-build-a-hands-free-autopilot-blogging-bfce377f</link>
      <description>The new era of publishing</description>
      <pubDate>Wed, 04 Jun 2025 11:57:19 GMT</pubDate>
      <content:encoded><![CDATA[<p><img src="https://cdn-images-1.medium.com/max/1024/1*NmcPUKHt3HmzyJJhowqpkA.png" alt=""></p>
<h3>The New Era of Content Creation</h3>
<p>In the fast-paced world of digital publishing, the demand for consistent, high-quality content is relentless. Whether you run a niche blog, content-heavy startup, personal newsletter, or affiliate site, keeping up with publishing schedules can feel like a full-time job. But what if your blog could write itself — on autopilot?</p>
<p>That’s exactly what autoblogging makes possible. Autoblogging tools use AI and automation to generate, schedule, and even distribute blog content without manual writing. And two platforms are leading the charge in this space: <a href="https://www.blogbuster.so/">Blogbuster</a>, your go-to autopilot blog generator, and <a href="https://trycrosspost.com/">Crosspost</a>, the one-click publishing and distribution tool.</p>
<p>In this feature, we’ll explore how <a href="https://www.blogbuster.so/">Blogbuster</a> can power your blog’s content engine while you sleep, and how pairing it with <a href="https://trycrosspost.com/">Crosspost</a> transforms it into a seamless syndication powerhouse. This article will cover the Blogbuster setup, generation process, and strategic use cases and then show you how to publish and cross-post your new AI-written posts across the internet using <a href="https://trycrosspost.com/">Crosspost</a>.</p>
<h3>What is Blogbuster?</h3>
<p>Blogbuster is an AI autoblogging tool that takes the manual work out of content creation. It generates original, SEO-friendly blog posts from just a few inputs — no writing, editing, or formatting needed.</p>
<p><a href="https://blogbuster.so/">BlogBuster: Turn Your Blog into an Autopilot Traffic Machine</a></p>
<p>Once set up, Blogbuster runs on autopilot, creating and scheduling articles daily, weekly, or monthly. You can choose content categories or let it pick trending topics from your niche.</p>
<p>Each post comes optimized for search, complete with structured headings, keywords, and even images to break up walls of text — making your blog look pro with zero effort.</p>
<h3>What is Crosspost?</h3>
<p>Crosspost is a content distribution tool that lets you publish your blog posts everywhere from one place. With a single click, you can send your articles to platforms like Medium, Substack, Hashnode, Dev.to, and more.</p>
<p><a href="https://trycrosspost.com/">Crosspost - Write once, publish everywhere.</a></p>
<p>It’s built for creators who want maximum reach without copying and pasting across sites. Just connect your accounts, upload or paste your post, and Crosspost handles the rest.</p>
<p>Each version is formatted to match the destination platform, keeping your content clean and consistent — so you focus on writing once, and let Crosspost handle the rest.</p>
<h3>Getting Started with Blogbuster</h3>
<p>Starting with Blogbuster is surprisingly fast and intuitive. Here’s a breakdown of how to set up your autoblog in under 10 minutes:</p>
<h4>1. Sign Up and Create a Project</h4>
<p>Visit <a href="https://www.blogbuster.so/">Blogbuster’s website</a> and sign up for an account. After logging in, enter your domain URL and let Blogbuster scrape your project and generate the brand info, audience and tone in 2–3 minutes. You can also customize these if you want.</p>
<p><img src="https://cdn-images-1.medium.com/max/1024/1*-gVvRhS-ry0iU9NmJrVy8g.png" alt=""></p>
<p>To get you started, Blogbuster will let you choose one of three suggested topics to generate an article about.</p>
<p><img src="https://cdn-images-1.medium.com/max/1024/1*QHBgZyeCcyND4Zf51ITxUg.png" alt=""></p>
<h4>2. Set Your Content Preferences</h4>
<p>Head over to Settings in Blogbuster to set your brand and content preferences. You can set preferences for brand logo, name, description, and target audience, as well as content preferences like length, specific instructions, exclusions, and much more.</p>
<blockquote>
<p>For me, because tables are not supported on Medium and can have funny behaviours in different platforms, I added the instruction “Do not generate tables or any advanced formatting”.</p>
</blockquote>
<h4>3. Pick Topics or Let AI Decide</h4>
<p>Next, head over to Topics. Here you can see the topics generated by Blogbuster based on your domain, or you can generate new ones if you are a paying customer.</p>
<p><img src="https://cdn-images-1.medium.com/max/1024/1*ZmYi1XhTElDK8DzRPoV6bw.png" alt=""></p>
<p>For each generated topic, you can choose to schedule or generate immediately. For this tutorial, click “Generate Now” to generate the articles. This could take a while, and you will receive an email once the article is fully generated!</p>
<h4>4. Publish Articles</h4>
<p>Head over to <a href="https://www.blogbuster.so/app/article">Article</a> to view generated articles. Here, you can open each article to make any edits you may want. When satisfied with what you have, publish the article.</p>
<h4>5. Generate API token</h4>
<p>To be able to import and crosspost articles generated by Blogbuster on Crosspost, you will need a Blogbuster API key. To get this, head over to <a href="https://www.blogbuster.so/app/domain-setting">Settings</a> > Integrations and click on Generate to get a new key.</p>
<p>Store this key safely!</p>
<h3>Setting up Crosspost</h3>
<p>Now that we are done with the Blogbuster side of the setup, we now need to setup Crosspost to import and publish the generated articles across the internet.</p>
<h4>1. Set up a Crosspost account</h4>
<p>Head over to <a href="https://trycrosspost.com/sign-up">Crosspost</a> to create a new account easily.</p>
<h4>2. Add integrations</h4>
<p>You will need to connect your Blogbuster account on Crosspost. Also, you will need to connect target platforms where you want to publish.<br>
Navigate to <a href="https://trycrosspost.com/integrations/blogbuster">Integrations > Blogbuster</a>, paste in your Blogbuster API key, then click on “Choose” to select the tenant (project) you want to import from. Then save the integration.</p>
<p><img src="https://cdn-images-1.medium.com/max/1024/1*RAkHoZYk1KEP_2tziMYNFw.png" alt=""></p>
<p>Do this for other platforms (e.g DEV, Medium, Hashnode) where you want to publish to.</p>
<h4>3. Import from Blogbuster</h4>
<p>Click on the pencil icon on the navigation bar and then “New” to start a new article on Crosspost. On the edit page that shows next, click on “Import from…” and select Blogbuster.</p>
<p><img src="https://cdn-images-1.medium.com/max/1024/1*K3BHIhqhOOVI0a6GEy-ZCw.png" alt=""></p>
<p>This will open a modal that lists all <strong>published</strong> articles on Blogbuster and you will be able to choose one from the list. Select the one you wish to crosspost and “Import selected”.</p>
<h4>4. Crosspost!</h4>
<p>After making sure everything looks good and imported correctly — which I’m sure is the case — go ahead and click on the Continue button and select all connected platforms you wish to publish to.</p>
<p><img src="https://cdn-images-1.medium.com/max/1024/1*mfHWisc-VMqCr_4LlEUTHg.png" alt=""></p>
<p>You can also click on Advanced Settings to set properties like canonical URL, tags, SEO properties and more. When ready to publish, click on Publish and watch your content distributed everywhere at once!</p>
<h4>Further reading:</h4>
<ul>
<li>
<p><a href="https://medium.com/write-once/why-crossposting-your-articles-is-a-superpower-if-you-do-it-right-7aa77b9e7282">https://medium.com/write-once/why-crossposting-your-articles-is-a-superpower-if-you-do-it-right-7aa77b9e7282</a></p>
</li>
<li>
<p><a href="https://medium.com/write-once/the-ultimate-guide-to-streamlined-publishing-for-writers-and-bloggers-a8ef65760c7b?source=collection_home---5------0-----------------------">https://medium.com/write-once/the-ultimate-guide-to-streamlined-publishing-for-writers-and-bloggers-a8ef65760c7b</a></p>
</li>
<li>
<p><a href="https://www.blogbuster.so/blog/How-to-Use-AI-to-Craft-Evergreen-Blog-Content-That-Ranks-Long-Term">https://www.blogbuster.so/blog/How-to-Use-AI-to-Craft-Evergreen-Blog-Content-That-Ranks-Long-Term</a></p>
</li>
<li>
<p><a href="https://www.coleruche.com/post/content-syndication-vs-crossposting-0be12da9">https://www.coleruche.com/post/content-syndication-vs-crossposting-0be12da9</a></p>
</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/content-syndication-vs-crossposting-0be12da9</guid>
      <title>Content Syndication vs Crossposting: What’s the Difference?</title>
      <link>https://coleruche.com/post/content-syndication-vs-crossposting-0be12da9</link>
      <description>Learn how content syndication and crossposting work—what sets them apart and how using both can maximize your content’s reach.</description>
      <pubDate>Tue, 03 Jun 2025 14:23:56 GMT</pubDate>
      <content:encoded><![CDATA[<blockquote>
<p>TL;DR:</p>
<p>Content syndication is when third parties republish your content (with credit).</p>
<p>Crossposting is when you publish the same content across multiple platforms yourself.</p>
</blockquote>
<p><img src="https://ofxqeonyelozjixehdyo.supabase.co/storage/v1/object/public/images/user_2wtUuRPT5LK3kNVkguDKHD90vPe/7187bb97-aa75-4f72-99f9-7a332342dd38-jpeg.jpeg" alt=""></p>
<p>In the rapidly evolving digital landscape, content is king. Whether you’re a blogger, an entrepreneur, or a marketer, the ability to share and disseminate your content widely is crucial for building an audience and establishing authority in your niche. Two prevalent strategies for distributing content are <strong>content syndication</strong> and <strong>crossposting</strong>. While they may seem similar at first glance, they serve different purposes and have distinct implications for content creators and marketers. In this article, we will explore the nuances of content syndication and crossposting, helping you understand when and how to use each strategy effectively.</p>
<h2>Understanding Content Syndication</h2>
<p><img src="https://ofxqeonyelozjixehdyo.supabase.co/storage/v1/object/public/images/user_2wtUuRPT5LK3kNVkguDKHD90vPe/e58f5895-3825-47c3-aa1f-1072a3c4b5c9-jpeg.jpeg" alt=""></p>
<p>Content syndication refers to the process of republishing your content on third-party sites, with the intent of reaching a broader audience. This practice can be beneficial in several ways:</p>
<ol>
<li>
<p><strong>Reach and Visibility</strong>: By syndicating your content, you can tap into the existing audience of larger platforms. This is particularly advantageous for new bloggers or brands looking to gain traction. For example, a well-established website in your niche may have thousands of visitors daily. If your article appears there, it can introduce your work to potential readers who may not have discovered you otherwise.</p>
</li>
<li>
<p><strong>SEO Benefits</strong>: While some may worry about duplicate content penalties from search engines, reputable syndication platforms often include canonical tags that point back to the original article on your site. This means that search engines understand where the content originated, preserving your SEO ranking.</p>
</li>
<li>
<p><strong>Brand Authority</strong>: Being featured on reputable sites can enhance your brand’s credibility. When audiences see your content on trusted platforms, they are more likely to view you as an authority in your field.</p>
</li>
</ol>
<p>However, it’s essential to choose syndication partners wisely. Not all platforms offer the same benefits, and low-quality sites may harm your brand’s reputation.</p>
<h2>The Concept of Crossposting</h2>
<p><img src="https://ofxqeonyelozjixehdyo.supabase.co/storage/v1/object/public/images/user_2wtUuRPT5LK3kNVkguDKHD90vPe/6539f6f2-7d2d-413d-b708-2b93a316015b-jpeg.jpeg" alt=""></p>
<p>Crossposting, on the other hand, involves sharing the same piece of content across multiple platforms simultaneously, often with the intention of engaging different audiences on each platform. This technique is commonly used on social media channels, forums, and other online communities. Here are some key attributes of crossposting:</p>
<ol>
<li>
<p><strong>Audience Engagement</strong>: Different platforms attract different demographics and interests. By crossposting, you can engage with varied audiences, tailoring your content to fit the nuances of each platform. For instance, a professional article might be suitable for LinkedIn, while a more casual version could resonate better on Facebook or Twitter.</p>
</li>
<li>
<p><strong>Consistency in Messaging</strong>: Crossposting allows for consistent messaging across various channels. When executed properly, this strategy reinforces your brand voice and keeps your audience informed, regardless of the platform they are using.</p>
</li>
<li>
<p><strong>Time Efficiency</strong>: Content creation is a labor-intensive process. Crossposting allows you to maximize the value of your content by sharing it across multiple platforms quickly. This efficiency can be particularly beneficial for busy professionals who need to maintain an active online presence without dedicating excessive time to content creation.</p>
</li>
</ol>
<p>However, crossposting can be tricky. Each platform has its own culture, and what works on one might not work on another. It’s important to adapt your content slightly—such as changing the tone or format—to suit the audience of each platform, rather than simply copying and pasting the same text everywhere.</p>
<h2>Key Differences Between Syndication and Crossposting</h2>
<p>While both content syndication and crossposting aim to increase visibility and reach, several key differences set them apart:</p>
<ul>
<li>
<p><strong>Purpose</strong>: The primary purpose of syndication is to <strong>leverage the audience of another platform</strong> to gain exposure, while crossposting focuses on engaging different audiences across multiple platforms simultaneously.</p>
</li>
<li>
<p><strong>Control</strong>: In syndication, content creators often relinquish some control over how their content is presented, as it is republished by another site. In contrast, crossposting allows for more direct control, enabling you to tailor your content to fit each platform’s unique style and audience.</p>
</li>
<li>
<p><strong>SEO Implications</strong>: Syndicated content typically includes canonical links, protecting the original source’s SEO ranking. Conversely, crossposting may not always have these safeguards, which could lead to duplicate content issues if not managed correctly.</p>
</li>
</ul>
<h2>Best Practices for Content Syndication and Crossposting</h2>
<p>To make the most of both syndication and crossposting, consider the following best practices:</p>
<ol>
<li>
<p><strong>Choose the Right Platforms</strong>: For syndication, select reputable sites that align with your brand values and target audience. For crossposting, ensure that the platforms you choose are relevant to your content and conducive to engagement.</p>
</li>
<li>
<p><strong>Tailor Your Content</strong>: When crossposting, it’s essential to slightly modify your content for each platform. This could mean changing the headline, adjusting the tone, or adding platform-specific elements (like hashtags for Twitter or images for Instagram).</p>
</li>
<li>
<p><strong>Monitor Performance</strong>: Use analytics tools to track how your content performs across different platforms. This information can guide your future content strategy, helping you identify what works best for your audience.</p>
</li>
<li>
<p><strong>Utilize Tools</strong>: Platforms like <a href="https://trycrosspost.com"><strong>Crosspost</strong></a> can assist in simplifying crossposting efforts. This user-friendly tool enables you to schedule posts, track engagement, and streamline your content distribution process, ensuring consistency and efficiency.</p>
</li>
</ol>
<h2>Conclusion</h2>
<p>In conclusion, both content syndication and crossposting are valuable strategies for increasing your content's reach and engagement. While they share a common goal of enhancing visibility, they differ significantly in their execution and implications for content creators. Understanding these differences will empower you to make informed decisions about how to share your content effectively.</p>
<p>By leveraging the right combination of syndication and crossposting, and utilizing tools like <a href="https://trycrosspost.com"><strong>Crosspost</strong></a>, you can enhance your online presence, engage with diverse audiences, and ultimately achieve your content marketing goals. As the digital landscape continues to evolve, mastering these strategies will be essential for anyone looking to thrive in the competitive world of content creation.</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/what-is-generative-engine-optimization-29b72a24</guid>
      <title>What is Generative Engine Optimization?</title>
      <link>https://coleruche.com/post/what-is-generative-engine-optimization-29b72a24</link>
      <description>Explore how Generative Engine Optimization (GEO) is reshaping content visibility in the age of AI assistants</description>
      <pubDate>Mon, 02 Jun 2025 12:54:17 GMT</pubDate>
      <content:encoded><![CDATA[<p><img src="https://ofxqeonyelozjixehdyo.supabase.co/storage/v1/object/public/images/user_2wtUuRPT5LK3kNVkguDKHD90vPe/c565be5c-9f58-4dd0-91d8-147ca139a580-jpeg.jpeg" alt=""></p>
<p>Once upon a time in the realm of digital marketing, there was a revolutionary concept that changed the way businesses approached online visibility: Search Engine Optimization, or SEO. As Google began to dominate the search landscape in the early 2000s, savvy marketers recognized the power of optimizing website content to rank higher in search results. The marriage of keyword strategy, backlinks, and user experience became the holy grail for driving traffic and engagement. Fast forward to today, and we find ourselves in a world where content marketing has evolved into a sophisticated ecosystem, thanks to the rise of generative AI tools like ChatGPT, Claude, Perplexity, and Gemini.</p>
<p>These AI models are not just reshaping how we create content; they are redefining the very essence of how we think about optimization. Enter Generative Engine Optimization (GEO), a modern approach that focuses on optimizing content not for traditional search engines but for generative AI models that deliver direct, conversational answers to user queries. As we navigate this new landscape, it's essential to understand what GEO entails, how it influences content strategy, and the key strategies that can enhance your efficacy in this evolving domain.</p>
<h2>The Shift from SEO to GEO</h2>
<p>Traditional SEO was primarily concerned with aligning content to the algorithms of search engines, ensuring that keywords were strategically placed and that backlinks were acquired to boost authority. However, with the advent of generative AI, the paradigm is shifting. These AI tools do not just index and rank content; they generate it, providing users with concise, relevant responses drawn from a vast array of sources. This means that the focus of content creators is no longer solely on driving traffic to their websites but also on ensuring that their content is optimized for these AI's understanding and generation processes.</p>
<p>Generative AI is built on complex algorithms that analyze language patterns, context, and user intent. As a result, content must be structured and presented in a way that these models can easily parse and utilize. GEO is thus born out of the necessity to adapt content strategies to a world where AI is the intermediary between the creator and the consumer.</p>
<h2>Key Strategies for Generative Engine Optimization</h2>
<p>As we embrace GEO, there are several critical strategies to consider that can help ensure your content resonates with both AI models and human readers.</p>
<h3>1. Writing Factual and Easily Digestible Content</h3>
<p>Generative AI thrives on clarity and accuracy. Therefore, it is essential to focus on factuality in your content. Information must be presented in a straightforward manner, free from jargon and complex language that could confuse both AI and users. Short paragraphs, bullet points, and clear headings can enhance readability, making it easier for generative models to extract relevant information.</p>
<h3>2. Using Explainer or Q&#x26;A Formats</h3>
<p>Generative AI tools often pull data to answer specific questions. Creating content in an explainer or Q&#x26;A format can significantly enhance the chances of your information being utilized by these models. Structuring your content to address common queries or to explain key concepts can help ensure that your insights are the ones that generative engines serve up when users seek answers.</p>
<h3>3. Including Authorship and Trust Signals</h3>
<p>In a world filled with misinformation, trust is paramount. Including authorship and credibility markers in your content can help establish authority. This can be achieved by integrating author bios, references to reputable sources, and statistics from trusted organizations. Generative AI models favor content that demonstrates expertise and reliability, making this an essential aspect of GEO.</p>
<h3>4. Structuring Content for Machine Parsing</h3>
<p>To enhance the likelihood of your content being recognized and used by generative AI, it’s vital to structure it in a way that machines can easily parse. This includes using clear headings, subheadings, and well-organized sections. Incorporating schema markup can also improve how search engines and generative models understand the context of your content, thereby enhancing its visibility.</p>
<h3>5. Making Content Accessible to Real-Time Engines and Prompting Communities</h3>
<p>Generative AI is continually learning and adapting. Therefore, your content should be accessible and relevant to real-time engines. This means keeping your information up-to-date and engaging with communities that share your content. By fostering dialogue and encouraging interaction, you can enhance your content's relevance and visibility in the eyes of generative engines.</p>
<p>Moreover, tools like <a href="https://trycrosspost.com">Crosspost</a> are already helping creators prepare for this shift by making multi-platform publishing effortless. By allowing content creators to write once and publish across various platforms, Crosspost simplifies the distribution process and aligns seamlessly with GEO principles. This ensures that your optimized content reaches diverse audiences, maximizing its impact.</p>
<h2>Conclusion</h2>
<p>As we stand on the precipice of this new era in content strategy, Generative Engine Optimization is a powerful concept that every content creator should embrace. By understanding the core principles of GEO and implementing key strategies, you can ensure that your content not only meets the needs of traditional search engines but also resonates with generative AI models that shape the future of information retrieval.</p>
<p>For those eager to delve deeper into the capabilities of modern tools in this evolving landscape, I invite you to explore this <a href="https://www.coleruche.com/post/the-ultimate-guide-to-streamlined-publishing-for-w-044085bb">blog post</a>. This resource will provide you with further insights into how you can streamline your content generation processes while adapting to the shifts in digital marketing.</p>
<p>In the world of content creation, staying ahead of the curve is not just advantageous; it is essential. Embrace GEO, adapt your strategies, and watch your content thrive in the age of generative AI.</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/11-essential-frontend-development-tips-for-beginne-76266aad</guid>
      <title>11 Essential Frontend Development Tips for Beginners</title>
      <link>https://coleruche.com/post/11-essential-frontend-development-tips-for-beginne-76266aad</link>
      <description>Discover key advice for aspiring web creators to build a strong foundation in coding and user interface design.</description>
      <pubDate>Sat, 31 May 2025 12:51:37 GMT</pubDate>
      <content:encoded><![CDATA[<p><img src="https://ofxqeonyelozjixehdyo.supabase.co/storage/v1/object/public/images/user_2wtUuRPT5LK3kNVkguDKHD90vPe/f597b506-4310-4ea6-bfb9-fe8868cb6f4e-png.png" alt=""></p>
<p>The average person in the United States spends over 7 hours looking at a screen each day, according to Exploding Topics' 2024 screen time statistics. Much of that interaction is with websites and web applications, all brought to life by frontend development. If you're looking to step into this creative and in-demand field, understanding the fundamentals is key for <strong>starting frontend development</strong>.</p>
<h2>Getting Started with Frontend Development</h2>
<p>Frontend development is all about crafting what you directly see and interact with on a website or application. It’s the art and science of transforming design concepts into the responsive, functional digital interfaces that users engage with every day. Think of it as building the 'storefront' of the digital world. While the array of technologies involved might seem like a steep climb at first, remember that consistent effort, a structured approach to learning, and good guidance make mastering these skills entirely achievable and incredibly rewarding. This article will walk you through ten core tips, carefully chosen to help <strong>frontend basics new developers</strong> navigate the early stages of their learning journey and build a solid foundation for a future in this exciting field.</p>
<h2>Tip 1-3: Mastering The Core Trio: HTML, CSS, JavaScript</h2>
<p><img src="https://ofxqeonyelozjixehdyo.supabase.co/storage/v1/object/public/images/user_2wtUuRPT5LK3kNVkguDKHD90vPe/a90da98f-ca3f-4b25-b4b5-89ff8b54910a-png.png" alt=""></p>
<p>At the heart of all web experiences are three cornerstone technologies. Understanding these is non-negotiable for any aspiring frontend developer, as they form the bedrock of all <strong>essential web dev skills</strong>.</p>
<h3>Tip 1: Build Solid Structures with Semantic HTML</h3>
<p>HTML, or HyperText Markup Language, provides the skeleton for your web content. It’s not just about putting text on a page; it’s about structuring it meaningfully. Using <strong>semantic HTML5 tags</strong> like <code>&#x3C;article></code>, <code>&#x3C;nav></code>, <code>&#x3C;header></code>, and <code>&#x3C;footer></code> does more than organize your content. It significantly boosts website accessibility for users relying on assistive technologies and improves how search engines understand your site.</p>
<h3>Tip 2: Master Visual Styling with CSS Fundamentals</h3>
<p>CSS, Cascading Style Sheets, is what brings visual life to your HTML structure. It controls everything from layout and colors to typography and spacing. Key concepts to grasp early include the <strong>box model</strong> (content, padding, border, margin), how <strong>selectors</strong> target HTML elements, and <strong>specificity</strong>, which dictates which styles apply when conflicts arise. For precision in styling, understanding different units is crucial; you can explore more about <a href="https://www.coleruche.com/post/Units-of-Measurements-in-CSS">Units of Measurements in CSS</a> to refine your approach.</p>
<h3>Tip 3: Implement Interactivity using JavaScript Basics</h3>
<p>JavaScript is the engine that powers interactivity and dynamic content on websites. For beginners, focusing on the <strong>HTML CSS JS basics</strong> is key. This means getting comfortable with core programming concepts such as <strong>variables</strong> for storing data, understanding different <strong>data types</strong>, writing <strong>functions</strong> for reusable code, and learning fundamental <strong>Document Object Model (DOM) manipulation</strong> to change webpage content and style in response to user actions.</p>
<h2>Tip 4-6: Adopting Essential Tools and Practices</h2>
<p>Beyond the core languages, certain tools and practices are fundamental to an efficient and professional workflow. Adopting these early will significantly streamline your development process.</p>
<h3>Tip 4: Choose and Master Your Code Editor</h3>
<p>Your code editor is your primary workspace. <strong>Visual Studio Code (VS Code)</strong> is a popular choice for its features and customization. Learn its productivity tools: extensions like Prettier for formatting, Live Server for real-time previews, and ESLint for error checking, plus keyboard shortcuts and the integrated terminal. This is one of the <strong>essential web dev skills</strong> to cultivate.</p>
<h3>Tip 5: Implement Version Control with Git Early On</h3>
<p>Git is an indispensable tool for <strong>source code management</strong>. Even if you're working on solo projects, using Git from the start is a best practice. It allows you to track changes, revert to previous stable versions if something goes wrong, and is crucial for collaboration. Get comfortable with basic commands:</p>
<ul>
<li>
<p><code>git add</code>: Stage changes for commit.</p>
</li>
<li>
<p><code>git commit -m "commit message"</code>: Save staged changes with a descriptive message.</p>
</li>
<li>
<p><code>git push</code>: Upload local commits to a remote repository.</p>
</li>
<li>
<p><code>git pull</code>: Fetch and merge changes from a remote repository.</p>
</li>
<li>
<p><code>git branch &#x3C;branch-name></code>: Create a new branch.</p>
</li>
<li>
<p><code>git checkout &#x3C;branch-name></code>: Switch to a different branch.</p>
</li>
</ul>
<h3>Tip 6: Leverage Browser Developer Tools for Debugging</h3>
<p>Modern browsers like Chrome, Firefox, and Edge offer powerful developer tools. Use them for <strong>inspecting HTML and CSS</strong>, debugging JavaScript using breakpoints and variable inspection, analyzing performance, and monitoring network requests. Mastering the inspector, console, and network tabs is crucial. For a practical walkthrough, Mozilla Developer Network's guide on <a href="https://developer.mozilla.org/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">What are browser developer tools?</a> is an excellent resource.</p>
<h2>Tip 7-9: Building and Learning Effectively</h2>
<p><img src="https://ofxqeonyelozjixehdyo.supabase.co/storage/v1/object/public/images/user_2wtUuRPT5LK3kNVkguDKHD90vPe/a371905f-45a1-4732-a9a6-38369aad828a-png.png" alt=""></p>
<p>Knowing the languages and tools is one thing; applying that knowledge effectively is another. These next tips focus on how to truly solidify your skills and build for the modern web.</p>
<h3>Tip 7: Solidify Knowledge by Building Small, Tangible Projects</h3>
<p>To truly <strong>learn frontend development</strong>, you must move beyond tutorials and build. Hands-on practice solidifies concepts and hones problem-solving. Start with small, tangible projects like:</p>
<ul>
<li>
<p>A <strong>personal portfolio</strong> to showcase your work.</p>
</li>
<li>
<p>A simple <strong>to-do list app</strong> for JavaScript and DOM practice.</p>
</li>
<li>
<p>Replicating a basic webpage layout to apply HTML and CSS.</p>
</li>
<li>
<p>A basic calculator for logic.</p>
</li>
<li>
<p>A weather app using a free API for data handling.</p>
</li>
</ul>
<h3>Tip 8: Prioritize Learning Responsive Design Principles</h3>
<p>Websites must look and work well on all devices. <strong>Responsive design is crucial</strong>, especially with high mobile usage in the US. Key techniques include:</p>
<ul>
<li>
<p><strong>Fluid grids</strong> using relative units.</p>
</li>
<li>
<p><strong>Flexible images and media</strong> that scale correctly.</p>
</li>
<li>
<p><strong>CSS Media Queries</strong> to apply styles based on device features like screen width.</p>
</li>
</ul>
<p>Mastering these ensures a good user experience for everyone.</p>
<h3>Tip 9: Write, Write, and Write Some More!</h3>
<p>A very important tip I am glad I caught early on in my career is the importance and art of writing. It is not enough to learn all you will. It is super important to teach these online as well. Set up your own hosted blog, or simply write on Medium. </p>
<p>Blogging forces you to organize your thoughts, spot gaps in your understanding, and retain knowledge better. It also builds your online footprint, shows proof of your growth, and helps others learn—turning you from just a learner into a contributor. Mohab dives deeper into the importance of writing in this <a href="https://medium.com/write-a-catalyst/an-article-a-day-keeps-the-9-5-away-ac4952bc3771">Medium article.</a></p>
<p>Given that there are so many platforms to publish to (Medium, DEV, Hashnode, Ghost, etc), it makes it daunting to write and effectively get your content wide. But with tools like <a href="https://trycrosspost.com">Crosspost</a>, you can publish your articles once and effortlessly share them across platforms like Medium, Dev.to, and Substack—so more people benefit from what you’ve learned.</p>
<h2>Tip 10-11: Advancing Your Frontend Skills</h2>
<p>Once you have a firm grasp of the fundamentals, you can start exploring more advanced tools and cultivate habits for long-term growth in this dynamic field.</p>
<h3>Tip 10: Consider a JavaScript Framework or Library After Mastering Basics</h3>
<p>Once HTML, CSS, and vanilla JavaScript are solid, consider a framework like React, Vue.js, or Angular. These tools offer <strong>pre-built components and patterns</strong> for building complex UIs efficiently. But don't rush; strong fundamentals are key. Frameworks like React JS simplify tasks such as <a href="https://www.coleruche.com/post/uploading-images-to-REST-API-backend-in-React-JS">uploading images to a REST API backend in React JS</a>. To understand React's popularity, resources like freeCodeCamp's <a href="https://www.freecodecamp.org/news/tag/react/">React.js for Beginners – A 2024 Tutorial</a> are helpful.</p>
<h3>Tip 11: Cultivate a Habit of Continuous Learning and Curiosity</h3>
<p>Frontend development is always changing. To effectively <strong>learn frontend development</strong> and stay current, adopt a mindset of <strong>lifelong learning</strong>. Stay updated by:</p>
<ul>
<li>
<p>Reading industry blogs.</p>
</li>
<li>
<p>Following official documentation.</p>
</li>
<li>
<p>Engaging with developer communities like Stack Overflow, Dev.to, Reddit, or local US meetups.</p>
</li>
<li>
<p>Taking online courses for deeper dives.</p>
</li>
</ul>
<p>This keeps your skills sharp.</p>
<h2>Your Next Steps in Frontend</h2>
<p>Where do you go from here? With these insights, your frontend journey is off to a strong start.</p>
<p><strong>Recapping Your Foundational Toolkit</strong>: These ten <strong>beginner frontend tips</strong> provide a solid launchpad, covering core practices and knowledge to build upon.</p>
<p><strong>The Ongoing Journey of a Developer</strong>: Frontend development is a continuous process of learning, problem-solving, and adapting. Be patient, persist through challenges, and celebrate your progress. Every problem solved is a step forward.</p>
<p><strong>Finding Resources and Community Support</strong>: Seek quality learning materials. In-depth tutorials and practical guides can be found online everywhere, like on <a href="https://www.coleruche.com/blog">my blog</a> Connect with other developers through online communities or local US-based groups. Sharing knowledge and getting support is invaluable. The path of a frontend developer is rewarding, full of creative opportunities.</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/the-ultimate-guide-to-streamlined-publishing-for-w-044085bb</guid>
      <title>The Ultimate Guide to Streamlined Publishing for Writers and Bloggers</title>
      <link>https://coleruche.com/post/the-ultimate-guide-to-streamlined-publishing-for-w-044085bb</link>
      <description>A Better Way for Writers to Publish Across Platforms, Save Time, and Grow Readership</description>
      <pubDate>Wed, 28 May 2025 17:25:17 GMT</pubDate>
      <content:encoded><![CDATA[<p><img src="https://cdn-images-1.medium.com/max/768/1*0aW6VeNdBMdZLWG-JGhWiw@2x.jpeg" alt=""></p>
<p>In an environment brimming with content, getting your voice heard requires more than just compelling writing. Many creators find their carefully crafted articles reach only a fraction of their potential audience. This guide explores how a smart approach to publishing can amplify your message, helping you connect with more readers without multiplying your workload.</p>
<h3>The Modern Writer’s Publishing Challenge</h3>
<p>The digital landscape presents a curious paradox for writers and bloggers. While opportunities to share work have never been more abundant, the path to visibility is often cluttered with repetitive tasks and strategic dilemmas. The core issue is that creating great content is only half the battle; distributing it effectively is the other, often more complex, half.</p>
<p>There’s a growing expectation to <strong>publish on multiple platforms</strong>. Readers congregate in different digital spaces. Platforms like Medium attract a broad audience interested in diverse topics, Dev.to serves as a hub for the developer community, personal blogs offer a dedicated space for an author’s unique brand, and LinkedIn Articles cater to professional networking and industry insights. To truly grow an audience, a presence across several of these is becoming less of a choice and more of a necessity. Each platform offers access to distinct reader segments, and neglecting them means leaving potential engagement on the table.</p>
<p>This multi-platform ambition, however, often leads to a significant time sink through manual publishing. Writers frequently describe the frustration of adapting formatting for each site, the mind-numbing repetition of uploading, tagging, and scheduling content multiple times. These tasks, while seemingly small individually, accumulate, diverting precious hours away from the primary activities of writing, researching, and engaging with readers. It’s a drain that many creators feel acutely, wondering if the effort to reach wider is worth the sacrifice in creative output.</p>
<p>Beyond the time commitment, maintaining consistency and brand voice across these varied channels presents another hurdle. When managing multiple platforms manually, ensuring uniform quality, tone, style, and even simple branding elements like author bios or calls to action becomes a juggling act. The risk of inconsistencies is high, potentially diluting a writer’s carefully cultivated brand identity or, worse, confusing their audience with mixed messages or varying presentation standards.</p>
<p>Ultimately, content confined to a single platform may never reach its full potential impact. This siloed approach means that valuable insights and stories are missed by large swathes of potential readers. The absence of a <strong>streamlined publishing</strong> process translates directly into missed opportunities for broader visibility, engagement, and influence. These are the pain points that drive writers to seek more efficient ways to share their work.</p>
<h3>Foundations of Effective Content Distribution</h3>
<p><img src="https://cdn-images-1.medium.com/max/768/1*6xJS_8fnWqOgFFdBXyMMhQ@2x.jpeg" alt=""></p>
<p>Moving beyond the frustrations of manual publishing requires a strategic shift in thinking. Before diving into tools or techniques, laying a solid foundation for your <strong>content distribution strategy</strong> is essential. This isn’t about working harder, but smarter, ensuring every piece of content has the best possible chance to find its audience.</p>
<p>The first step is <strong>defining your content distribution goals</strong>. What do you hope to achieve with your writing? Are you aiming for increased brand awareness, generating leads for a service, building a vibrant community, or establishing yourself as a thought leader in your niche? Your primary objectives will significantly influence where and how you distribute your content. For instance, if thought leadership is key, platforms that encourage in-depth articles and professional networking might take precedence. Clarity on these aims provides a compass for all subsequent distribution choices.</p>
<p>With goals in mind, the next crucial element is <strong>understanding your audience’s platform preferences</strong>. It’s tempting to cast a wide net, but not all platforms are suitable for all types of content or every target audience. Consider where your ideal readers spend their time. Developers, for example, are likely to frequent Dev.to for technical articles and community discussions, while a more general audience seeking lifestyle or business insights might be more active on Medium. Researching these preferences, perhaps by observing where similar successful creators engage, is vital. For those looking to explore this further, searching for ‘best practices for multi-platform content strategy for bloggers’ can yield valuable resources and deeper insights into audience analysis.</p>
<p>This leads naturally to the principle of ‘<strong>Write Once, Publish Strategically</strong>’. This concept is central to efficient content distribution. It involves creating one high-quality, well-crafted piece of content and then thoughtfully disseminating it across your chosen platforms. The aim is to maximize reach and impact with minimal redundant effort, ensuring your core message is delivered effectively in multiple relevant spaces.</p>
<p>It’s also important to clarify the distinction between <strong>crossposting articles</strong> and content repurposing, as these terms are sometimes used interchangeably. While both are valuable, this guide focuses on the former.</p>
<h4>Crossposting Articles:</h4>
<ul>
<li>
<p>Involves publishing largely the same article across multiple platforms.</p>
</li>
<li>
<p>Focuses on extending the reach of existing written content with minimal changes.</p>
</li>
<li>
<p>Aims for efficiency in distribution to tap into different platform audiences.</p>
</li>
</ul>
<h4>Content Repurposing:</h4>
<ul>
<li>
<p>Involves transforming an existing piece of content into a different format (e.g., an article into a video, podcast episode, or infographic).</p>
</li>
<li>
<p>Focuses on adapting the core message for different consumption preferences and platforms.</p>
</li>
<li>
<p>Often requires more significant creative effort to reformat and re-present the information.</p>
</li>
</ul>
<p>Understanding this difference helps maintain focus on streamlining the direct publishing of your articles to various platforms.</p>
<h3>Actionable Steps to Streamline Your Publishing Process</h3>
<p>Once you have a clear strategy, the next phase involves implementing practical steps to make your publishing workflow more efficient. These actions are designed to reduce friction and free up your time, allowing you to focus more on creation and less on the mechanics of distribution. Many of these can be considered essential <strong>blogging efficiency tips</strong>.</p>
<ol>
<li>
<p><strong>Creating a Master Content Calendar</strong>: A structured content calendar is more than just a schedule; it’s a strategic tool. By planning your content topics, target platforms, and publishing dates in advance, you can maintain a consistent output and coordinate your efforts far more effectively. This visual roadmap helps you see at a glance what needs to be written, edited, and published, preventing last-minute rushes and ensuring a steady flow of content to your audience. It transforms publishing from a reactive task to a proactive strategy.</p>
</li>
<li>
<p><strong>Developing Templates and Basic Style Guides</strong>: Consistency is key to building a recognizable brand, but achieving it manually for every post on every platform can be tedious. Creating simple formatting templates, such as pre-set markdown for Dev.to or standard heading styles for Medium, can save considerable time. Alongside this, a concise style guide outlining your preferred tone, voice, common terminology, and image guidelines ensures that your content maintains a professional and uniform presentation with minimal effort for each new piece. Think of it as creating a kit of parts for quick assembly.</p>
</li>
<li>
<p><strong>Batching Your Publishing Tasks for Efficiency</strong>: The human brain isn’t designed for constant context switching. Grouping similar tasks together, known as batching, can significantly improve focus and productivity. For example, you could dedicate specific blocks of time to writing several articles, then another block to formatting all of them for their respective platforms, and a final block to scheduling or publishing them. This approach minimizes the mental gear-shifting that occurs when you try to do everything for one article before moving to the next. Writers keen on mastering this can find more by searching for ‘content batching techniques for writers productivity’.</p>
</li>
<li>
<p><strong>Optimizing Content for Each Platform (Without Sacrificing Efficiency)</strong>: While the core of streamlined publishing is about using the same fundamental content, minor platform-specific adjustments can enhance performance. This doesn’t mean a full repurposing effort for each platform. Instead, consider small tweaks like crafting unique, compelling titles tailored to what resonates on a particular site, using relevant tags or categories specific to that platform’s discovery system, or slightly modifying introductions or conclusions to better align with the platform’s audience expectations. The goal is to find a practical balance: achieve maximum efficiency from your standardized content while making small, high-impact customizations where they matter most.</p>
</li>
</ol>
<p>By implementing these steps, you can build a more robust and less time-consuming publishing process, allowing your content to work harder for you.</p>
<h3>Choosing the Right Publishing Automation Tools</h3>
<p><img src="https://cdn-images-1.medium.com/max/768/1*VzEvOOPBTI1_CXgW164-BA@2x.jpeg" alt=""></p>
<p>While manual streamlining techniques significantly improve efficiency, leveraging technology through publishing automation tools can further enhance your <strong>streamlined publishing</strong> efforts. These tools are designed to handle the repetitive aspects of distribution, allowing you to focus on what you do best: creating compelling content. Selecting the right tool, however, requires careful consideration of your specific needs.</p>
<p>When evaluating a crossposting solution, there are several <strong>key features to look for</strong>. These functionalities determine how effectively the tool can integrate into your workflow and support your distribution goals:</p>
<ul>
<li>
<p><strong>Support for your primary publishing platforms</strong>: Ensure the tool seamlessly integrates with the platforms you use most, such as Medium, Dev.to, WordPress, or LinkedIn.</p>
</li>
<li>
<p><strong>An intuitive user interface</strong>: The tool should be easy to learn and use. A complicated interface can create more work than it saves.</p>
</li>
<li>
<p><strong>Content scheduling capabilities</strong>: The ability to schedule posts in advance is crucial for maintaining a consistent publishing rhythm without needing to be online at specific times.</p>
</li>
<li>
<p><strong>Effective handling of formatting nuances</strong>: Different platforms have different formatting requirements. A good tool will manage these variations, preserving your content’s intended appearance as much as possible.</p>
</li>
</ul>
<p>The tangible benefits of automation are significant. Specialized tools <strong>minimize manual errors</strong>, such as formatting mistakes, forgotten tags, or missed posts, which can easily occur when juggling multiple platforms. More importantly, they free up substantial amounts of time. This reclaimed time can be reinvested into content creation, research, or, crucially, engaging with your audience. For instance, services like <a href="https://trycrosspost.com/">Crosspost</a> are specifically designed to automate the distribution of articles to platforms like Medium and Dev.to, embodying these efficiencies by simplifying how writers <strong>publish on multiple platforms.</strong></p>
<p>There is a range of publishing tools available, from simple browser extensions that offer basic copying features to comprehensive, dedicated platforms that provide a full suite of management and analytics capabilities. When <strong>evaluating different types of publishing tools</strong>, assess your specific needs. Consider your content volume: are you publishing daily, weekly, or monthly? What is your budget? A solo blogger with a few articles a month might have different requirements than a content team producing daily updates. The aim is to select a solution that is appropriate for your scale and complexity.</p>
<p>Finally, <strong>integrating automation smoothly into your existing workflow</strong> is key to its success. A new tool should complement, not complicate, your creative process. Start by using its core features, focusing on the aspects that provide the most immediate time savings. Gradually explore more advanced options as you become comfortable. The best automation tool is one that feels like a natural extension of your publishing habits, quietly working in the background to amplify your reach.</p>
<h3>Amplifying Your Voice Across Platforms</h3>
<p>Adopting a streamlined, multi-platform publishing approach offers more than just time savings; it fundamentally changes how your voice resonates in the digital sphere. The strategies and tools discussed are not merely about efficiency, but about maximizing the impact of your hard-earned content and building a stronger, more visible presence as a writer or blogger.</p>
<p>The most immediate outcome is the <strong>multiplier effect on reaching diverse audiences</strong>. When you <strong>publish on multiple platforms</strong>, you significantly broaden your content’s exposure. Each platform, be it Medium, Dev.to, or your personal blog, cultivates a unique user base with distinct interests and consumption habits. Effective <strong>crossposting articles</strong> allows you to tap into these varied communities, helping to <strong>increase blog reach</strong> far beyond what a single outlet could achieve. It’s about meeting readers where they are, rather than hoping they find you in one isolated corner of the internet.</p>
<p>There are also <strong>SEO considerations for strategic crossposting</strong>. Distributing your content on reputable platforms like Medium and Dev.to can contribute positively to your overall online visibility, partly due to their high domain authority. While concerns about content duplication sometimes arise, many platforms utilize mechanisms like canonical tags to indicate the original source to search engines. For many creators, the substantial benefit of increased reach and referral traffic from these authoritative sites often outweighs minor SEO complexities, especially when content is shared thoughtfully.</p>
<p>Furthermore, a regular and consistent appearance on multiple relevant platforms works to <strong>build a consistent brand presence and authority</strong>. When readers encounter your insightful articles across different channels, it reinforces your expertise and strengthens your personal or professional brand. This sustained visibility helps establish you as a knowledgeable and reliable voice in your niche, fostering trust and credibility over time. Each piece of content becomes another touchpoint, solidifying your reputation.</p>
<p>Finally, it’s crucial to remember that <strong>streamlined publishing</strong> is not just about the act of distribution; it also frees up invaluable time for <strong>engagement post-publishing</strong>. The efficiency gained means you have more capacity to interact with comments, respond to questions, and participate in discussions on each platform where your content appears. This interaction is vital for fostering a community around your work, gathering feedback for future content, and building genuine relationships with your readers. Ultimately, effective publishing is a means to a greater end: meaningful connection and amplified impact.</p>
<p><img src="https://medium.com/_/stat?event=post.clientViewed&#x26;referrerSource=full_rss&#x26;postId=a8ef65760c7b" alt=""></p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/automating-the-generation-of-markdown-articles-wit-e34855dd</guid>
      <title>Automating the generation of Markdown articles with Crosspost</title>
      <link>https://coleruche.com/post/automating-the-generation-of-markdown-articles-wit-e34855dd</link>
      <description>Learn how to automatically generate new Markdown files for your blog using Crosspost</description>
      <pubDate>Wed, 21 May 2025 00:00:29 GMT</pubDate>
      <content:encoded><![CDATA[<p><img src="https://cdn-images-1.medium.com/max/1024/0*jeUgn82PyYc_zma4" alt=""></p>
<p>Photo by <a href="https://unsplash.com/@glamorousplanning?utm_source=medium&#x26;utm_medium=referral">Alexa Williams</a> on <a href="https://unsplash.com/?utm_source=medium&#x26;utm_medium=referral">Unsplash</a></p>
<p>Today, it is not a new practice to <a href="https://javascript.plainenglish.io/getting-started-with-markdown-pages-in-gatsbyjs-a6879909c5e9">use</a> <a href="https://medium.com/swlh/how-to-create-blog-posts-from-markdown-with-gatsby-in-2021-80636d6ca8e9">Markdown</a> <a href="https://www.coleruche.com/post/My-Top-5-Plugins-for-a-GatsbyJS-Powered-Blog">files</a> as a <a href="https://daext.com/blog/blogging-with-markdown-all-you-need-to-know/">data</a> <a href="https://www.reddit.com/r/reactjs/s/eyMC9fzpml">source</a> for (statically generated) blogs. I use it to write on <a href="http://coleruche.com/">my blog</a>, powered by Next.js and Vercel.</p>
<p>It comes with a number of advantages:</p>
<p><strong>1. Simplicity and Focus:</strong> Markdown is easy to read and write. Its minimal syntax lets you focus on content, not formatting, making it perfect for distraction-free writing.</p>
<p>2. <strong>Portability:</strong> Markdown files are plain text, meaning they’re lightweight, cross-platform, and can be opened or edited with any text editor or version control system.</p>
<p><strong>3. Version Control Friendly:</strong> Because Markdown is plain text, it works seamlessly with Git. You can easily track changes, collaborate via pull requests, and roll back edits.</p>
<p><strong>4. Static Site Compatibility:</strong> Static site generators like Next.js, Gatsby, Jekyll, and Hugo support Markdown natively, making it ideal for content-driven sites and blogs.</p>
<p><strong>5. Flexible Output:</strong> Markdown can be converted to HTML, PDF, DOCX, and more using tools like Pandoc or markdown parsers—great for repurposing content across platforms.</p>
<p>Modern blogs powered by static site generators like Next.js, Gatsby, Jekyll, and Hugo often rely on Markdown files for managing content. However, manually writing .md files and committing them to your repo for every blog post can be tedious. That’s where Crosspost’s Webhook integration feature comes in. It enables you to automate the creation of Markdown files from posts you write once, streamlining publishing across your blog and third-party platforms.</p>
<h4>Understanding the workflow</h4>
<p>Here’s how I use it:</p>
<p>The integration involves setting up a webhook that listens for new content events from Crosspost and providing this webhook’s URL to Crosspost. When a new article is published (or cross-posted) on Crosspost, Crosspost sends out event data to the provided webhook URL. The webhook triggers a function that:</p>
<p><strong>1. Receives the article data:</strong> Captures the title, content, and metadata, etc.<br>
<strong>2. Generates a Markdown file:</strong> Formats the content into Markdown syntax and saves it in your project’s designated folder.<br>
<strong>3. Commits to Version Control:</strong> Checks out the current branch to a new one, creates and commits the new file to your Git repository while maintaining a history of changes, and automatically opens a new pull request for the new article file.<br>
<strong>4. Triggers a site rebuild</strong>: If you’re using platforms like Netlify or Vercel, the new commit (and PR) can automatically trigger a site rebuild, giving you a preview of the new article. You can then simply merge the new PR, publishing your new content live.</p>
<h4>Writing the webhook</h4>
<p>As I mentioned, my blog is built on Next.js and deployed to Vercel. However, this will work almost the same way with little adjustments to suit your tech stack.</p>
<p>To get this to work, you will need some external packages:</p>
<ol>
<li><a href="https://github.com/octokit/octokit.js">Octokit</a>: Octokit is GitHub’s official JavaScript/TypeScript client for interacting with the GitHub REST and GraphQL APIs. It allows developers to programmatically manage repositories, issues, pull requests, commits, and more using simple, structured methods.</li>
<li><a href="https://www.npmjs.com/package/turndown/v/4.0.0-rc.1">Turndown</a>: Turndown is a JavaScript library that converts HTML into clean, structured Markdown.</li>
</ol>
<p>To install these packages, run the command:</p>
<pre><code>yarn add @octokit/rest turndown
</code></pre>
<p>You will also need to create a GitHub personal access token (PAT) to authorize the creation of the remote branch and pull request. Visit the <a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-fine-grained-personal-access-token">official documentation</a> to create your PAT and provide the necessary Read and Write permissions.</p>
<p><img src="https://cdn-images-1.medium.com/max/1024/1*6cWfnbGs34qzFN9Dy4QNeQ.png" alt=""></p>
<p>Required permissions for GitHub PATs</p>
<p>It is advised to verify webhooks (of any source and type) to make sure they are intended and coming from the right source. Crosspost generates and provides a webhook secret, which can be found on the Webhook integration screen and is subsequently set in the <strong>X-Webhook-Signature</strong> header of the webhook POST calls. This can be used to confirm the call is actually coming from Crosspost and no one else who knows your webhook endpoint will send unwanted or malicious data to it.</p>
<p><img src="https://cdn-images-1.medium.com/max/1024/1*M6WQllv-LuhuZV7euq9pUA.png" alt=""></p>
<p>Screenshot highlighting the webhook secret from Crosspost</p>
<p>Take care to store these highly sensitive tokens <a href="https://medium.com/@oadaramola/a-pitfall-i-almost-fell-into-d1d3461b2fb8">securely in a .env file</a>. Never commit sensitive keys to git.</p>
<p>The next step is to create a new <a href="https://nextjs.org/docs/app/building-your-application/routing/route-handlers">route handler</a>. In this file, I added the code below:</p>
<pre><code>import { Octokit } from '@octokit/rest'  
import { NextResponse } from 'next/server'  
import TurndownService from 'turndown'  
  
const REPO\_OWNER = 'your\_gh\_username'  
const REPO\_NAME = 'your\_blog\_repo\_name'  
const POSTS\_PATH = 'src/content/posts' // or path to your posts directory  
const GITHUB\_TOKEN = process.env.GITHUB\_TOKEN // your GH PAT, securely written in a .env file  
  
function slugify(str: string) {  
  return str  
    .toLowerCase()  
    .replace(/\[^a-z0-9\]+/g, '-')  
    .replace(/^-+|-+$/g, '')  
    .substring(0, 50)  
}  
  
export async function POST(request: Request) {  
  try {  
    // verify webhook signature from Crosspost  
    const signature = request.headers.get('X-Webhook-Signature')  
    const expectedSignature = process.env.AUTO\_PUBLISH\_WEBOOK\_SECRET // your Crosspost webook verification token  
    if (!signature || signature !== expectedSignature) {  
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })  
    }  
  
    const body = await request.json()  
    const {  
      id,  
      title,  
      description,  
      html\_content,  
      publishedAt,  
      slug,  
      canonicalUrl,  
      tags,  
    } = body  
  
    if (!title || !html\_content || !slug) {  
      throw new Error(  
        'One of the following required fields is missing: title, html\_content, slug',  
      )  
    }  
  
    if (!GITHUB\_TOKEN) {  
      throw new Error('Missing Github token in env')  
    }  
  
    // Convert HTML to Markdown  
    const turndownService = new TurndownService()  
    const markdownContent = turndownService.turndown(html\_content)  
  
    // Prepare frontmatter.   
    // This may differ from your own frontmatter structure  
    const frontmatter = \`---  
title: "${title.replace(/"/g, '"')}"  
description: "${description ? description.replace(/"/g, '"') : ''}"  
cover\_image: ""  
altText: "${title.replace(/"/g, '"')}"  
keywords: \[${(tags || \[\]).map((t: string) => \`"${t}"\`).join(', ')}\]  
published: true  
date: "${publishedAt || new Date().toISOString()}"  
canonicalUrl: "${canonicalUrl || ''}"  
originalId: "${id}"  
\---  
\`  
  
    const fileContent = \`${frontmatter}  
${markdownContent}  
\`  
  
    const fileName = \`${slug}.md\`  
    const filePath = \`${POSTS\_PATH}/${fileName}\`  
    const branchName = slugify(title) + '-' + new Date().getTime()  
  
    // Initialize Octokit  
    const octokit = new Octokit({ auth: GITHUB\_TOKEN })  
  
    // Get the default branch  
    const repo = await octokit.repos.get({ owner: REPO\_OWNER, repo: REPO\_NAME })  
    const defaultBranch = repo.data.default\_branch  
  
    // Create a new branch from the default branch  
    const defaultBranchRef = await octokit.git.getRef({  
      owner: REPO\_OWNER,  
      repo: REPO\_NAME,  
      ref: \`heads/${defaultBranch}\`,  
    })  
  
    await octokit.git.createRef({  
      owner: REPO\_OWNER,  
      repo: REPO\_NAME,  
      ref: \`refs/heads/${branchName}\`,  
      sha: defaultBranchRef.data.object.sha,  
    })  
  
    // Create the file in the new branch  
    await octokit.repos.createOrUpdateFileContents({  
      owner: REPO\_OWNER,  
      repo: REPO\_NAME,  
      path: filePath,  
      message: \`Add new post: ${title}\`,  
      content: Buffer.from(fileContent).toString('base64'),  
      branch: branchName,  
    })  
  
    // Create PR  
    const pr = await octokit.pulls.create({  
      owner: REPO\_OWNER,  
      repo: REPO\_NAME,  
      title: \`New post: ${title}\`,  
      head: branchName,  
      base: defaultBranch,  
      body: \`Automated PR to add new post: ${title}\`,  
    })  
  
    return NextResponse.json({ pr\_url: pr.data.html\_url })  
  } catch (e) {  
    console.warn(e)  
    let message = 'Unknown error'  
    if (typeof e === 'object' &#x26;&#x26; e &#x26;&#x26; 'message' in e) {  
      message = (e as { message: string }).message  
    } else if (typeof e === 'string') {  
      message = e  
    }  
    return NextResponse.json({ error: message }, { status: 500 })  
  }  
}
</code></pre>
<p>Code comments have been added to this file to explain what each block of code does. Also, note that my frontmatter (and generally, the Markdown content) structure may differ from what you have. So format accordingly. If all goes right, which it should, you will be able to see the new PR generated for you.</p>
<p>Here’s a <a href="https://www.loom.com/share/79e2e7c2db2c4f8ca5809b470e1f6cdb?sid=49043912-4e66-42ab-a628-cd4f91d106c2">demo</a> showing this in action.</p>
<p><img src="https://medium.com/_/stat?event=post.clientViewed&#x26;referrerSource=full_rss&#x26;postId=f06aeb49b7a4" alt=""></p>
<hr>
<p><a href="https://medium.com/write-once/automating-the-generation-of-markdown-articles-with-crosspost-f06aeb49b7a4">Automating the generation of Markdown articles with Crosspost</a> was originally published in <a href="https://medium.com/write-once">Write Once</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/why-crossposting-your-articles-is-a-superpower-if--a70f525b</guid>
      <title>Why Crossposting Your Articles Is a Superpower (If You Do It Right)</title>
      <link>https://coleruche.com/post/why-crossposting-your-articles-is-a-superpower-if--a70f525b</link>
      <description>Learn how to crosspost articles the right way to boost reach, protect SEO, and save time—plus a tool to automate it all.</description>
      <pubDate>Sat, 17 May 2025 12:30:50 GMT</pubDate>
      <content:encoded><![CDATA[<p><img src="https://cdn-images-1.medium.com/max/1024/1*6Uzc-8AEGXwzn-BIOidLMQ@2x.jpeg" alt=""></p>
<p>Photo by Joe Green on <a href="https://unsplash.com/?utm_source=medium&#x26;utm_medium=referral">Unsplash</a></p>
<p>In today’s crowded digital landscape, writing great content is no longer enough. You need to make sure it reaches the right audience — and often, that means more than one platform.</p>
<p>This is where crossposting becomes your secret weapon. But while the idea seems simple — publish the same article across Medium, Dev.to, Hashnode, etc. — the execution is often messy. Done wrong, it can hurt your SEO, confuse readers, or make your content look spammy.</p>
<p>Done right? It multiplies your reach, builds your brand, and drives lasting traffic.</p>
<p>Let’s break it down.</p>
<h3>What Exactly Is Crossposting?</h3>
<p>Crossposting is the practice of sharing the same piece of content on multiple platforms. For example, you might publish an article on your blog, then repost it to Medium, Dev.to, and Hashnode to get in front of different communities.</p>
<p>But there’s a key distinction: crossposting is not copy-pasting.</p>
<p>Done properly, crossposting involves:</p>
<ul>
<li>Using canonical links to point search engines to the original</li>
<li>Adapting content slightly for each platform’s audience</li>
<li>Respecting formatting quirks of each platform</li>
</ul>
<h3>Why Crossposting Works</h3>
<p>Here’s what you gain when you crosspost strategically:</p>
<h4>More Reach for Less Work</h4>
<p>Every platform has its own audience. By publishing on multiple sites, you tap into readers who may never discover your blog on its own.</p>
<h4>SEO Benefits (If You Use Canonical URLs)</h4>
<p>Canonical links tell Google which version is the “original,” avoiding duplicate content penalties. When done right, crossposting can actually boost your SEO with more backlinks and discoverability.</p>
<h4>Audience Growth Across Platforms</h4>
<p>Each community has its own vibe. Crossposting lets you plant flags in all of them, growing a diverse and loyal readership.</p>
<h4>Future-Proofing Your Content</h4>
<p>If a platform disappears (looking at you, Medium paywall experiments…), you’ve still got your work elsewhere. Think of it as content diversification.</p>
<h3>The Pitfalls of Crossposting (and How to Avoid Them)</h3>
<p>Let’s be honest: crossposting can be annoying.</p>
<p><img src="https://cdn-images-1.medium.com/max/1024/1*CvhikLU8PwooANRFN4rsdQ@2x.jpeg" alt=""></p>
<p>Photo by 傅甬 华 on <a href="https://unsplash.com/?utm_source=medium&#x26;utm_medium=referral">Unsplash</a></p>
<ul>
<li>You format your post in Markdown for Dev.to… but Medium wants rich text.</li>
<li>You forget to add a canonical tag… and now Google thinks you plagiarized yourself.</li>
<li>You’re copying, pasting, editing, tweaking… again and again.</li>
</ul>
<p>This tedious, error-prone process is why many creators avoid crossposting entirely — or do it badly.</p>
<h3>How to Crosspost Like a Pro</h3>
<p>To do this right:</p>
<ul>
<li><strong>Customize the intro</strong> for each platform’s tone</li>
<li><strong>Use canonical URLs</strong> to signal original authorship</li>
<li><strong>Adjust formatting</strong> for each platform’s quirks</li>
<li><strong>Space out your posts</strong> to avoid overlapping traffic</li>
<li><strong>Track performance</strong> across platforms</li>
</ul>
<p>It’s a lot. Which is why I built a tool to help.</p>
<h3>Meet Crosspost</h3>
<p>I built <a href="https://trycrosspost.com/">Crosspost</a> to scratch my own itch: I was tired of wasting time manually republishing my content.</p>
<p><img src="https://cdn-images-1.medium.com/max/1024/1*ZSQV-0leiUGE-HFyuk0kTw@2x.jpeg" alt=""></p>
<p>Photo by Madison Oren on <a href="https://unsplash.com/?utm_source=medium&#x26;utm_medium=referral">Unsplash</a></p>
<p>With Crosspost, you can:</p>
<ul>
<li><strong>Write once</strong></li>
<li><strong>Publish everywhere</strong> (Medium, Dev.to, Hashnode , Notion, etc— with more on the way)</li>
<li>Automatically handle canonical tags, formatting, and syncing</li>
</ul>
<p>It’s built for developers, indie hackers, and technical writers who want to spend more time writing and less time formatting.</p>
<p>Your content deserves more reach. Crossposting is a smart, high-leverage way to get it — if you do it properly.</p>
<p>And now, with the right tools, that’s easier than ever.</p>
<p>So the next time you publish something you’re proud of, don’t leave it sitting in one place. Spread it. Share it. <a href="https://trycrosspost.com/">Crosspost</a> it.</p>
<p><img src="https://medium.com/_/stat?event=post.clientViewed&#x26;referrerSource=full_rss&#x26;postId=7aa77b9e7282" alt=""></p>
<hr>
<p><a href="https://medium.com/write-once/why-crossposting-your-articles-is-a-superpower-if-you-do-it-right-7aa77b9e7282">Why Crossposting Your Articles Is a Superpower (If You Do It Right)</a> was originally published in <a href="https://medium.com/write-once">Write Once</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/understanding-server-actions-in-nextjs-14-198e5a2a-198e5a2a</guid>
      <title>Understanding Server Actions in Next.js 14</title>
      <link>https://coleruche.com/post/understanding-server-actions-in-nextjs-14-198e5a2a-198e5a2a</link>
      <description>A quick guide to Server Actions in Next.js 14 and how they simplify full-stack development.</description>
      <pubDate>Sun, 11 May 2025 19:08:41 GMT</pubDate>
      <content:encoded><![CDATA[<p>Next.js, a popular React framework, continues to evolve, and with the release of version 14, it introduced a powerful feature known as Server Actions. This addition is designed to streamline the development process, enhance the user experience, and improve performance. In this article, we will delve into what Server Actions are, their benefits, and how to implement them effectively in your Next.js applications.</p>
<h4>What are Server Actions?</h4>
<p>Server Actions in Next.js 14 allow developers to define functions that run on the server, enabling them to perform tasks such as data fetching, form submissions, and other server-side logic without the need for additional API routes. This capability simplifies the architecture of applications by integrating server-side functionality directly into components, promoting a more cohesive development experience.</p>
<p>At their core, Server Actions are functions that can be invoked directly from client components. When a Server Action is called, it executes on the server, allowing you to harness the full power of your backend without the overhead of HTTP requests. This results in faster responses and a more seamless interaction for users.</p>
<h4>Benefits of Using Server Actions</h4>
<h4>1. <strong>Improved Performance</strong></h4>
<p>One of the standout advantages of Server Actions is their ability to enhance performance. Since these functions execute on the server, they can access server resources directly, which reduces latency. By minimizing the number of round trips between the client and server, applications can respond more quickly to user interactions.</p>
<h4>2. <strong>Simplified Codebase</strong></h4>
<p>With Server Actions, developers can eliminate the need for separate API endpoints for many common tasks. This results in a cleaner, more maintainable codebase. Instead of juggling multiple files and routes, you can encapsulate server logic directly within your components, leading to a more intuitive project structure.</p>
<h4>3. <strong>Easier Data Management</strong></h4>
<p>Server Actions facilitate better control over data flows in your application. By handling data fetching and manipulation directly on the server, you can manage state more effectively, reducing the complexity often associated with client-side data handling.</p>
<h4>4. <strong>Enhanced Security</strong></h4>
<p>With server-side execution, sensitive operations such as authentication, database access, and third-party API calls can be better secured. Server Actions help to prevent exposure of sensitive logic to the client, reducing the risk of malicious attacks.</p>
<h4>Implementing Server Actions</h4>
<p>To harness the power of Server Actions in your Next.js 14 application, follow these steps:</p>
<h4>Step 1: Define a Server Action</h4>
<p>You can define a Server Action by creating an async function within your component file. For example:</p>
<pre><code>// app/page.js  
export const myServerAction = async (data) => {  
    // Perform some server-side logic, such as database operations  
    const result = await database.save(data);  
    return result;  
};
</code></pre>
<h4>Step 2: Call the Server Action from the Client</h4>
<p>You can invoke your Server Action from a client component using an event handler. This can be done in a form submission or any other user interaction:</p>
<pre><code>// app/components/MyForm.js  
'use client';  
  
import { myServerAction } from '../page';  
  
const MyForm = () => {  
    const handleSubmit = async (event) => {  
        event.preventDefault();  
        const formData = new FormData(event.target);  
        const result = await myServerAction(formData);  
        console.log(result);  
    };  
  
    return (  
        &#x3C;form onSubmit={handleSubmit}>  
            &#x3C;input type="text" name="data" required />  
            &#x3C;button type="submit">Submit&#x3C;/button>  
        &#x3C;/form>  
    );  
};
</code></pre>
<h4>Step 3: Handling Responses</h4>
<p>Once the Server Action is executed, you can handle the response within your client component. This could involve updating the UI, displaying messages, or redirecting users based on the outcome of the server operation.</p>
<h4>Best Practices</h4>
<p>When using Server Actions, consider the following best practices:</p>
<ul>
<li><strong>Keep Actions Focused</strong>: Each Server Action should perform a single responsibility. This makes it easier to debug and reuse your actions across different components.</li>
<li><strong>Error Handling</strong>: Implement robust error handling within your Server Actions. This ensures that your application can gracefully handle failures and provide meaningful feedback to users.</li>
<li><strong>Optimize for Performance</strong>: Be mindful of any heavy operations within your Server Actions. Utilize caching strategies where appropriate to enhance performance further.</li>
</ul>
<h4>Conclusion</h4>
<p>Server Actions in Next.js 14 represent a significant leap forward in simplifying server-client interactions. By allowing developers to run server-side logic directly within components, they improve performance, reduce complexity, and enhance security. As you explore this feature, you’ll find new ways to streamline your development process and create more responsive applications. Embrace Server Actions, and watch your Next.js applications reach new heights of efficiency and user satisfaction.</p>
<p><img src="https://medium.com/_/stat?event=post.clientViewed&#x26;referrerSource=full_rss&#x26;postId=7a5bd72b7f8e" alt=""></p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/ReactNode-vs-React-Element</guid>
      <title>ReactNode vs React.Element: Understanding the Difference</title>
      <link>https://coleruche.com/post/ReactNode-vs-React-Element</link>
      <description>An in-depth look at ReactNode and React.Element, their differences, use cases, and best practices in React development.</description>
      <pubDate>Thu, 22 Aug 2024 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>In the world of React development, especially when working with TypeScript, you'll often encounter two important types: <code>ReactNode</code> and <code>React.Element</code>. While they might seem similar at first glance, understanding their differences is crucial for writing clean, type-safe React code. In this article, we'll dive deep into what these types represent, how they differ, and when to use each one.</p>
<h2>What is ReactNode?</h2>
<p><code>ReactNode</code> is a type that represents any type of React content that can be rendered. It's a union type that includes:</p>
<ul>
<li>React elements (created via JSX)</li>
<li>Strings</li>
<li>Numbers</li>
<li>Arrays or fragments of the above</li>
<li>null</li>
<li>undefined</li>
<li>booleans</li>
</ul>
<p>Here's the TypeScript definition:</p>
<pre><code class="language-typescript">type ReactNode = React.ReactElement | string | number | React.ReactFragment | React.ReactPortal | boolean | null | undefined;
</code></pre>
<h2>What is React.Element?</h2>
<p><code>React.Element</code> is a more specific type that represents a React element, which is the object returned by <code>React.createElement()</code> or JSX expressions. It's a concrete object with a specific structure.</p>
<p>Here's a simplified version of its TypeScript definition:</p>
<pre><code class="language-typescript">interface ReactElement&#x3C;P = any, T extends string | JSXElementConstructor&#x3C;any> = string | JSXElementConstructor&#x3C;any>> {
  type: T;
  props: P;
  key: Key | null;
}
</code></pre>
<h2>Key Differences</h2>
<ul>
<li>
<p><strong>Scope</strong>: <code>ReactNode</code> is broader and includes <code>React.Element</code> as well as primitive types and arrays. <code>React.Element</code> is more specific and only represents React elements.</p>
</li>
<li>
<p><strong>Usage</strong>: <code>ReactNode</code> is often used for component children or any prop that can accept various types of renderable content. <code>React.Element</code> is used when you specifically need a React element.</p>
</li>
<li>
<p><strong>Nullability</strong>: <code>ReactNode</code> can be <code>null</code> or <code>undefined</code>, while <code>React.Element</code> cannot.</p>
</li>
<li>
<p><strong>Type Safety</strong>: <code>React.Element</code> provides more type safety as it ensures you're working with a React element structure.</p>
</li>
</ul>
<h2>When to Use ReactNode</h2>
<p>Use <code>ReactNode</code> when:</p>
<ul>
<li>Defining the type for children props.</li>
<li>Working with content that could be of various types (elements, strings, numbers, etc.).</li>
<li>Creating flexible components that can render different types of content.</li>
</ul>
<p>Example:</p>
<pre><code class="language-typescript">interface Props {
  content: React.ReactNode;
}

const FlexibleComponent: React.FC&#x3C;Props> = ({ content }) => {
  return &#x3C;div>{content}&#x3C;/div>;
};
</code></pre>
<h2>When to Use React.Element</h2>
<p>Use <code>React.Element</code> when:</p>
<ul>
<li>You specifically need a React element and want to ensure type safety</li>
<li>Working with higher-order components or render props that deal with elements</li>
<li>Manipulating or analyzing the structure of React elements</li>
</ul>
<p>Example:</p>
<pre><code class="language-typescript">interface Props {
  element: React.ReactElement;
}

const ElementWrapper: React.FC&#x3C;Props> = ({ element }) => {
  return &#x3C;div className="wrapper">{React.cloneElement(element, { className: 'modified' })}&#x3C;/div>;
};
</code></pre>
<h2>Best Practices</h2>
<ul>
<li>
<p><strong>Default to ReactNode</strong>: When in doubt, especially for component children, use <code>ReactNode</code>. It provides more flexibility.</p>
</li>
<li>
<p><strong>Use React.Element for Specificity</strong>: When you need to ensure you're working with a React element and want to leverage its properties (like <code>type</code> or <code>props</code>), use <code>React.Element</code>.</p>
</li>
<li>
<p><strong>Consider Nullability</strong>: Remember that <code>ReactNode</code> can be <code>null</code> or <code>undefined</code>, so handle these cases in your components.</p>
</li>
<li>
<p><strong>Type Narrowing</strong>: When using <code>ReactNode</code>, you might need to narrow the type if you want to perform specific operations:</p>
<pre><code class="language-typescript">if (React.isValidElement(node)) {
  // node is now treated as React.ReactElement
}
</code></pre>
</li>
<li>
<p><strong>Generic Types</strong>: For more advanced use cases, consider using generic types with <code>React.Element</code>:</p>
<pre><code class="language-typescript">function Wrapper&#x3C;P>(props: { element: React.ReactElement&#x3C;P> }) {
  return React.cloneElement(props.element, { className: 'wrapped' });
}
</code></pre>
</li>
</ul>
<h2>Common Pitfalls and Potential Issues</h2>
<p>When working with <code>ReactNode</code> and <code>React.Element</code>, it's important to be aware of potential pitfalls that can arise from using the wrong type. Here are some common issues and what could go wrong:</p>
<ul>
<li>
<p><strong>Type Mismatch Errors</strong>:</p>
<ul>
<li>Using <code>React.Element</code> when <code>ReactNode</code> is expected can lead to type errors, as <code>React.Element</code> is more restrictive.</li>
<li>Example: Trying to pass a string or number to a prop typed as <code>React.Element</code> will cause a compilation error.</li>
</ul>
</li>
<li>
<p><strong>Unexpected Rendering Behavior</strong>:</p>
<ul>
<li>Using <code>ReactNode</code> when you specifically need a React element can lead to unexpected rendering issues.</li>
<li>For instance, if you're using <code>React.cloneElement()</code> with a <code>ReactNode</code>, it might fail at runtime if the node isn't actually an element.</li>
</ul>
</li>
<li>
<p><strong>Loss of Type Safety</strong>:</p>
<ul>
<li>Overusing <code>ReactNode</code> can lead to a loss of type safety. While it's more flexible, it also means TypeScript can't provide as much help in catching errors.</li>
<li>This can result in runtime errors that could have been caught at compile-time with more specific typing.</li>
</ul>
</li>
<li>
<p><strong>Null/Undefined Handling</strong>:</p>
<ul>
<li><code>ReactNode</code> can be <code>null</code> or <code>undefined</code>, but <code>React.Element</code> cannot. Forgetting to handle these cases can lead to runtime errors.</li>
<li>Example: Not checking for <code>null</code> when using a <code>ReactNode</code> prop could cause your component to crash if <code>null</code> is passed.</li>
</ul>
</li>
<li>
<p><strong>Performance Implications</strong>:</p>
<ul>
<li>Using <code>ReactNode</code> when <code>React.Element</code> would suffice might lead to unnecessary type checks at runtime, potentially impacting performance in large applications.</li>
</ul>
</li>
<li>
<p><strong>Difficulty in Prop Manipulation</strong>:</p>
<ul>
<li>When using <code>ReactNode</code>, you lose the ability to easily manipulate props of the passed elements.</li>
<li>If you need to clone and modify elements, using <code>React.Element</code> is more appropriate and safer.</li>
</ul>
</li>
</ul>
<p>To avoid these pitfalls:</p>
<ul>
<li>Always consider the specific needs of your component when choosing between <code>ReactNode</code> and <code>React.Element</code>.</li>
<li>Use type narrowing and null checks when working with <code>ReactNode</code>.</li>
<li>Prefer <code>React.Element</code> when you need to perform operations specific to React elements.</li>
<li>Don't default to <code>ReactNode</code> for all cases; use it when you genuinely need the flexibility it offers.</li>
</ul>
<p>By being aware of these potential issues, you can make more informed decisions about which type to use in different scenarios, leading to more robust and type-safe React applications.</p>
<h2>Conclusion</h2>
<p>Understanding the difference between <code>ReactNode</code> and <code>React.Element</code> is crucial for writing robust React applications, especially when using TypeScript. While <code>ReactNode</code> offers flexibility and is suitable for most cases where you need to render content, <code>React.Element</code> provides more specificity and type safety when working directly with React elements. By choosing the right type for your use case and being aware of potential pitfalls, you can improve the clarity, maintainability, and reliability of your React code.</p>
<p>Remember, the goal is to create components that are both flexible and type-safe. By mastering these types and understanding their implications, you'll be better equipped to achieve this balance in your React projects and avoid common issues that can arise from misusing these types.</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/understanding-the-difference-between-arrayt-and-t-in-typescript</guid>
      <title>Understanding the Difference Between `Array&lt;T&gt;` and `T[]` in TypeScript</title>
      <link>https://coleruche.com/post/understanding-the-difference-between-arrayt-and-t-in-typescript</link>
      <description>The article explains the difference between Array&lt;T&gt; and T[] in TypeScript, highlighting that both define arrays of a specific type with slightly different syntax. It provides examples to help developers understand their usage.</description>
      <pubDate>Sat, 13 Jul 2024 10:19:32 GMT</pubDate>
      <content:encoded><![CDATA[<p>In TypeScript, arrays are a fundamental part of the language, allowing developers to store collections of values of a specific type. There are two primary ways to define arrays: <code>Array&#x3C;T></code> and <code>T[]</code>. While they are often used interchangeably, there are subtle differences between the two that are worth understanding. This article will delve into these differences and provide guidance on when to use each form.</p>
<h2>What are <code>Array&#x3C;T></code> and <code>T[]</code>?</h2>
<ul>
<li><strong><code>Array&#x3C;T></code></strong>: This is a generic type provided by TypeScript. It signifies an array where each element is of type <code>T</code>.</li>
<li><strong><code>T[]</code></strong>: This is a shorthand notation for the <code>Array&#x3C;T></code> type. It also represents an array where each element is of type <code>T</code>.</li>
</ul>
<h2>Syntax Differences</h2>
<p>The primary difference between <code>Array&#x3C;T></code> and <code>T[]</code> lies in their syntax. Here’s a quick comparison:</p>
<pre><code class="language-typescript">// Using Array&#x3C;T>
let numbers: Array&#x3C;number> = [1, 2, 3, 4];

// Using T[]
let numbersAlt: number[] = [1, 2, 3, 4];
</code></pre>
<h2>Type Readability</h2>
<p>In some cases, <code>Array&#x3C;T></code> can improve readability, especially when dealing with more complex types. Consider the following example:</p>
<pre><code class="language-typescript">// Using Array&#x3C;T>
let arrayOfArrays: Array&#x3C;Array&#x3C;number>> = [[1, 2], [3, 4]];

// Using T[]
let arrayOfArraysAlt: number[][] = [[1, 2], [3, 4]];
</code></pre>
<p>While both notations are correct, <code>Array&#x3C;Array&#x3C;number>></code> might be clearer in showing that the type is an array of arrays of numbers, whereas <code>number[][]</code> can sometimes be harder to parse visually.</p>
<h2>Consistency with Other Generic Types</h2>
<p>Using <code>Array&#x3C;T></code> can also be more consistent with other generic types in TypeScript. For instance, if you’re already using generics for other types like <code>Promise&#x3C;T></code> or <code>Map&#x3C;K, V></code>, it might make sense to use <code>Array&#x3C;T></code> for consistency:</p>
<pre><code class="language-typescript">let promises: Array&#x3C;Promise&#x3C;number>> = [Promise.resolve(1), Promise.resolve(2)];
</code></pre>
<h2>Function Signatures</h2>
<p>When defining function signatures, both <code>Array&#x3C;T></code> and <code>T[]</code> can be used interchangeably. However, in more complex generic functions, <code>Array&#x3C;T></code> might be preferred for clarity:</p>
<pre><code class="language-typescript">// Using Array&#x3C;T>
function getFirstElement&#x3C;T>(arr: Array&#x3C;T>): T | undefined {
    return arr[0];
}

// Using T[]
function getFirstElementAlt&#x3C;T>(arr: T[]): T | undefined {
    return arr[0];
}
</code></pre>
<h2>Compatibility and Preferences</h2>
<p>Both <code>Array&#x3C;T></code> and <code>T[]</code> are fully compatible with each other. It ultimately comes down to personal or team preference. Some developers prefer the concise <code>T[]</code> notation, while others favor the explicit <code>Array&#x3C;T></code> syntax for its readability and consistency.</p>
<h2>Conclusion</h2>
<p>In summary, <code>Array&#x3C;T></code> and <code>T[]</code> in TypeScript are two ways to define arrays, with subtle differences in syntax and readability. Both are equally valid and compatible, so choosing one over the other often comes down to personal preference or the need for consistency with other generic types.</p>
<p>Understanding these differences can help you write clearer, more maintainable TypeScript code. Whether you opt for <code>Array&#x3C;T></code> or <code>T[]</code>, the key is to stay consistent with your choice across your codebase.</p>
<p>Happy coding!</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/Input Field Auto-Zoom</guid>
      <title>Auto Zoom on Small-Font Inputs</title>
      <link>https://coleruche.com/post/Input Field Auto-Zoom</link>
      <description>Exploring the auto-zoom effect on small font inputs in mobile web design for enhanced accessibility.</description>
      <pubDate>Fri, 29 Dec 2023 22:40:32 GMT</pubDate>
      <content:encoded><![CDATA[<h2>Introduction</h2>
<p>Frontend development continuously adapts to enhance user accessibility (a11y). A key example is the automatic zoom on mobile browsers for input fields with a font size under 16 pixels. This feature, introduced with early smartphones around the mid-2000s, aims to improve readability on small screens.</p>
<h2>The 16-Pixel Threshold</h2>
<p>Set against the backdrop of increasing mobile internet usage, this feature was popularized by browsers like Safari on the first iPhone in 2007. The choice of 16 pixels as the threshold is based on average visual acuity and typical mobile screen reading distances, making smaller text more legible and interaction more user-friendly.</p>
<h2>Implications for Developers</h2>
<p>This auto-zoom behavior compels frontend developers to consider mobile user experience when designing web forms and input fields. A font size of 16 pixels or more can prevent unwanted zooming and maintain the intended layout, but it's crucial to balance this with the accessibility needs of users with visual impairments.</p>
<h2>Best Practices</h2>
<ul>
<li><strong>Use Minimum Font Size of 16 Pixels</strong>: For design consistency and control over zoom behavior. This right here "fixes" the automatic zooming as well as maintains best a11y practices.</li>
<li><strong>Responsive Design</strong>: Adapt layouts for various screen sizes for optimal user experience.</li>
<li><strong>Accessibility Testing</strong>: Regularly check your site with accessibility tools and user feedback.</li>
</ul>
<h2>Conclusion</h2>
<p>The auto-zoom feature in mobile browsers represents a significant step towards making web content accessible on smaller screens. Frontend developers must understand and incorporate this feature to create inclusive, user-friendly websites that cater to diverse user needs.</p>
<p>It is important to note that this feature is not a bug and nothing is broken in your design and implementation. Although, from an accessibility point of view, it is advised to use a minimum of 16px on form element sizes, but if doing this will break your UI, then you can safely ignore this behavior.</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/Ethereum-Faucets</guid>
      <title>Top 5 Testnet Ethereum Faucets</title>
      <link>https://coleruche.com/post/Ethereum-Faucets</link>
      <description>What are Ethereum faucets and free eth sepolia faucets available</description>
      <pubDate>Sun, 10 Sep 2023 22:40:32 GMT</pubDate>
      <content:encoded><![CDATA[<h2>What are faucets?</h2>
<p>With the world of Web3 becoming increasingly costly to interact with, there comes the need at some point to look for alternative, cheap (and if possible, free) ways to get these tokens. That is where faucets come in.
 <br>
 <br>
As the name suggests, faucets are programs and software that provide users with free tokens of the supported network. These tokens are usually quite small and may sometimes require users to complete certain tasks or meet specific requirements.</p>
<h2>How do faucets work?</h2>
<p>Typically, faucets involve the benefactor having a sufficient supply of these tokens and then providing a means for users to get these tokens for free by fulfilling certain requirements. These requirements can range from simple ones like posting to social media, subscribing to a newsletter or service, streaming videos, downloading content, or simply having an account with a service provider.
 <br>
 <br>
Regarding the tokens, while very few of them are real ETH tokens spendable on the mainnet, most of them are actually ETH that is only usable on test networks like Sepolia or Goerli. These kinds of tokens are important for developers testing and developing on the blockchain where it would not make much sense to use real ETH which costs real money. Ideally would need to use fake ETH tokens to iterate new features and test out their code as many times as they need, for little or no money.
 <br>
These test tokens are also utilized by other participants in the Web3 world who participate in tasks and challenges that include testing out new blockchains and protocols.
 <br>
 </p>
<h2>Top 5 faucets I have come across</h2>
<p>Right away, I will be listing out some really nice Ethereum faucets I have come across, including shamelessly plugging in one of mine.</p>
<h3><a href="https://goerlidrop.com">Goerli Drop</a></h3>
<p>I built this simple faucet that gives out free test ETH tokens for the Goerli test network. The tokens can be as high as <strong>0.05</strong> ETH redeemable <strong>every 6 hours or so</strong>. The main requirement for getting this faucet is to be subscribed to my growing <a href="https://cole-ruche.ck.page/subscribe">newsletter</a>. On visiting the site, it automatically requests to switch to the Goerli network if MetaMask is installed and not on Goerli. Give it a try!</p>
<p><strong>[UPDATE]: Goerli has been deprecated and is no longer supported. You can visit the new faucet I built for <a href="https://sepolia-faucet.coleruche.com/">Sepolia</a>.</strong></p>
<h3><a href="https://www.infura.io/faucet/sepolia">Infura Faucet</a></h3>
<p>This faucet was built by the incredible team at Infura, one of the leading blockchain technology companies. They have faucets for Sepolia and Linea networks. Their requirement? Simply create an account with them and log in to request for free <strong>0.5</strong> test ETH after completing a simple captcha. This is one of the most generous offerings I've encountered, and you are eligible for it <strong>once per day</strong>.</p>
<h3><a href="https://www.allthatnode.com/faucet/ethereum.dsrv">All That Node</a></h3>
<p>The team at <em>All That Node</em> has a simple-to-use faucet that drips free <strong>0.025</strong> test ETH for Sepolia and Goerli <em>once per day</em>. No requirements are necessary. Simply specify where you'd like your tokens sent. (Please double-check your testnet address) and solve a captcha. However, at the time of writing this (Sept 10, 2023), the platform is down for maintenance.</p>
<h3><a href="https://goerlifaucet.com/">Goerli Faucet</a> and <a href="https://sepoliafaucet.com/">Sepolia Faucet</a></h3>
<p>These awesome faucets were developed and are maintained by the Alchemy team. They are faucets that give out free <strong>0.02</strong> Goerli and <strong>0.5</strong> Sepolia ETH for the respective test networks, <strong>per day</strong>. To use this faucet, you have to be registered with the platform and signed in. However, for the Goerli faucet, you need to have a <em>minimum mainnet balance of 0.001 ETH on the wallet address being used.</em></p>
<h3><a href="https://faucet.quicknode.com/ethereum">Ethereum Faucet</a> by QuickNode</h3>
<p>This faucet is one of the simplest faucets I have ever used. You only need to connect your wallet, select one of the many networks they support (or Ethereum in this case), choose between Sepolia and Goerli, and submit. They give out free <strong>0.05</strong> ETH, but if you wish to double this to <strong>0.1</strong> ETH, you can simply share the link to a tweet they require you to post. However, my only concern is that at the time of writing this, their user interface seemed a bit disorganized, with the original content of the screen overlapping on the left side, and no feedback was provided when I submitted the request.</p>
<h2>Conclusion</h2>
<p>This list does not cover all the faucets out there. There are still many I have not come across or used. But I believe the 5 listed out here are enough to get you started with whatever you require the tokens for. In case you wish to learn how to build one for yourself just like I did, I may be writing an article on how to build one. Stay connected and subscribe to my newsletter to know when this happens. And <em>hey</em>, you can get free Sepolia ETH while you're at it!</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/Function-Modifiers-in-Solidity</guid>
      <title>Function Modifiers in Solidity</title>
      <link>https://coleruche.com/post/Function-Modifiers-in-Solidity</link>
      <description>All about function modifiers in Solidity.</description>
      <pubDate>Sat, 24 Sep 2022 22:40:32 GMT</pubDate>
      <content:encoded><![CDATA[<p>If you are familiar with Solidity, you may have noticed or come across code like:</p>
<pre><code class="language-sol">pragma solidity ^0.7.0;

contract TestContract {
    uint private score;

    function getScore() external view returns(uint){
        return score;
    }
}
</code></pre>
<p>The <code>view</code> key in the <code>getScore</code> function above is an example of Modifiers in Solidity.</p>
<p>Modifiers in Solidity are little helper functions that <em>modify</em> a function that it is attached to. Modifiers are called before the main function is called and we may need this behavior in cases like:</p>
<ul>
<li>Validating an input.</li>
<li>Making checks before modifying the contract.</li>
<li>Running a set of tasks or functions before running the main one.</li>
</ul>
<p>There are built-in modifiers in Solidity and we can as well create our own custom modifiers.</p>
<h3>Built-in Modifiers</h3>
<p>The <code>view</code> example above is an example of the built-ins. There exist other examples like <code>pure</code> and <code>payable</code>.</p>
<h5><code>view</code></h5>
<p>This modifier is used to explicitly inform Solidity that you intend to only read the state from the contract. You are not allowed to modify or alter any state variable using a function containing this modifier. Attempting to do this will lead to an error and cancel the code execution.</p>
<p>For example, using the sample code above, we are not allowed to do this:</p>
<pre><code class="language-sol">function getScore() external view returns(uint){
    score += 1; // TypeError: Function declared as view, but this expression (potentially) modifies the state
    return score;
}
</code></pre>
<h5><code>pure</code></h5>
<p>This modifier is used to inform Solidity that we have no intention of reading or modifying the contract state. In <code>view</code>, we can read but cannot set/alter state, while in <code>pure</code> we cannot even read the state. For, example:</p>
<pre><code class="language-sol">function getScore() external pure returns(uint){
    return score; // TypeError: Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
}
</code></pre>
<p>You may think, <em>"When do we need this then?"</em>. We may need this modifier when we wish to make some internal calculations and checks where we do not need any variables from the existing state. For example,</p>
<pre><code class="language-solidity">pragma solidity ^0.7.0;

contract TestContract {
    uint private scoreA;
    uint private scoreB;

    function addScores(uint a, uint b) internal pure returns (uint) {
        return a * b;
    }

    function addAndGetScores() external view returns (uint) {
        return addScores(scoreA, scoreB);
    }
}
</code></pre>
<p>Above, <code>addScores</code> accepts arguments and only carries out instructions based on them. They do not read state or change it.</p>
<h5><code>payable</code></h5>
<p>This other modifier is used to inform Solidity that we expect some ether in form of Wei to be passed in along with the function. It is simply called as such:</p>
<pre><code class="language-solidity">pragma solidity ^0.7.0;

contract TestContract {
    uint private score;

    function setScore(uint newScore) external payable {
        score = newScore;
    }
}
</code></pre>
<p>When we do this without sending in some ether with the transaction, the function execution will fail.</p>
<h3>Custom Modifiers</h3>
<p>We may also decide to create our own custom modifiers that handle specific tasks before executing our functions. To do this, we simply define the modifier using the <code>modifier</code> keyword and can also use them alongside other modifiers:</p>
<pre><code class="language-sol">pragma solidity ^0.7.0;

contract TestContract {
    uint private score;
    address manager;

    constructor() {
        manager = msg.sender;
    }

    modifier isManager() {
        require(msg.sender == manager);
        _;
    }

    function setScore(uint newScore) external payable isManager {
        score = newScore;
    }
}
</code></pre>
<p>Let us break down the contract code above:</p>
<ul>
<li>We added a new variable to store our manager, which in this case is the address of the wallet or contract that deploys this <code>TestContract</code>.</li>
<li>We set this manager in the constructor.</li>
<li>The next line is where we declare our modifier called <code>isManager</code> which just checks that the caller of the function it is attached to is the manager. This adds some layer of protection on top of our contract by preventing the general public or unintended users to modify the state of our contract.</li>
</ul>
<p>The modifier function above has a line of code with just an underscore "_". This special symbol informs Solidity that this is the point where we inject the main function block. So it checks that the caller is the manager, and then runs <code>score = newScore;</code></p>
<p>Also, note that modifiers can also accept arguments like regular functions.</p>
<pre><code class="language-sol">pragma solidity ^0.7.0;

contract TestContract {
    uint private score;
    address manager;

    constructor() {
        manager = msg.sender;
    }

    modifier checkFee(uint fee) {
        require(fee > 100000);
        _;
    }

    function setScore(uint newScore) external payable checkFee(msg.value) {
        score = newScore;
    }
}
</code></pre>
<p>In the code above, the new <code>checkFee</code> modifier expects to be called with a value that it checks to be greater than 100000wei. This modifier is now used in <code>setScore</code> and the value of ether sent with the transaction is passed as the parameter.</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/JavaScript-Null-Coalescing</guid>
      <title>Nullish Coalescing in JavaScript</title>
      <link>https://coleruche.com/post/JavaScript-Null-Coalescing</link>
      <description>Taking a dive into the ES2020 Nullish Coalescing operator.</description>
      <pubDate>Tue, 14 Apr 2020 05:47:32 GMT</pubDate>
      <content:encoded><![CDATA[<p>Hey there! It's been a while since I wrote an article; kinda had a writer's block. Well, I just recently learned about a really cool <em>thing</em> in our beloved JavaScript and I thought it would be nice to share.</p>
<p>Today we'd be talking about Nullish Coalescing in JavaScript. The nullish coalescing operator (??) is considered a logical operator - much like the 'OR' (||), 'AND' (&#x26;&#x26;) and 'NOT' (!) operators - that returns the right side operand if <em>and only if</em> the operand on the left-hand side has a <strong>null</strong> or <strong>undefined</strong> value. It is quite similar to the 'OR' operator, but with a significant difference which we will get to soon enough.</p>
<p>To see this in action, let's consider the code below:</p>
<pre><code class="language-js">// for null values
let x = null;
let y = x ?? "defaultValue";
console.log(y); //returns 'defaultValue'

//for undefined values
let m = undefined;
let n = m ?? "defaultValue";
console.log(n); //returns 'defaultValue'
</code></pre>
<p>This also works if the left-hand side operand has been declared but not yet assigned a value as this is also an undefined value, like in the example below.</p>
<pre><code class="language-js">let f;
let g = f ?? "defaultValue";
console.log(g); //returns 'defaultValue'
</code></pre>
<p>As I mentioned, the nullish operator is somewhat similar to the OR operator except for an important difference. The OR operator returns the right-hand side operand for not just null and undefined values but <em>also</em> for falsy values. Consider the code below:</p>
<pre><code class="language-js">// with nullish operator
let a = false;
let b = a ?? "defaultValue";
console.log(b); //returns false

//with OR operator
let k = false; //also works with 0
let l = a || "defaultValue";
console.log(b); //returns 'defaultValue'
</code></pre>
<p>You might be wondering what the use case for this is, let's consider the code block below:</p>
<pre><code class="language-jsx">import React from "react";
const profile = {
  numberOfPosts: 0,
  username: "",
};
let displayNumberOfPosts =
  numberOfPosts || "An error occured while fetching data";
export const Example = () => {
  return &#x3C;p>{displayNumberOfPosts}&#x3C;/p>;
};
</code></pre>
<p>The above returns <code>&#x3C;p>An error occured while fetching data&#x3C;/p></code> because 0 is a <em>falsy</em> value hence the OR operator returns the right hand side operand, in this case being 'An error occured while fetching data' which is unintended.
The desired result could be achieved by using the nullish coalescing operator as thus:</p>
<pre><code class="language-js">import React from "react";
const profile = {
  numberOfPosts: 0,
  username: "",
};
let displayNumberOfPosts =
  numberOfPosts ?? "An error occured while fetching data";
export const Example = () => {
  return &#x3C;p>{displayNumberOfPosts}&#x3C;/p>;
};
</code></pre>
<p>The above will return <code>&#x3C;p>0&#x3C;/p></code> as the operator returns the right-hand side operand only if the left-hand side is a nullish value, and not a <em>falsy</em> one.</p>
<p>The nullish coalescing operator is currently a stage four proposal for ES2020 which is the <a href="https://tc39.es/process-document/">last stage for the TC39 process</a> and I'm sure we can't wait to start using it soon in the next version of JavaScript.</p>
<p>Thanks for taking the time to read this article. I will be writing even more; stay tuned!</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/Building-an-Ecommerce-Store-With-Gatsby-and-Shopify</guid>
      <title>Building an E-commerce store with Gatsby and Shopify</title>
      <link>https://coleruche.com/post/Building-an-Ecommerce-Store-With-Gatsby-and-Shopify</link>
      <description>This tutorial covers an in-depth guide on how to set up a static PWA ecommerce site with Gatsby and Shopify with automatic rebuild when products are updated, added or deleted.</description>
      <pubDate>Thu, 14 Nov 2019 22:40:32 GMT</pubDate>
      <content:encoded><![CDATA[<p>Have you ever visited a site to shop for your favourite item and got so frustrated over the many redirects and loadings - and the unnecessary waste of time that comes with it. Or have you been faced with a challenge of building out a online store but could not just find a way to get started - and done - with it? This tutorial is just for you.</p>
<p>With the relative ease that comes with using Gatsby, and the amazing <em>love</em> that comes from its community ever since I started using it, I decided to find out what other <a href="https://www.storyblok.com/tp/3-reasons-why-you-should-consider-gatsby-js-for-your-next-project">amazing things that come. with it</a>. It then hit me, <em>"could Gatsby be used to build out an online store as a static site?".</em> At first, it seemed most unlikely, as I thought of the highly dynamic functionality that comes with e-commerce stores and could not possibly imagine how Gatsby could generate static pages for them. But then, hey, we live in a time where there is Gatsby and <a href="https://netlify.com">Netlify</a>. <em>Anything</em> can be done on the web these days.</p>
<p>I then started to do a little digging to see what I could come up with. I saw a few articles on it, but they were mostly using not-so-popular technology or providers. I needed something quick and fast. Something that did not require me reading a big ass documentation in order to get things started.</p>
<p>I also came across this <a href="https://www.gatsbyjs.org/tutorial/ecommerce-tutorial/">article from the Gatsby docs</a>, but I still felt it was a bit limiting as it was an integration with Stripe, which is not totally supported in all countries, at least not Nigeria. I needed a solution that supported many payment providers and methods and I could only think of one. Shopify.</p>
<p>A few <em>digs</em> later I discovered an awesome Gatsby starter for e-commerce stores powered by Gatsby and Shopify. The joy! The starter already hast taken out the stressful parts of it all. No need to reinvent the wheel here and all it needs is a tweak here and there and some redesign to suit your taste. You can check out the starter <a href="https://www.gatsbyjs.org/docs/building-an-ecommerce-site-with-shopify/">here on Gatsby</a> or directy get to the <a href="https://github.com/AlexanderProd/gatsby-shopify-starter">source code</a> on Github.</p>
<p>Two issues are likely to arise when creating <strong><em>static</em></strong> online shops. First, dynamic product inventory. Your product availability should change in accordance to your inventory in the Shopify store. You wouldn't want your products to appear as available, because Gatsby has already <em>statically</em> built out the listing page, when in reality you are out of stock. For this issue, the starter I mentioned above has it all sorted out. According to their README,</p>
<blockquote>
<p>"The Shopify product inventory is being checked in realtime, therefore no rebuilding and redeploy is needed when a product goes out of stock. This avoids problems where products could still be available even though they're out of stock due to redeploy delay."</p>
</blockquote>
<p>Secondly, as the pages would be all pre-built by Gatsby, what happens when we change the details of a product, add a new product or delete an existing product? Would we have to log back to Netlify to trigger a build each time? Nope! For this issue, we also have a workaround for it.</p>
<p>Without much ado, let's begin. </p>
<p>###Shopify setup
First, you would need to log into your <a href="https://shopify.com/">Shopify</a> account or <a href="https://www.shopify.com/signup">create one</a> if you do not have already. While logged in, create a new store and give it whatever name you wish. You will need this name, plus a Storefront access token which you will get soon.  With the store created, go on to add a few products to the store. Gatsby's graphql would throw an error during build if there are no products in the store.</p>
<p>Next, we have to get a storefront token. For this, navigate to the <strong>Apps</strong> section of your store and continue to <strong>Manage private apps</strong>. Create a new private app, with any name under “Private app name” and leave the default permissions as <strong>Read access</strong> under Admin API. Enable the Shopify Storefront API by checking the box that says “Allow this app to access your storefront data using Storefront API”. Make sure to also grant access to read product and customer tags by checking their corresponding boxes. Then, copy the storefront access token that will be provided to you. This is not a secret and could be put in any publicly available JavaScript file.</p>
<p>###Gatsby setup
To start up the project, in the command line, run:</p>
<pre><code>gatsby new gatsby-shopify-starter https://github.com/AlexanderProd/gatsby-shopify-starter
</code></pre>
<p>This will take some time to start the project and install dependencies. Once done, open up the project folder in your favourite editor and open the <code>.env.development</code> and the <code>.env.production</code> files and change the default values of <code>SHOP_NAME</code> and <code>SHOPIFY_ACCESS_TOKEN</code> to your own store name and access token, respectively. That is about all you need to do for the setup. You can test this out by running <code>gatsby develop</code>. Please for this, you should be connected to the internet for Gatsby to fetch the product and build the product pages. When all is done, you should have a new ecommerce store running on your localhost. You can go ahead and make relevant changes to the project as suits your designs and use case. All done then deploy to Netlify.</p>
<p>###Handling automatic build
With the store deployed to Netlify, we then have to set up an automatic build on Netlify each time we make product changes on the Shopify store.
To do this, we need to set up Netlify's build hooks, which is a URL that continuoulsy listens for <code>POST</code> requests and triggers a build automatically when such requests hit the URL. For this, go the the app's Settings > Build &#x26; deploy > Build hooks and Add build hook. Put in a hook name and select a branch from git which the build should run with, ideally <code>master</code>. Hit Save. Upon save, a new hook URL endpoint will be displayed. Copy that and head over back to the Shopify store. Move to Settings > Notifications > Webhooks > Create webhook. For the event, choose <strong>Product creation</strong>, leave format as JSON and paste the URL from the Netlify build hook and hit Save webhook. Do this again two more times for <strong>Product deletion</strong> and <strong>Product update</strong> and any other event you feel may be necessary for a rebuild, while using the same URL from Netlify.

And that is it, as you add/update/delete products, Netlify rebuilds the site in a few minutes to reflect changes.</p>
<blockquote>
<p>For more stuff, like adding payment or delivery options, please do that in the Shopify dashboard. The Gatsby "front-end" just displays the info and preferences from the Shopify dashboard "back-end".</p>
</blockquote>
<p><em>Extra stuff:</em> Seeing you do not need the Shopify online store sales channel (as the Gatsby app serves the purpose), you can safely remove it as a sales channel. This makes you (or your client) avoid the $29 monthly charges on the Basic Shopify plan and instead, subscribe to the $9 monthly Shopify Lite plan.</p>
<p>PS: If you need someone to set up a store for you, you can <a href="mailto:emeruchecole9@gmail.com">hire me</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/Implementing-a-Draft-Feature-in-a-Gatsby-Blog</guid>
      <title>Implementing a Draft Feature in a Gatsby Blog</title>
      <link>https://coleruche.com/post/Implementing-a-Draft-Feature-in-a-Gatsby-Blog</link>
      <description>This covers how to implement a draft system in your GatsbyJS-powered blog.</description>
      <pubDate>Sat, 31 Aug 2019 20:02:32 GMT</pubDate>
      <content:encoded><![CDATA[<p><em>Hello there, fellow Gatsby blog owner!</em>
Recently, I've found myself thinking and writing about GatsbyJS. Mostly because, like Bootstrap and React, it's one of the best thing that has happened to me since I started learning front-end development. And now I'm going to share something (not-so-new) I learnt.</p>
<p>When I started out building my portfolio-cum-blog website with Gatsby and actually started writing, I came across an issue. For someone who also writes on <a href="https://dev.to">Dev.to</a> - where you can start writing out an article, only to <em>draft</em> it and move onto a new one - I got a bit disappointed why uptil now, Gatsby's <a href="https://www.gatsbyjs.org/starters/gatsbyjs/gatsby-starter-blog/">blog starter</a> does not include a built-in functionality of saving drafts and only publishing posts you set as "published", as seen on Dev.to.</p>
<blockquote>
<p>There are other alternatives to this which I found online. Links to them will be listed at the end of this article.
Also this article assumes you're running a blog powered by Gatsby's <code>gatsby-starter-blog</code></p>
</blockquote>
<p>My first thought on how to solve this was looking for the chunk of code that handles creation of pages from Markdown files, and I found this in <code>gatsby-node.js</code>:</p>
<pre><code class="language-js">exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions;

  const blogPost = path.resolve(`./src/templates/blog-post.js`);
  const result = await graphql(
    `
      {
        allMarkdownRemark(
          sort: { fields: [frontmatter___date], order: DESC }
          limit: 1000
        ) {
          edges {
            node {
              fields {
                slug
              }
              frontmatter {
                title
              }
            }
          }
        }
      }
    `
  );

  if (result.errors) {
    throw result.errors;
  }

  // Create blog posts pages.
  const posts = result.data.allMarkdownRemark.edges;

  posts.forEach((post, index) => {
    const previous = index === posts.length - 1 ? null : posts[index + 1].node;
    const next = index === 0 ? null : posts[index - 1].node;

    createPage({
      path: post.node.fields.slug,
      component: blogPost,
      context: {
        slug: post.node.fields.slug,
        previous,
        next,
      },
    });
  });
};
</code></pre>
<p>As you can rightly guess, the pages are created from data gotten with the <code>allMarkdownRemark</code> query. This is where we can work our magic.</p>
<p>Right next to the <code>sort</code> command, we can add our own <code>filter</code> rule to get only posts we mark as published. To do this, you should add a variable <code>published</code> in your articles' frontmatter, which is set to <code>true</code> or <code>false</code> depending on the status of the article. For example, to set an article as a draft (i.e unpublshed) add this to the file's front matter: <code>published: false</code>.</p>
<p>Now that we have a way of marking posts as ready to be published or not, we get back to the GraphQL query and change it like so:</p>
<pre><code class="language-js">exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions

  const blogPost = path.resolve(`./src/templates/blog-post.js`)
  const result = await graphql(
    `
      {
        allMarkdownRemark(sort: {fields: frontmatter___date, order: DESC}, filter: {frontmatter: { published: {eq: true} }}, limit: 1000)
        ...

        slug: post.node.fields.slug,
        previous,
        next,
      },
    })
  })
}
</code></pre>
<p>This change ensures that Gatsby only filters out posts we set it's published variable to <code>true</code> in it's fromtmatter.
Please note to add this rule to wherever else you are doing some tasks with your posts, eg when in your <code>src/pages/index.js</code> file, where there's a similar query for listing out your articles, and also if you're creating your RSS feed with <code>gatsby-plugin-feed</code>.</p>
<p>As I stated before I started, there are other alternatives around the web for this. Check out this method by <a href="https://www.google.com.ng/url?sa=t&#x26;source=web&#x26;rct=j&#x26;url=https://janosh.io/blog/exclude-drafts-from-production/&#x26;ved=2ahUKEwi99uvmz63kAhVRQxUIHbWLAJ4QFjAAegQIAxAB&#x26;usg=AOvVaw3jun-nNSBWsJ8Gqq71dGYi">Janosh</a> and this one by <a href="https://chaseonsoftware.com/gatsby-drafts/#how-i-write-drafts-in-gatsby">Chase Adams</a>. Use whichever method you prefer, and if you have your own super cool method for this, please share with us some code snippets in the comment sections or paste the link to the article.</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/My-Top-5-Plugins-for-a-GatsbyJS-Powered-Blog</guid>
      <title>My Top Plugins for a GatsbyJS Powered Blog</title>
      <link>https://coleruche.com/post/My-Top-5-Plugins-for-a-GatsbyJS-Powered-Blog</link>
      <description>A look into what I think are my best plugins for a blog site created with GatsbyJS and Markdown</description>
      <pubDate>Sat, 10 Aug 2019 22:40:32 GMT</pubDate>
      <content:encoded><![CDATA[<p>For some time, I did not quite get the idea of static page generators, especially Gatsby JS. It was until I decided to give it a try and I discovered how amazing technology it is! Gatsby JS, amongst all other super things, is used to create a stunning and blazing fast blog, which can use varying data sources like Contentful CMS, WordPress or plain old Markdown. For the latter, it's simply easy to set up and use.
<em>This awesome blog was built with Gatsby and Markdown.</em></p>
<p>Now, while this won't be a tutorial to set up Gatsby with Markdown, I'll be showing you some awesome plugins I have come across so far, and I use them in my Gatsby blog site. Some of these plugins help in UI, UX, SEO, others help in integration with useful services, which otherwise would have been pretty difficult (or maybe not) to set up.</p>
<blockquote>
<p>These plugins are not entirely <em>top</em> per se - there are more important plugins that comes with a Gatsby starter, but these are my favorite extras to add.</p>
</blockquote>
<p>In no particular order, let's get started:</p>
<h3>gatsby-plugin-mailchimp</h3>
<p>What is a blog without subscribers, right? This plugin makes it ridiculously easy to link up your <a href="https://mailchimp.com/">Mailchimp</a> account with your Gatsby blog to enable you to subscribe email addresses to your Mailchimp list.
To set it up is as easy as running <code>yarn add gatsby-plugin-mailchimp</code> to install the package and adding to below snippet to your <code>gatsby-config.js</code> file:</p>
<pre><code class="language-js">{
  resolve: "gatsby-plugin-mailchimp",
  options: {
    endpoint: // add your MC list endpoint here; see instructions below
  },
},
</code></pre>
<p>For more information, visit the page <a href="https://www.gatsbyjs.org/packages/gatsby-plugin-mailchimp/">here</a>.</p>
<p>###gatsby-plugin-nprogress
Gatsby JS sites are blazing fast, that is the idea of static site generators. They load pages on click in less than a second. But if you have built, or visited a site built with Gatsby, you will agree with me this is not always the case.Sometimes, and for some reason, they delay a bit in loading pages. Most times there is no indicator to show the user that the page is loading, which they might perceive as an error and might end up continuously clicking on links, or might just leave entirely. This is where <code>gatsby-plugin-nprogress</code> comes in.</p>
<p>According to the gatsby plugin library, it <em>"automatically shows the nprogress indicator when a page is delayed in loading (which Gatsby considers as one second after clicking on a link)."</em></p>
<p>To set up, <code>yarn add gatsby-plugin-nprogress</code> and add the line below to <code>gatsby-config.js</code> file:</p>
<pre><code class="language-js">// In your gatsby-config.js
plugins: [
  {
    resolve: `gatsby-plugin-nprogress`,
    options: {
      // Setting a color is optional.
      color: `tomato`,
      // Disable the loading spinner.
      showSpinner: false,
    },
  },
];
</code></pre>
<p>###gatsby-remark-prismjs
This plugin adds syntax highlighting to code blocks in your markdown files using <a href="https://prismjs.com/">PrismJS</a>. This makes your code snippets, samples, and blocks aesthetically pleasing.</p>
<p>To use, <code>yarn add gatsby-transformer-remark gatsby-remark-prismjs prismjs</code>. This installs all the required modules, including the official PrismJS library. For customization options and how to use, visit [their page](gatsby-transformer-remark gatsby-remark-prismjs prismjs).</p>
<p>###gatsby-plugin-disqus
This helps you link your <a href="https://disqus.com/">Disqus</a> account to your blog. It enables you to activate comments and reactions to your blog pages. Thus, it allows interaction between you and your audience. From here, you can get feedback and see what your readers think and feel about your works and writing.
For usage and instructions, visit <a href="https://www.gatsbyjs.org/packages/gatsby-plugin-disqus/">here</a>.</p>
<p>###gatsby-plugin-robots-txt
This is a gatsby plugin that automatically creates robots.txt for your site. According to <a href="https://neilpatel.com/blog/robots-txt/">Neil Patel</a>, <em>"The robots.txt file, also known as the robots exclusion protocol or standard, is a text file that tells web robots (most often search engines) which pages on your site to crawl."</em> Having a <code>robots.txt</code> file is good for SEO as it tells the search engine (e.g Googlebots) instructions on how to crawl your site. To add this to your site, run <code>yarn add gatsby-plugin-robots-txt</code> and for the simplest implementation, add the code below to your project's <code>gatsby-config.js</code>:</p>
<pre><code class="language-js">plugins: ["gatsby-plugin-robots-txt"];
</code></pre>
<p>For additional configurations, visit the <a href="https://www.gatsbyjs.org/packages/gatsby-plugin-robots-txt/?=gatsby-plugin-robots-txt">plugin page</a></p>
<p>###gatsby-plugin-manifest
Gatsby plugin which adds a <code>manifest.webmanifest</code> to make sites progressive web apps. This plugin comes with features that turn your app to a <a href="https://www.google.com/url?sa=t&#x26;source=web&#x26;rct=j&#x26;url=https://developers.google.com/web/progressive-web-apps/&#x26;ved=2ahUKEwj_vruhuvTjAhUJShUIHSdHC_cQFjAhegQIBBAC&#x26;usg=AOvVaw0dIOwy-hAgSXFNdlBrXXwO">progressive web app</a> - automatic icon generation, favicon support and caching, all taken care of. It is recommended to use this plugin together with <a href="https://www.gatsbyjs.org/packages/gatsby-plugin-offline/?=gatsby-plugin-offline">gatsby-plugin-offline</a> for best results. To use, run <code>yarn add gatsby-plugin-offline gatsby-plugin-manifest</code>.
Open your config file and paste below:</p>
<pre><code class="language-js">plugins: [
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: `GatsbyJS`,
        short_name: `GatsbyJS`,
        start_url: `/`,
        background_color: `#f7f0eb`,
        theme_color: `#a2466c`,
        display: `standalone`,
      },
    },
    'gatsby-plugin-offline'
  ],
</code></pre>
<p>Make sure to replace necessary lines with your own details.</p>
<p>###gatsby-plugin-google-analytics</p>
<p>This is used to add <a href="https://www.google.com/url?sa=t&#x26;source=web&#x26;rct=j&#x26;url=https://analytics.google.com/analytics/web/&#x26;ved=2ahUKEwjoq6CRj_jjAhVPSxUIHaH9CB0QFjAAegQIBRAB&#x26;usg=AOvVaw095EntAfOjiijSk290zWyQ">google analytics</a> to your blog. This helps you get useful information about your visitors like demographics, device information, pages and stuff like that. It helps in knowing which pages are most visited, which country represents most of your visitors, which devices s are most used by your visitors and so, helps you to make better content targeted at your particular choice of audience. To use, run <code>yarn add gatsby-plugin-google-analytics</code> and then add the code below to your <code>plugins</code>:</p>
<pre><code class="language-js">{
  resolve: `gatsby-plugin-google-analytics`,
    options: {
       trackingId: `YOUR-TRACKING-ID`,
},
</code></pre>
<p>For more options and configurations, visit the <a href="https://www.gatsbyjs.org/packages/gatsby-plugin-google-analytics/">plugin page</a></p>
<p>###gatsby-plugin-sitemap
This plugin generates a sitemap for your site. Sitemaps are <em>highly</em> <a href="https://www.seeme-media.com/what-is-a-sitemap/">recommended for SEO purposes</a>. And it will do you a lot of good to add a plugin for it. To get started, install the plugin by running <code>yarn add gatsby-plugin-sitemap</code> and then add the following line of code to your Gatsby config:</p>
<pre><code class="language-javascript">plugins: [`gatsby-plugin-sitemap`];
</code></pre>
<p>The line above is the minimum configuration needed and the generates sitemap will include all of your site's pages by default. If for some reason, you don't want this behavior and need to exclude some pages, visit <a href="https://www.gatsbyjs.org/packages/gatsby-plugin-sitemap/?=">this page</a> for additional configurations.</p>
<blockquote>
<p>NOTE: This plugin only generates output when running in <code>production</code> mode! To test your sitemap, run: <code>gatsby build &#x26;&#x26; gatsby serve</code></p>
</blockquote>
<p>The plugins above are just a very itsy-bitsy of the over 1000 supported plugins in the <a href="https://www.gatsbyjs.org/plugins/?=">Gatsby library</a>, but they're just the few I have worked with and loved. Some of these plugins come bundled in some starters and you may not need to install them yourselves.</p>
<p>I'll be very glad to get feedback on some of these plugins and to know which extra plugins you love. Please tell us in the comment section.</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/Adding-Bootstrap-CDN-in-Gatsby</guid>
      <title>Adding Bootstrap CDN link to Gatsby</title>
      <link>https://coleruche.com/post/Adding-Bootstrap-CDN-in-Gatsby</link>
      <description>We wil take a look into how to set up a Gatsby JS site to use Twitter Bootstrap&apos;s CDN</description>
      <pubDate>Sat, 03 Aug 2019 22:40:32 GMT</pubDate>
      <content:encoded><![CDATA[<p>This post is intended to help out developers who love using Gatsby JS and Twitter Bootstrap and would absolutely love to use them together in one project - <em>lovely!</em>
One issue you might come across would be how to link them both up. For this you have two options: you can use supported packages like <a href="https://react-bootstrap.netlify.com/">React Bootstrap</a> or <a href="https://reactstrap.github.io/">reactstrap</a>; or you can include in CDN links to your app.</p>
<p>While the first option is quite great, I feel it is a bit too much of an overkill to use, especially if what you need from Bootstrap is just the juicy CSS. non-jQuery part and functionality like the grid system or typography. If so, we will go with the second option. This sounds easy, till you discover that Gatsby apps created with the <a href="https://www.gatsbyjs.org/starters/">starters</a> have no <code>index.html</code> file like in normal React apps made with <code>create-react-app</code>, or any other front end project.</p>
<p>Now where do we include our CDN links? There is no <code>html</code> file, hence no <code>head</code> tag. This is where the purpose of this article comes into play.</p>
<p>Again, we have two options - <em>hey! Life's full of options.</em>Gatsby projects come with a <code>seo.js</code> file which can be found in <code>src/components</code>. This component uses <a href="https://github.com/nfl/react-helmet">React Helmet</a> to function. This makes it easy for us to just make changes to the <code>html</code> file that will be produced when gatsby bundles our app. We can include the CDN link by so doing:</p>
<pre><code class="language-js">&#x3C;Helmet>
  &#x3C;link
    rel="stylesheet"
    href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
    integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
    crossorigin="anonymous"
  />
&#x3C;/Helmet>
</code></pre>
<p>This is relatively easy to do and should work well. I used this before, till I noticed that sometimes and for some reason, it did not work - it worked most of the time - and required the user to refresh the page for it to hopefully work. You can't expect users to do that!</p>
<p>This leads us to the second workaround.</p>
<p>A look into the project structure created for us when we bootstrap an app with a Gatsby starter should show a file in root folder called <code>gatsby-browser.js</code>.
According to the Gatsby website, <em>"This file is where Gatsby expects to find any usage of the Gatsby browser APIs (if any). These allow customization/extension of default Gatsby settings affecting the browser."</em>
What this means (to me), is that we can call APIs and import <em>stuff</em> that affects the browser, like our styles and custom JavaScript scripts. This sounds like a good enough point to introduce our CDN,</p>
<p>To do this, we have to let go of our CDN. Sorry that the article of this blog might be <em>misleading</em> as we will have to drop our CDN link here. All for the best. We have to install Bootstrap into our project. For this, run:</p>
<pre><code class="language-bash">npm install bootstrap
</code></pre>
<p>or</p>
<pre><code class="language-bash">yarn add bootstrap
</code></pre>
<p>This installs the official Bootstrap folders in our app. Next, open up the <code>gatsby-browser.js</code> file and import the CSS files from Bootstrap at the top of the file like so</p>
<pre><code class="language-js">//bootstrap
import "bootstrap/dist/css/bootstrap.css";
</code></pre>
<p>And that's it! Feel free to use Bootstrap styles as you wish. No hassles!</p>
<p>Thanks for following along and would love to have a feedback of how this helped you, or if you have your own way of linking them both up.</p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/Units-of-Measurements-in-CSS</guid>
      <title>Units of Measurements in CSS</title>
      <link>https://coleruche.com/post/Units-of-Measurements-in-CSS</link>
      <description>Units of measurements used when styling HTML elements in CSS</description>
      <pubDate>Wed, 31 Jul 2019 22:40:32 GMT</pubDate>
      <content:encoded><![CDATA[<p><em>px and %, em and rem - they are not all the same</em></p>
<p>Ever since I learnt and started styling pages with CSS, I have always felt confused regarding which unit to use for styling my paragraphs, headings, paddings and margins. This is common among (frontend) developers, as there are quite a lot of options out there to use - more options than I knew of till I started writing this!
I kept deferring learning the differences between these units, as I thought they did not really matter until <a href="https://twitter.com/_KaylaSween">Kayla</a> created <a href="https://twitter.com/_KaylaSween/status/1153799464340971525">a small quiz</a> on Twitter. And I failed it.</p>
<p>It was at this point that I decided to try and understand what they all are, and <em>document</em> it as well.</p>
<p>###So what are they?
The units are categorized into <strong><em>Absolute</em></strong> and <strong><em>Relative</em></strong> lengths.
Let's take them one after the other.</p>
<p>###Absolute Lengths
These are length units that are fixed and appear as exactly that size. Absolute units are mostly discouraged to be used on screens, as 12px on a large screen might not look the same on an iPhone. They depend highly on the output medium, and hence should be <em>ideally</em> be used when the output medium is known, or a particular screen size is targeted.</p>
<blockquote>
<p>"There is another reason to avoid absolute units for other uses other than print: You look at different screens from different distances. 1cm on a desktop screen looks small. But the same on a mobile phone directly in front of your eyes looks big. It's better to use relative units, such as <strong><em>em</em></strong>, instead."</p>
<p>-- <em>w3.org</em></p>
</blockquote>
<p>The absolute units are: <strong><em>px</em></strong>, <strong><em>in</em></strong>, <strong><em>cm</em></strong>, <strong><em>pt</em></strong>, <strong><em>pc</em></strong>, and <strong><em>mm</em></strong>. There might be others, but we will treat these ones for brevity sake.</p>
<ul>
<li><strong><em>px</em></strong>: This defines a size in screen pixels. It equals one dot on the computer screen. A pixel is equal to 1/96th of an inch. <a href="https://w3.org">W3</a> describes <strong><em>px</em></strong> as <em>the magic unit of CSS</em>.</li>
<li><strong><em>in</em></strong>: This means inches. 1in equals 96px.</li>
<li><strong><em>cm</em></strong>: Centimeters. Equals 37.8px.</li>
<li><strong><em>mm</em></strong>: Milimeters. 1mm is same as 3.778px.</li>
<li><strong><em>pc</em></strong>, <strong><em>pt</em></strong>: Defines measurements in picas and points, respectively. 1pt equals 1/72 of an inch, while 1pc equals 12pt.</li>
</ul>
<p>###Relative Lengths
These units define sizes and length relative to another length property. They are mostly preferred as they scale better across different mediums. They include <strong><em>em</em></strong>, <strong><em>rem</em></strong>, <strong><em>%</em></strong>, <strong><em>ex</em></strong>, <strong><em>ch</em></strong>, amongst others.</p>
<ul>
<li><strong><em>em</em></strong>: Simply put, an <strong><em>em</em></strong> is the same as the current font size. As a default, modern browsers display fonts at 16px (12in), thus, a text styled at 1em is same as 16px For example, look at the style below:</li>
</ul>
<pre><code class="language-css">p {
  font-size: 2em;
}
</code></pre>
<p>This sets the font size to 32px, i.e 2 * 16px.
<strong><em>em</em></strong> is scalable and are mobile-device-friendly.</p>
<ul>
<li><strong><em>rem</em></strong>: Stands for '<strong><em>r</em></strong>oot <strong><em>em</em></strong>'. This is the font size relative to the root element, which is the <code>html</code> tag.
Consider the style below:</li>
</ul>
<pre><code class="language-css">html {
  font-size: 62.5%;
}
body {
  font-size: 100%;
}
p {
  font-size: 1rem;
}
</code></pre>
<p>The size of the <code>p</code> tag comes out as 62.5% (of 16px, which is 10px) and not 100% (16px) as it is relative to the <code>html</code> font size and not that of the body tag.
The <code>rem</code> unit is not widely used, and so you might not need to use it.</p>
<ul>
<li><strong><em>%</em></strong>: Defines a size relative to the parent element.</li>
<li><strong><em>ex</em></strong> and <strong><em>ch</em></strong>: <strong><em>ex</em></strong> defines measurement relative to the font's x-height, which is the size of the font's lowercase 'x' while <strong><em>ch</em></strong> is relative to the font's width of the character '0' (zero).</li>
</ul>
<h3>Conclusion</h3>
<p>Really, the choice of what unit to use is left for you to choose, but most people use (and recommend) <strong><em>em</em></strong> and <strong><em>px</em></strong>.</p>
<blockquote>
<p>"I tend to use <strong><em>px</em></strong> for borders, and <strong><em>rems</em></strong> for most everything else -- because it makes it easy to keep things consistent and make layout tweaks without a lot of effort."</p>
<p>-- <a href="https://twitter.com/brian_d_vaughn">Brian Vaughn</a></p>
</blockquote>
<p>JavaScript Joe and JavaScript Joel both seem to be fans of px.</p>
<blockquote>
<p>"When it comes to font sizes, I traditionally use something like <a href="https://kyleamatthews.github.io/typography.js/">TypographyJS</a> because it basically sets up a system for me. 
However, I try to stick to measurements in multiples of 4px (e.g 4px, 8px, 12px, 16px etc) when I use px. This way things feel "uniform".</p>
<p>-- <a href="https://twitter.com/jsjoeio">JavaScriptJoe</a></p>
</blockquote>
<blockquote>
<p>"I typically only use px. That could be my bias as when I started, px was the only thing absolutely available. Now I leave it up to the designers to tell me what the style is."</p>
<p>-- <a href="https://twitter.com/joelnet">JavaScriptJoel</a></p>
</blockquote>
<p>This is what a Twitter user, Florin, has to say:</p>
<blockquote>
<p>"I use px mostly. Not very good with others."</p>
<p>-- <a href="https://twitter.com/florinpop1705">Florin Pop</a></p>
</blockquote>
<p>Now, whatever method you choose to use, it is recommended to use at least 16px (1em) for body text and em as the go-to unit. This ensures the font size is relative to the default font size, which is the size the reader can comfortably read. It also ensures the size scales well on different screen sizes and density. Although we can choose to ignore this, as modern browsers and devices provide tools to increase font size and display, it would not hurt to design with a11y in mind.</p>
<p>As was rightly pointed out by <a href="https://twitter.com/Brent_m_Clark">Brent Clark</a>, using <code>em</code> also comes with it's own issues: it is relative to the size of the parent, which in turn depends on other parent(s). For example, consider the code below:</p>
<pre><code class="language-html">&#x3C;!-- HTML -->
&#x3C;body>
    &#x3C;p class='outer-p'>
        Outer paragraph
        &#x3C;p class='nested-p'> Nested paragraph&#x3C;/p>
    &#x3C;/p>
&#x3C;/body>

&#x3C;!-- CSS -->
&#x3C;style>
    body{font-size: 16px}
    .outer-p{font-size: 2em}
    .nested-p{font-size: 1.5em}
&#x3C;/style>
</code></pre>
<p>From the above code, we need the <code>outer-p</code> paragraph to be 2em, and rightly it will be 32px, as it will be x2 of the immediate parent, the body, which was already set to 16px.
Now, if wanted to set our <code>nested-p</code> paragraph to 1.5em and expect it to come out as 24px (i.e 1.5 _ 16px), we'll be disappointed as the size comes out as 48px. This behaviour is because <code>em</code> is relative to whatever size the parent has. In this case, <code>nested-p</code> is a child of <code>outer-p</code>, which already has a size of 32px. This explains why it comes out as 48px, I.e 1.5 _ 32px.
This behavior of <code>em</code> should be put into consideration when using it.</p>
<p>In order to avoid unwanted outcomes that might be associated with <code>em</code>, I believe that was why the <code>rem</code> was introduced. With this, just set the default style on the <code>html</code> directly and then use <code>rem</code> as your CSS unit, this way you're sure they all refer to the <code>html</code> tag style size and not on their parent's sizes.</p>
<p>For example, using the same code above, to get the desired sizes for <code>outer-p</code> and <code>nested-p</code>, which are 32px and 24px respectively, we'll <em>refactor</em> to this:</p>
<pre><code class="language-html">&#x3C;!-- HTML -->
&#x3C;body>
    &#x3C;p class='outer-p'>
        Outer paragraph
        &#x3C;p class='nested-p'> Nested paragraph&#x3C;/p>
    &#x3C;/p>
&#x3C;/body>

&#x3C;!-- CSS -->
&#x3C;style>
    html{font-size: 16px}
    .outer-p{font-size: 2rem}
    .nested-p{font-size: 1.5rem}
&#x3C;/style>
</code></pre>
<p>By doing so, the font sizes are now all relative to the root style, in this case <code>html</code>.</p>
<p>As for me, I will <em>try</em> to stick to this little snippet I found:</p>
<pre><code class="language-css">body {
  font-size: 62.5%; /* sets default font size to 10px i.e 62.5% of 16px */
}
p {
  font-size: 1.4em; /* 14px */
}
</code></pre>
<p>As I earlier mentioned, use whatever makes you comfortable. And do not sweat it if you don't really get the hang of it, I still don't get most of it.</p>
<p><em>If 1.4em results to 14px, why not then just use 14px instead?</em></p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/JavaScript-Console-API-and-Methods</guid>
      <title>JavaScript Console API and Methods</title>
      <link>https://coleruche.com/post/JavaScript-Console-API-and-Methods</link>
      <description>A dive into the methods on the JavaScript inbuilt console object.</description>
      <pubDate>Sun, 26 May 2019 22:40:32 GMT</pubDate>
      <content:encoded><![CDATA[<p>As a JavaScript engineer, I have used the <code>console.log()</code> method more times than <a href="https://winteriscoming.net/2017/10/26/30-minutes-or-less-watch-all-174373-deaths-in-game-of-thrones-seasons-1-7/">the number of people killed in Game Of Thrones up to the 7th season</a> — well, maybe not that much.
The point, is that much like many other (newbie) JS coders, I pretty much knew <code>log()</code> as the only method on the JavaScript <code>console</code> object.</p>
<blockquote>
<p>Yes, it is an object.
You can verify this by opening up your browser console and running <code>typeof(console)</code> and you should get “object” returned back.</p>
</blockquote>
<p>Now that we have proven it is an object, like all other objects, it has many other methods in it apart from <code>log()</code>.</p>
<p>“Why is it so important knowing these other methods?”, you may ask. Well, although you might just go on using the <code>log</code> method to debug your code, learning about and using other methods helps in better representation and easier debugging. And <em>hey!</em>, why not learn more to help us combat our common enemy — bugs. Besides, you dunno what your next job interviewer has under their sleeves.</p>
<p>Let’s get started, shall we?</p>
<p>Hopefully, your browser console is still up and running, if not open it up again, and never close it till we are done with this, as we will get back to them occasionally.
To view other methods on the console, try running <code>console.log(console)</code> — the irony! The data below should be returned to us:</p>
<pre><code class="language-javascript">console {debug: ƒ, error: ƒ, info: ƒ, log: ƒ, warn: ƒ, …}
assert: ƒ assert()
clear: ƒ clear()
context: ƒ context()
count: ƒ count()
countReset: ƒ countReset()
debug: ƒ debug()
dir: ƒ dir()
dirxml: ƒ dirxml()
error: ƒ error()
group: ƒ group()
groupCollapsed: ƒ groupCollapsed()
groupEnd: ƒ groupEnd()
info: ƒ info()
log: ƒ log()
memory: (...)
profile: ƒ profile()
profileEnd: ƒ profileEnd()
table: ƒ table()
time: ƒ time()
timeEnd: ƒ timeEnd()
timeLog: ƒ timeLog()
timeStamp: ƒ timeStamp()
trace: ƒ trace()
warn: ƒ warn()
Symbol(Symbol.toStringTag): "Object"
get memory: ƒ ()
set memory: ƒ ()
__proto__: Object
</code></pre>
<p>This gives us so much more methods than we (rather, I) ever knew existed on the console. And like every other numerous lists, we will pick our most important ones.</p>
<p>###console.assert()
The simplest case of using the <code>assert()</code> method, is when we want to display something on the console only and only if the assertion passed into the method is false. If by any means the assertion passes, nothing happens, or you get an <code>undefined</code> if you are using a browser console. To see this in action, pull up your console if not open (PUYCINO — this is not a real thing) and run the following code:</p>
<pre><code class="language-javascript">var x = 21;
console.assert(x % 2 === 0, "oops! x is not divisible by 2");
// or alternatively

var errMsg = "oops! x is not divisible by 2";
console.assert(x % 2 === 0, errMsg);
</code></pre>
<p>You should get an assertion error with the error message printed to the console. Try changing <code>x</code> to 20 or any other even number and run the assert code again, this time nothing happens.</p>
<p>###console.clear()</p>
<p>This method is simple enough. Running <code>console.clear()</code> just clears the console and displays <code>Console was cleared</code> message (as if we cannot see it has been cleared). Run this code whenever you feel your console is all clogged up and you need room.</p>
<p>###console.dir() and console.dirxml()</p>
<p>This method helps us to print out to the console all the properties (methods) of any valid JavaScript object passed into it. Remember when we said — and proved — that <code>console</code> was an object. Now lets use it as an argument in the <code>console.dir()</code> method. PUYCINO and run the code <code>console.dir(console)</code> and a familiar output will be displayed. You can also try <code>console.dir(window)</code> to view the properties on the native Window object. And this will come in handy someday, you’ll see!</p>
<p><code>dirxml</code> is almost similar to <code>dir</code> with very small and insignificant differences.</p>
<p>###console.error()</p>
<p>This displays content as an error — red highlight, light red background and a red error (x) sign by the side. All features to let you know that what is being displayed is an error. Try running <code>console.error('This is a typical error')</code> and see what I mean.</p>
<p>The use case for this is when you are expecting an error in your code. Example, during a .catch block of an API call that returns a Promise.</p>
<p>###console.group(), console.groupCollapsed() and console.groupEnd()</p>
<p>These methods are used to group together blocks of code or similar <em>whatever it is you’re trying to display to the console.</em>
<code>group()</code> signifies the start of the group. It accepts an optional <code>label</code> as an argument. The label serves as, well, the label for the group.
<code>groupEnd()</code> marks the end of a group. 
<code>groupCollapsed()</code> works like <code>group()</code> but while all items in <code>group()</code> is automatically all listed out, <code>groupCollapsed()</code> displays them in a collapsed manner, you will have to manually click on a “dropdown” list beside it to list them all out.
Let us see this in action. PUYCINO and paste the following:</p>
<pre><code class="language-javascript">console.group("My fav tech tools");
// Here, 'my fav tech tools' is the label for my group
console.log("React");
console.log("Twitter Bootstrap");
console.log("Django");
console.log("Django REST");
console.log("Axios");
console.groupEnd(); //ends the group
</code></pre>
<p>Groups can also be nested into another group. Let’s see how this and <code>groupCollapsed()</code> works:</p>
<pre><code class="language-javascript">console.groupCollapsed("My fav languages and tools");
console.group("JavaScript"); //nests in JavaScript group
console.log("React");
console.log("Redux");
console.log("Twitter Bootstrap");
console.groupEnd(); //exits nested group for JavaScript
console.groupCollapsed("Python"); //nests in a collapsed Python group
console.log("Django");
console.log("Django REST");
console.groupEnd(); //exits nested group for Python
console.groupEnd(); //exits all groups
</code></pre>
<p>As you can see, at first the displayed groups are collapsed and you will have to expand them manually. Next, you can see we nested in two more groups: JavaScript and Python.</p>
<blockquote>
<p>Always remember to exit each nested group with <code>groupEnd()</code> as pointed out above.</p>
</blockquote>
<p>###console.log()</p>
<p>I think we all are familiar with this. So no need to waste time. It basically just prints out something to the console without any level of warning or danger.</p>
<p>###console.table()
This displays data in a tabular format. It takes in a compulsory <code>data</code> which must be an array or object — passing in a string does not work — and an optional <code>columns</code> as parameter.
Let us see this in action. Again, PUYCINO (hey, by now there is no more need to include this). Paste in the following:</p>
<pre><code class="language-javascript">var nations = ["Nigeria", "USA", "Canada", "Algeria"];
console.table(nations);
</code></pre>
<p>This should print the data out in a tabular form with <code>(index)</code> and <code>value</code> columns. Using arrays, the <code>(index)</code> column is auto filled with the index of the instance. To specify what should be used as the table’s index, pass in objects instead. Here, the <code>(index)</code> column will be filled by the <code>keys</code> of the object while the value will be filled by the <code>values</code> of the object. Try below:</p>
<pre><code class="language-javascript">var nationsCurrency = { USA: "dollars", Nigeria: "naira", France: "franc" };
console.table(nationsCurrency);
</code></pre>
<p>###console.time() and console.timeEnd()</p>
<p><code>time()</code> starts a timer you can use to track how long an operation takes. It takes in an optional <code>label</code> as argument. Calling t<code>imeEnd()</code> with the same <code>label</code> ends the timer and ouputs the time (in miliseconds) that has elapsed since <code>time()</code> was called and code between <code>time()</code> and <code>timeEnd()</code> has executed.</p>
<pre><code class="language-javascript">console.time("test");
let mult = 2000 * 4444;
mult * 222;
console.timeEnd("test");
</code></pre>
<p>Best use case for this is to compare which two similar functions or logic is faster. Example, the code below compares the speed of execution of <code>for</code> and <code>while</code> loops.</p>
<pre><code class="language-javascript">console.time("test for loop");
for (i = 0; i &#x3C; 100000; i++) {
  console.log(i);
}
console.timeEnd("test for loop");

console.time("test while loop");
while (i &#x3C; 1000000) {
  i++;
}
console.timeEnd("test while loop");
</code></pre>
<p>From running the above code, we can effectively see that the <code>for</code> loop is faster than the <code>while</code>.</p>
<p>###console.warn()</p>
<p>Outputs a warning message to the browser console. It displays the data in a light yellow background with a warning icon by the side. Try it:</p>
<pre><code class="language-javascript">console.warn(
  "GOT is hugely graphical and full of violent. Watch at your own discretion."
);
</code></pre>
<p>We are done with the important methods. Hopefully by now you will have less <code>console.log()</code> lines during debugging sessions.</p>
<p>Or maybe not, either way thanks for getting this far.</p>
<p><strong><em>Valar Morghulis!</em></strong></p>
]]></content:encoded>
    </item>
    <item>
      <guid>https://coleruche.com/post/uploading-images-to-REST-API-backend-in-React-JS</guid>
      <title>Uploading images to REST API backend in React JS</title>
      <link>https://coleruche.com/post/uploading-images-to-REST-API-backend-in-React-JS</link>
      <description>We will look at how to send images to a back end with React forms.</description>
      <pubDate>Thu, 28 Feb 2019 22:40:32 GMT</pubDate>
      <content:encoded><![CDATA[<p>So I would be writing about a very challenging task I faced when building a test project for a job I applied to: I was asked to build a React app that lets users add products with descriptions, categories, and an image, while utilising an API. So the issue was that I have built a few learning apps that gets data from a React form and send it to a backend through an API POST call to a REST API - but never an image!
I spent a good amount of time that day (and the next!) trying to get this done. I came across a lot of tutorials and articles online saying to utilize FormData, but just could not get my head around it.
So after lots of trials and heartbreaks, I got it done, and I am here to teach you how to do it.</p>
<blockquote>
<p>DISCLAIMERS:</p>
<p>This tutorial assumes you have basic knowledge of Django and React JS. This is not a tutorial for them.</p>
<p>The processes here uses django and django rest framework for its backend configurations. But the React logic works for any backend framework - just do a little bit more googling regarding your framework.</p>
</blockquote>
<p>###Tools and Frameworks</p>
<ul>
<li>
<p>React: We will be using React to build the UI components for our form. I presume by now you understand the conecpt of React and what it is.</p>
</li>
<li>
<p>Axios: We shall use axios to make the post requests. Axios is a Promise based HTTP client for the browser and node.js. It is used to make XMLHttpRequests to a server.</p>
</li>
<li>
<p>Django: Django is a web framework for the Python programming language.</p>
</li>
<li>
<p>Django Rest Framework: DRF is a framework (a Django app — actually) that enables us build simple but yet highly customizable RESTful APIs.</p>
</li>
<li>
<p>Django-CORS-Headers: django-cors-headers is a Django application for handling the server headers required for Cross-Origin Resource Sharing (CORS).</p>
</li>
<li>
<p>Pillow: This is a Python Image Library you need to have installed when your models have an image field, else you will get an error when running migrations and migrating.</p>
</li>
</ul>
<p>###Project Setup:
<em>Please note the command lines I will be using here is for Windows</em></p>
<p>The project will be divided into two directories — frontend and backend.
So cd into your preferred directory and create the root project folder:</p>
<pre><code class="language-shell">#cmd

mkdir react-form-data &#x26;&#x26; cd react-form-data
</code></pre>
<p>Now, we will create two folders frontend and backend which will contain the codes respectively.
The front end will be created by <a href="https://facebook.github.io/create-react-app/">create-react-app</a> — which I assume you are comfortable with — while the backend will be with django-admin.</p>
<p>Now while in the react-form-data directory, run the following commands:</p>
<pre><code class="language-shell">#cmd

mkdir backend &#x26;&#x26; cd backend
django-admin startproject backend .
cd .. &#x26;&#x26; npx create-react-app frontend
</code></pre>
<p>The code above creates a backend directory and we move into it to create our django app also called backend. Remember to add the . so as not to create another folder there.</p>
<p>###Getting Started:
We will start with the backend.As with most Python projects, we need to set up a virtual environment, using virtualenv. <code>cd</code> into the root <code>react-form-data</code> project folder with CLI and type in <code>virtualenv env</code> and start up the virtual environment with <code>env\Scripts\activate</code>. On running la in your root project folder you should see:</p>
<pre><code>backend env frontend
</code></pre>
<p>Now, making sure the virtual environment is running, run the following in CLI to install the required packages:</p>
<pre><code class="language-python">cd backend
pip install django djangorestframework django-cors-headers Pillow
</code></pre>
<p>This installs the required packages. Now open the settings.py file in your favorite IDE and update the INSTALLED_APPS to include the installed apps:</p>
<pre><code class="language-python">INSTALLED_APPS = [
    ...,
    'rest_framework',  # for rest api
    'corsheaders',  # for cors policies
]
</code></pre>
<p>Now we create our own ‘post’ app to handle the API logic and views.
cd into the root <code>backend</code> directory and run <code>python manage.py startapp post</code>. Remember to include this in <code>INSTALLED_APPS</code>.</p>
<p>Next, add these two lines</p>
<pre><code class="language-py">'corsheaders.middleware.CorsMiddleware'
</code></pre>
<p>and</p>
<pre><code class="language-py">'django.middleware.common.CommonMiddleware'
</code></pre>
<p>above other lines in the MIDDLEWARE section, making sure</p>
<pre><code class="language-py">corsheaders.middleware.CorsMiddleware
</code></pre>
<p>above all others. Your middlewares should look like these:</p>
<pre><code class="language-python">MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
</code></pre>
<p>Right below the MIDDLEWARE section, add this line: <code>CORS_ORIGIN_ALLOW_ALL = True</code>. This enables all API requests from a different server to be allowed.
Also, since we are dealing with uploaded images, add the following to the bottom of your settings.py file:</p>
<pre><code class="language-python">MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
</code></pre>
<p>Overall, your settings.py file should look like this:</p>
<pre><code class="language-python">Django settings for backend project.
Generated by 'django-admin startproject' using Django 2.1.7.
For more information on this file, see
https://docs.djangoproject.com/en/2.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.1/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '9zff9-n4#2g--_$4@g4uu-zauef(s^i3^z_!7wtpzduma59ku8'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'post',
    'rest_framework',  # for django rest api
    'corsheaders',  # for rest api
]

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

CORS_ORIGIN_ALLOW_ALL = True

ROOT_URLCONF = 'backend.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'backend.wsgi.application'

# Database
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

# Password validation
# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

# Internationalization
# https://docs.djangoproject.com/en/2.1/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/

STATIC_URL = '/static/'

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

</code></pre>
<p>Now let us create our models for the posts.
Open up post/models.py and paste in the following code:</p>
<pre><code class="language-python">from django.db import models

# Create your models here.

class Post(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    image = models.ImageField(upload_to='post_images')

    def __str__(self):
        return self.title
</code></pre>
<p>Create a new media directory at the same level as manage.py to store our uploaded images.
Now, to register our model. Open up post/admin.py and paste the followng code:</p>
<pre><code class="language-python">from django.contrib import admin
from .models import Post

# Register your models here.

admin.site.register(Post)
</code></pre>
<p>Now, you must be wondering, when do we run migrations? Now! With the command line, <code>cd </code> into the root project folder and run:
<code>python manage.py makemigrations</code> and then <code>python manage.py migrate.</code>
Now, to the juicy part — serializers! Serializers is a way to convert Python data to API JSON format and vice-versa.
Create a new serializers.py file in the post directory an paste the code:</p>
<pre><code class="language-py">
from rest_framework import serializers
from .models import Post

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = '__all__'
</code></pre>
<p>We just created a new class that extends the ModelSerializer of DRF. model in class Meta just specifies the model to use, while fields can be a tuple or list holding the individual fields in the model, or takes in <code>__all__</code> to just serialize all fields.
Now, open up the post/views.py file and paste the following:</p>
<pre><code class="language-py">from .serializers import PostSerializer
from .models import Post
from rest_framework.views import APIView
from rest_framework.parsers import MultiPartParser, FormParser
from rest_framework.response import Response
from rest_framework import status
# Create your views here.

class PostView(APIView):
    parser_classes = (MultiPartParser, FormParser)

    def get(self, request, *args, **kwargs):
        posts = Post.objects.all()
        serializer = PostSerializer(posts, many=True)
        return Response(serializer.data)

    def post(self, request, *args, **kwargs):
        posts_serializer = PostSerializer(data=request.data)
        if posts_serializer.is_valid():
            posts_serializer.save()
            return Response(posts_serializer.data, status=status.HTTP_201_CREATED)
        else:
            print('error', posts_serializer.errors)
            return Response(posts_serializer.errors, status=status.HTTP_400_BAD_REQUEST)


</code></pre>
<p>I believe you understand the imports . The <code>parser_class</code> is used because we are dealing with request data that comes in as FormData. Two class methods <code>get</code> and <code>post</code> are defined to handle the respective requests.
Now, to the urls. Create a new <code>urls.py</code> file in the post directory. Open it and add the following code:</p>
<pre><code class="language-py">
from django.urls import path
from . import views

urlpatterns = [
    path('posts/', views.PostView.as_view(), name= 'posts_list'),
]
</code></pre>
<p>Now, to add this new url to our project urls, open up backend/urls.py and change the code to this:</p>
<pre><code class="language-py">from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('post.urls')),
]
</code></pre>
<p>Now, let us create a super user and test what we have been doing all along. With command line, cd into the root backend directory and <code>run python manage.py createsuperuser</code> and follow the prompts to create one. Now fire up the server by running <code>python manage.py runserver</code> and go to <a href="https://www.localhost:8000/api/posts">localhost:8000/api/posts</a>. You will be greeted with the following page, if everything works out well:</p>
<p><img src="/images/posts/pic1.png" alt="post form without data"></p>
<p>Now, no posts can be seen cos we have not added any. Navigate to <a href="https://localhost:8000/admin">localhost:8000/admin</a> to add a few posts. Done? Navigate back to <a>https://localhost:8000/api/posts</a>. You should get this — but with the data you put in.</p>
<p><img src="/images/posts/pic2.png" alt="post form with data">
Now, our backend works correctly. Now to React.</p>
<p>Remember we had already created a React <code>frontend</code> directory with <code>create-react-app</code>. Now, using the command line, <code>cd</code> into the <code>frontend</code> directory and run <code> npm install axios</code>. This installs axios for making the HTTP requests. Now run <code>npm run start</code>. We should be greeted with the popular React welcome page.
Now open the <code>frontend</code> directory in your editor and let us start by clearing a few things — delete the <code>App.css</code> , <code>logo.svg</code> and <code>App.test.js</code> files as we would not be needing them. Don’t forget to remove lines where they are referenced in <code>App.js</code>.
As this is a little project, our code will live in <code>App.js</code>
Modify your <code>App.js</code> file to look like:</p>
<pre><code class="language-jsx">import React, { Component } from "react";
import axios from "axios";

class App extends Component {
  state = {
    title: "",
    content: "",
    image: null,
  };

  handleChange = (e) => {
    this.setState({
      [e.target.id]: e.target.value,
    });
  };

  handleImageChange = (e) => {
    this.setState({
      image: e.target.files[0],
    });
  };

  handleSubmit = (e) => {
    e.preventDefault();
    console.log(this.state);
    let form_data = new FormData();
    form_data.append("image", this.state.image, this.state.image.name);
    form_data.append("title", this.state.title);
    form_data.append("content", this.state.content);
    let url = "http://localhost:8000/api/posts/";
    axios
      .post(url, form_data, {
        headers: {
          "content-type": "multipart/form-data",
        },
      })
      .then((res) => {
        console.log(res.data);
      })
      .catch((err) => console.log(err));
  };

  render() {
    return (
      &#x3C;div className="App">
        &#x3C;form onSubmit={this.handleSubmit}>
          &#x3C;p>
            &#x3C;input
              type="text"
              placeholder="Title"
              id="title"
              value={this.state.title}
              onChange={this.handleChange}
              required
            />
          &#x3C;/p>
          &#x3C;p>
            &#x3C;input
              type="text"
              placeholder="Content"
              id="content"
              value={this.state.content}
              onChange={this.handleChange}
              required
            />
          &#x3C;/p>
          &#x3C;p>
            &#x3C;input
              type="file"
              id="image"
              accept="image/png, image/jpeg"
              onChange={this.handleImageChange}
              required
            />
          &#x3C;/p>
          &#x3C;input type="submit" />
        &#x3C;/form>
      &#x3C;/div>
    );
  }
}

export default App;
</code></pre>
<p>I am going to try and explai what is going on here, as this is the main focus of this article.</p>
<ul>
<li>In <code>line 1</code> and <code>line 2</code> , we imported React (and Component) and axios respectively.</li>
<li>In <code>line 6</code> we set our initial state, which is just the respective fields in our <code>post</code> model. We use this to pass the FormData to the backend.</li>
<li><code>line 12</code> is where we handle form value changes to set our state to the value of the new input value. This method of using states in our forms in React is called <a href="https://reactjs.org/docs/forms.html#controlled-components">Controlled Forms</a>.</li>
<li><code>line 18</code> is an important one. We also set the state, but now the image property of our state is set to the the first file data of the event target, since the target is an array of files.</li>
<li>Another important part is the <code>handleSubmit</code> method in <code>line 24</code>. First, the default character of forms — which is reloading the web page — is prevented. Then a new instance of the in-built JavaScript’s FormData is instantiated by calling <code>new FormData()</code> in <code>line 27</code> . One method of the FormData is <code>append</code> which takes in two required parameters — a key:value pair — with the first parameter being the <strong>key</strong> while the second is the <strong>value</strong>. The key should correspond to the field in your django models — this is important to avoid errors! The <code>append</code> method is called on the FormData passing in three different times to add the form values, now saved in the state. The FormData is now one large parcel of data that is now passed as the body of our axios <code>POST</code> call to our Django REST API.</li>
<li>Please make note of the <code>content-type</code> in the axios headers. It should be set to <code>multipart/form-data</code>.</li>
</ul>
<p>Now, go back to the web page and try to fill in the forms and add an image. Submit. You will get a JSON response logged in your console with the request data, and an ID — which shows it has been successfully uploaded to the backend and a new object created. To verify this, go to <a href="http://localhost:8000/api/posts/">localhost:8000/api/posts</a> (with your django local server running, of course) and you will see the newly added post.</p>
<p>Thanks for following along and I hope you got it right.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>