<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Moonlit Capy</title>
    <description>The latest articles on DEV Community by Moonlit Capy (@moonlitcapy).</description>
    <link>https://dev.to/moonlitcapy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3783575%2Fa4f83d91-e594-442b-9567-5e881a669146.jpg</url>
      <title>DEV Community: Moonlit Capy</title>
      <link>https://dev.to/moonlitcapy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/moonlitcapy"/>
    <language>en</language>
    <item>
      <title>I Built a Free Dark-Themed Daily Journal &amp; Gratitude Planner (PDF)</title>
      <dc:creator>Moonlit Capy</dc:creator>
      <pubDate>Sat, 21 Feb 2026 13:29:08 +0000</pubDate>
      <link>https://dev.to/moonlitcapy/i-built-a-free-dark-themed-daily-journal-gratitude-planner-pdf-3om3</link>
      <guid>https://dev.to/moonlitcapy/i-built-a-free-dark-themed-daily-journal-gratitude-planner-pdf-3om3</guid>
      <description>&lt;p&gt;Journaling is one of the most effective habits for improving mental clarity, emotional well-being, and personal growth. But let's be honest â€” most journal templates are cluttered, uninspiring, and not enjoyable to use.&lt;/p&gt;

&lt;p&gt;So I built something different: a &lt;strong&gt;free printable Daily Journal &amp;amp; Gratitude Planner&lt;/strong&gt; with a beautiful dark theme, designed for people who actually want to use their planner every day.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Inside (5 Pages, A4 PDF)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Page 1: Cover
&lt;/h3&gt;

&lt;p&gt;A clean, modern cover with amber/orange accent colors. Looks great printed or on a tablet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Page 2: Morning Routine &amp;amp; Daily Intentions
&lt;/h3&gt;

&lt;p&gt;Start your day with structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Morning Checklist&lt;/strong&gt; â€” track habits like hydrate, exercise, meditate, healthy breakfast&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mood Tracker&lt;/strong&gt; â€” 7 emoji-based mood options to check in with yourself&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Top 3 Priorities&lt;/strong&gt; â€” focus on what actually matters today&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Daily Schedule&lt;/strong&gt; â€” time blocks from 6 AM to 9 PM&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Page 3: Daily Journal
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Journal Prompt&lt;/strong&gt; â€” a rotating prompt to spark reflection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free Writing Area&lt;/strong&gt; â€” 12 lined rows for unstructured thoughts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wins &amp;amp; Accomplishments&lt;/strong&gt; â€” celebrate what went right&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lessons Learned&lt;/strong&gt; â€” capture growth moments&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Page 4: Gratitude &amp;amp; Evening Reflection
&lt;/h3&gt;

&lt;p&gt;Wind down intentionally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;5 Gratitude Entries&lt;/strong&gt; â€” write what you're thankful for&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evening Reflection Questions&lt;/strong&gt; â€” what went well? what to improve?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-Care Checklist&lt;/strong&gt; â€” track healthy screen time, reading, stretching&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Daily Affirmation&lt;/strong&gt; â€” end on a positive note&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sleep Quality Tracker&lt;/strong&gt; â€” 5-level rating&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Page 5: Habit Tracker &amp;amp; Monthly Goals
&lt;/h3&gt;

&lt;p&gt;The long game:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;31-Day Habit Grid&lt;/strong&gt; â€” track up to 10 habits across an entire month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;4 Goal Cards&lt;/strong&gt; â€” each with title, deadline, and 3 action steps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Month-in-Review&lt;/strong&gt; â€” summarize highlights, challenges, and next month focus&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why Dark Theme?
&lt;/h2&gt;

&lt;p&gt;Two reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;It looks stunning&lt;/strong&gt; â€” modern gradients, amber accents, clean typography&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Less ink when printing&lt;/strong&gt; â€” inverted backgrounds use less toner on most printers&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you prefer digital journaling on a tablet (iPad, Android tablet), the dark theme is even better â€” easier on the eyes during evening journaling sessions.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Use It
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Download the PDF&lt;/strong&gt; â€” it's pay-what-you-want ($0 minimum)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Print it&lt;/strong&gt; â€” A4 size, works on any printer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Or use digitally&lt;/strong&gt; â€” import into GoodNotes, Notability, or any PDF annotation app&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fill it in daily&lt;/strong&gt; â€” morning routine â†’ journal â†’ evening reflection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monthly review&lt;/strong&gt; â€” use the habit tracker and goal cards for long-term progress&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Science Behind It
&lt;/h2&gt;

&lt;p&gt;Journaling isn't just a feel-good activity. Research shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gratitude journaling&lt;/strong&gt; reduces stress and improves sleep quality (&lt;a href="https://www.health.harvard.edu/healthbeat/giving-thanks-can-make-you-happier" rel="noopener noreferrer"&gt;source&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Habit tracking&lt;/strong&gt; increases follow-through by making progress visible&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Morning routines&lt;/strong&gt; with intention-setting improve focus and productivity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evening reflection&lt;/strong&gt; helps consolidate learning and emotional processing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This planner combines all four practices into a single daily workflow.&lt;/p&gt;




&lt;h2&gt;
  
  
  Get It Free
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/daily-journal" rel="noopener noreferrer"&gt;Download Daily Journal &amp;amp; Gratitude Planner&lt;/a&gt;&lt;/strong&gt; â€” $0+ (pay what you want, suggested $3)&lt;/p&gt;

&lt;p&gt;No sign-up walls. No email required. Just download and start journaling.&lt;/p&gt;




&lt;h2&gt;
  
  
  More Free Planners
&lt;/h2&gt;

&lt;p&gt;If you like this style, check out my other printable planners â€” all free, all dark-themed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://moonlitcapy.gumroad.com/l/dev-reference-card" rel="noopener noreferrer"&gt;Developer Quick Reference Card&lt;/a&gt; â€” coding cheat sheet&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://moonlitcapy.gumroad.com/l/budget-planner" rel="noopener noreferrer"&gt;Monthly Budget Planner&lt;/a&gt; â€” personal finance tracker&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://moonlitcapy.gumroad.com/l/workout-tracker" rel="noopener noreferrer"&gt;Workout Log &amp;amp; Fitness Tracker&lt;/a&gt; â€” exercise logging&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://moonlitcapy.gumroad.com/l/study-planner" rel="noopener noreferrer"&gt;Study Planner &amp;amp; Exam Tracker&lt;/a&gt; â€” academic planning&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://moonlitcapy.gumroad.com/l/meal-planner" rel="noopener noreferrer"&gt;Weekly Meal Planner &amp;amp; Grocery List&lt;/a&gt; â€” meal prep &amp;amp; nutrition&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Built with care by &lt;a href="https://marks-portfolio.elunari.uk" rel="noopener noreferrer"&gt;Moonlit Capy&lt;/a&gt;. If these planners help you, consider &lt;a href="https://buymeacoffee.com/moonlitcapy" rel="noopener noreferrer"&gt;buying me a coffee&lt;/a&gt; or paying what you want on Gumroad.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>journaling</category>
      <category>free</category>
      <category>mindfulness</category>
    </item>
    <item>
      <title>6 Free Printable Planners to Organize Your Life (Dark Theme, A4 PDF)</title>
      <dc:creator>Moonlit Capy</dc:creator>
      <pubDate>Sat, 21 Feb 2026 13:01:14 +0000</pubDate>
      <link>https://dev.to/moonlitcapy/5-free-printable-planners-to-organize-your-life-dark-theme-a4-pdf-1pbo</link>
      <guid>https://dev.to/moonlitcapy/5-free-printable-planners-to-organize-your-life-dark-theme-a4-pdf-1pbo</guid>
      <description>&lt;p&gt;Looking for printable planners that don't look like they were made in Microsoft Word circa 2003? Same.&lt;/p&gt;

&lt;p&gt;I couldn't find free planners that were actually nice to look at and use, so I built my own. All &lt;strong&gt;6 planners&lt;/strong&gt; below are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free&lt;/strong&gt; ($0 minimum, pay what you want)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dark-themed&lt;/strong&gt; with modern gradients and accent colors&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A4 PDF format&lt;/strong&gt; â€” print or use digitally&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;5 pages each&lt;/strong&gt; â€” packed with useful layouts, not filler&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here they are:&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Developer Quick Reference Card
&lt;/h2&gt;

&lt;p&gt;A coding cheat sheet covering terminal commands, Git workflows, HTTP status codes, regex patterns, data structures, and Big-O notation. Built for developers who want a printed reference next to their monitor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/dev-reference-card" rel="noopener noreferrer"&gt;Get it free on Gumroad â†’&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Monthly Budget Planner
&lt;/h2&gt;

&lt;p&gt;Track income, fixed expenses, variable spending, savings goals, and subscriptions. Includes a monthly overview, expense tracker, savings progress, and annual summary page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/budget-planner" rel="noopener noreferrer"&gt;Get it free on Gumroad â†’&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Workout Log &amp;amp; Fitness Tracker
&lt;/h2&gt;

&lt;p&gt;Log exercises with sets, reps, and weights. Track body measurements, personal records, weekly cardio, and monthly fitness goals. Built for people who actually go to the gym.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/workout-tracker" rel="noopener noreferrer"&gt;Get it free on Gumroad â†’&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Study Planner &amp;amp; Exam Tracker
&lt;/h2&gt;

&lt;p&gt;Manage your semester with a course tracker, weekly schedule grid, daily study session logs, exam preparation checklists, and goal-setting pages. Built for students who want structure without apps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/study-planner" rel="noopener noreferrer"&gt;Get it free on Gumroad â†’&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Weekly Meal Planner &amp;amp; Grocery List
&lt;/h2&gt;

&lt;p&gt;Plan meals for the entire week across breakfast, lunch, dinner, and snacks. Includes grocery lists organized by category (produce, proteins, dairy, pantry staples), meal prep schedules, and nutrition tracking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/meal-planner" rel="noopener noreferrer"&gt;Get it free on Gumroad â†’&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Daily Journal &amp;amp; Gratitude Planner âœ¨ NEW
&lt;/h2&gt;

&lt;p&gt;Start your morning with intention and end your evening with reflection. Includes morning routine checklist, mood tracker, daily priorities, free-writing journal pages, gratitude entries, self-care checklist, 31-day habit tracker grid, and monthly goal cards.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/daily-journal" rel="noopener noreferrer"&gt;Get it free on Gumroad â†’&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Dark Theme?
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Aesthetics&lt;/strong&gt; â€” They actually look good. Modern gradients, clean typography, visually appealing layouts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Less ink&lt;/strong&gt; â€” Dark backgrounds with light text use surprisingly less toner on most modern printers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Digital-friendly&lt;/strong&gt; â€” If you use them on a tablet (GoodNotes, Notability, etc.), dark themes reduce eye strain.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  How to Use Them
&lt;/h2&gt;

&lt;p&gt;All planners are standard A4 PDFs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Print them&lt;/strong&gt; â€” any home or office printer works&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use digitally&lt;/strong&gt; â€” import into your favorite PDF annotation app&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Combine them&lt;/strong&gt; â€” mix and match pages from different planners&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No accounts, no sign-ups, no email walls. Just download and use.&lt;/p&gt;




&lt;h2&gt;
  
  
  Browse All Planners
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://moonlitcapy.gumroad.com" rel="noopener noreferrer"&gt;See all products on Gumroad â†’&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with care by &lt;a href="https://marks-portfolio.elunari.uk" rel="noopener noreferrer"&gt;Moonlit Capy&lt;/a&gt;. If these help you, consider &lt;a href="https://buymeacoffee.com/moonlitcapy" rel="noopener noreferrer"&gt;buying me a coffee&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Also check out &lt;a href="https://tools.elunari.uk" rel="noopener noreferrer"&gt;85+ free developer tools&lt;/a&gt; built by the same team.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>free</category>
      <category>planners</category>
      <category>tools</category>
    </item>
    <item>
      <title>3 Free Printable Planners That Actually Help You Stay Organized</title>
      <dc:creator>Moonlit Capy</dc:creator>
      <pubDate>Sat, 21 Feb 2026 11:41:25 +0000</pubDate>
      <link>https://dev.to/moonlitcapy/3-free-printable-planners-that-actually-help-you-stay-organized-11f9</link>
      <guid>https://dev.to/moonlitcapy/3-free-printable-planners-that-actually-help-you-stay-organized-11f9</guid>
      <description>&lt;p&gt;Staying organized shouldn't require expensive apps or complex systems. Sometimes, a simple printable planner you can keep on your desk works better than any digital tool.&lt;/p&gt;

&lt;p&gt;I created three free printable planners covering the areas where most people struggle: &lt;strong&gt;work output, money, and fitness&lt;/strong&gt;. They're all pay-what-you-want (including $0), PDF format, designed for A4/Letter printing.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Developer Quick Reference Card
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;For&lt;/strong&gt;: Software developers who constantly Google the same commands.&lt;/p&gt;

&lt;p&gt;A compact 11-page landscape cheat sheet covering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Git commands &amp;amp; workflows&lt;/li&gt;
&lt;li&gt;Docker essentials&lt;/li&gt;
&lt;li&gt;JavaScript/TypeScript patterns&lt;/li&gt;
&lt;li&gt;React hooks &amp;amp; lifecycle&lt;/li&gt;
&lt;li&gt;SQL queries &amp;amp; joins&lt;/li&gt;
&lt;li&gt;HTTP status codes &amp;amp; API patterns&lt;/li&gt;
&lt;li&gt;Terminal shortcuts&lt;/li&gt;
&lt;li&gt;VS Code keyboard shortcuts&lt;/li&gt;
&lt;li&gt;CSS Layout (Flexbox + Grid)&lt;/li&gt;
&lt;li&gt;Regex patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Print it, pin it next to your monitor, stop context-switching to Stack Overflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/dev-reference-card" rel="noopener noreferrer"&gt;&lt;strong&gt;Get it free on Gumroad&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Monthly Budget Planner
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;For&lt;/strong&gt;: Anyone who reaches the end of the month wondering where their money went.&lt;/p&gt;

&lt;p&gt;A 5-page A4 portrait planner with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Monthly Overview&lt;/strong&gt; - income tracker + fixed bills checklist&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expense Tracker&lt;/strong&gt; - 6 categories (Housing, Food, Transport, Health, Personal, Education)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Savings &amp;amp; Goals&lt;/strong&gt; - 4 goal cards + debt tracker + monthly reflection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Daily Spending Log&lt;/strong&gt; - 31 days of item/category/amount tracking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The structure forces you to actually look at your spending patterns instead of just tracking totals.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/budget-planner" rel="noopener noreferrer"&gt;&lt;strong&gt;Get it free on Gumroad&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Workout Log &amp;amp; Fitness Tracker
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;For&lt;/strong&gt;: Gym-goers who want to track progress without paying for an app subscription.&lt;/p&gt;

&lt;p&gt;A 5-page A4 portrait tracker with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Weekly Workout Overview&lt;/strong&gt; - Mon-Fri + weekend split with weekly summary&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workout Log&lt;/strong&gt; - warm-up, 8 main exercises (4 sets each), cool-down&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Body Measurements &amp;amp; Progress&lt;/strong&gt; - core stats, upper/lower body measurements, strength PRs, 6-month weight chart&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Goals, Habits &amp;amp; Notes&lt;/strong&gt; - 4 goal cards, weekly habit tracker (6 habits x 7 days)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I designed this because most fitness apps try to upsell you into a premium tier just to log your sets. A piece of paper doesn't have a paywall.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/workout-tracker" rel="noopener noreferrer"&gt;&lt;strong&gt;Get it free on Gumroad&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Printable?
&lt;/h2&gt;

&lt;p&gt;Digital tools are great, but they add friction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need your phone/laptop open&lt;/li&gt;
&lt;li&gt;Notifications interrupt your flow&lt;/li&gt;
&lt;li&gt;Apps sunset features behind paywalls&lt;/li&gt;
&lt;li&gt;Battery dies at the gym&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A printed sheet is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Always visible (pin it, tape it, fold it)&lt;/li&gt;
&lt;li&gt;Zero boot time&lt;/li&gt;
&lt;li&gt;No subscription&lt;/li&gt;
&lt;li&gt;No distractions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I keep one of each on my desk. The budget planner goes in my wallet. The workout log goes in my gym bag. Friction-free.&lt;/p&gt;




&lt;h2&gt;
  
  
  All Three Are Free
&lt;/h2&gt;

&lt;p&gt;Every planner is pay-what-you-want starting at $0. No email gate, no free trial, no upsell. Download the PDF, print it, use it.&lt;/p&gt;

&lt;p&gt;If they save you even 10 minutes a week, &lt;a href="https://buymeacoffee.com/moonlitcapy" rel="noopener noreferrer"&gt;consider buying me a coffee&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also check out &lt;a href="https://tools.elunari.uk" rel="noopener noreferrer"&gt;85+ free developer tools&lt;/a&gt; I built - things like JSON formatters, regex testers, color palette generators, and more.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;What productivity tools do you keep on your physical desk? I'd love to hear in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>career</category>
      <category>health</category>
      <category>beginners</category>
    </item>
    <item>
      <title>React Performance Optimization: From Slow to Lightning Fast</title>
      <dc:creator>Moonlit Capy</dc:creator>
      <pubDate>Sat, 21 Feb 2026 08:57:59 +0000</pubDate>
      <link>https://dev.to/moonlitcapy/react-performance-optimization-from-slow-to-lightning-fast-oof</link>
      <guid>https://dev.to/moonlitcapy/react-performance-optimization-from-slow-to-lightning-fast-oof</guid>
      <description>&lt;p&gt;&lt;em&gt;14 min read&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;React is fast by default — until it isn't. As applications grow, rendering bottlenecks creep in. This guide covers the techniques for diagnosing and fixing performance issues in production React applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule Zero: Measure First
&lt;/h2&gt;

&lt;p&gt;Use React DevTools Profiler to find the actual bottleneck. Open the Profiler tab, record an interaction, and examine which components re-rendered and why.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preventing Unnecessary Re-renders
&lt;/h2&gt;

&lt;h3&gt;
  
  
  React.memo
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ExpensiveChart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ExpensiveChart&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ChartProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Only re-renders when props actually change&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;canvas&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  useMemo for Expensive Computations
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;summary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;byCategory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;groupBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;category&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  React Compiler (React 19)
&lt;/h2&gt;

&lt;p&gt;React 19 introduces automatic memoization at build time, making manual &lt;code&gt;memo&lt;/code&gt;/&lt;code&gt;useMemo&lt;/code&gt;/&lt;code&gt;useCallback&lt;/code&gt; largely unnecessary for new code. Enable with &lt;code&gt;experimental: { reactCompiler: true }&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Splitting
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DataViz&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./DataVisualization&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Dashboard&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Skeleton&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DataViz&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Virtualization for Long Lists
&lt;/h2&gt;

&lt;p&gt;Render only visible items. Use &lt;code&gt;@tanstack/react-virtual&lt;/code&gt; for lists over 100 items. The overhead of the virtualizer is negligible compared to rendering thousands of DOM nodes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Colocate State
&lt;/h2&gt;

&lt;p&gt;The most impactful technique: put state as close as possible to where it's used. Global state that changes frequently causes the entire tree to re-render.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Profile first — don't guess&lt;/li&gt;
&lt;li&gt;Colocate state — move it down&lt;/li&gt;
&lt;li&gt;Virtualize long lists (100+ items)&lt;/li&gt;
&lt;li&gt;Code split heavy routes&lt;/li&gt;
&lt;li&gt;Optimize images (next/image or lazy loading)&lt;/li&gt;
&lt;li&gt;Defer non-urgent updates (useDeferredValue)&lt;/li&gt;
&lt;li&gt;Enable React Compiler in React 19&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Focus on architecture (where state lives, how data flows) rather than micro-optimizations. A well-structured app is fast by default.&lt;/p&gt;




&lt;p&gt;Explore &lt;a href="https://tools.elunari.uk" rel="noopener noreferrer"&gt;85+ free developer tools&lt;/a&gt; or &lt;a href="https://buymeacoffee.com/moonlitcapy" rel="noopener noreferrer"&gt;support this work&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Keep Leveling Up
&lt;/h2&gt;

&lt;p&gt;If you found this useful, check out my &lt;strong&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/dev-reference-card" rel="noopener noreferrer"&gt;Dev Reference Card&lt;/a&gt;&lt;/strong&gt; - a downloadable cheat sheet with essential developer patterns, shortcuts, and references condensed into one page.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/dev-reference-card" rel="noopener noreferrer"&gt;Grab it here&lt;/a&gt; for the price of a coffee.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Browse all my tools and templates at &lt;a href="https://moonlitcapy.gumroad.com" rel="noopener noreferrer"&gt;moonlitcapy.gumroad.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>performance</category>
      <category>frontend</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Docker Essentials: A Developer's Practical Guide for 2026</title>
      <dc:creator>Moonlit Capy</dc:creator>
      <pubDate>Sat, 21 Feb 2026 08:49:08 +0000</pubDate>
      <link>https://dev.to/moonlitcapy/docker-essentials-a-developers-practical-guide-for-2026-47mo</link>
      <guid>https://dev.to/moonlitcapy/docker-essentials-a-developers-practical-guide-for-2026-47mo</guid>
      <description>&lt;p&gt;&lt;em&gt;13 min read&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Docker changed how we build and ship software. This guide covers Docker from a developer's perspective — the concepts, commands, and patterns you'll use daily.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Concepts
&lt;/h2&gt;

&lt;p&gt;An &lt;strong&gt;image&lt;/strong&gt; is a read-only blueprint. A &lt;strong&gt;container&lt;/strong&gt; is a running instance. A &lt;strong&gt;Dockerfile&lt;/strong&gt; is the recipe. A &lt;strong&gt;volume&lt;/strong&gt; persists data. A &lt;strong&gt;network&lt;/strong&gt; connects containers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Essential Commands
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;--tag&lt;/span&gt; myapp:latest &lt;span class="nb"&gt;.&lt;/span&gt;
docker run &lt;span class="nt"&gt;--detach&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; myapp &lt;span class="nt"&gt;--publish&lt;/span&gt; 3000:3000 myapp:latest
docker ps
docker logs &lt;span class="nt"&gt;--follow&lt;/span&gt; myapp
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;--interactive&lt;/span&gt; &lt;span class="nt"&gt;--tty&lt;/span&gt; myapp sh
docker stop myapp &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; docker &lt;span class="nb"&gt;rm &lt;/span&gt;myapp
docker system prune &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="nt"&gt;--force&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Multi-Stage Builds
&lt;/h2&gt;

&lt;p&gt;Separate the build environment from the runtime for smaller, more secure images.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:22-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;builder&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json package-lock.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:22-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;runner&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; NODE_ENV=production&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /app/dist ./dist&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /app/package.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci &lt;span class="nt"&gt;--production&lt;/span&gt; &lt;span class="nt"&gt;--ignore-scripts&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; node&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 3000&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "dist/server.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Docker Compose for Local Dev
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000:3000"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.:/app"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/app/node_modules"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;service_healthy&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16-alpine&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dev&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dev&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myapp&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD-SHELL"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pg_isready&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-U&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;dev"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Start with a simple Dockerfile and Docker Compose for local dev. Add multi-stage builds for production. The goal: remove environment differences as a source of bugs.&lt;/p&gt;




&lt;p&gt;Explore &lt;a href="https://tools.elunari.uk" rel="noopener noreferrer"&gt;85+ free developer tools&lt;/a&gt; or &lt;a href="https://buymeacoffee.com/moonlitcapy" rel="noopener noreferrer"&gt;support this work&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Keep Leveling Up
&lt;/h2&gt;

&lt;p&gt;If you found this useful, check out my &lt;strong&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/dev-reference-card" rel="noopener noreferrer"&gt;Dev Reference Card&lt;/a&gt;&lt;/strong&gt; - a downloadable cheat sheet with essential developer patterns, shortcuts, and references condensed into one page.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/dev-reference-card" rel="noopener noreferrer"&gt;Grab it here&lt;/a&gt; for the price of a coffee.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Browse all my tools and templates at &lt;a href="https://moonlitcapy.gumroad.com" rel="noopener noreferrer"&gt;moonlitcapy.gumroad.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>infrastructure</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Data Pipeline Design: From Messy CSV to Clean Database</title>
      <dc:creator>Moonlit Capy</dc:creator>
      <pubDate>Sat, 21 Feb 2026 08:48:50 +0000</pubDate>
      <link>https://dev.to/moonlitcapy/data-pipeline-design-from-messy-csv-to-clean-database-3283</link>
      <guid>https://dev.to/moonlitcapy/data-pipeline-design-from-messy-csv-to-clean-database-3283</guid>
      <description>&lt;p&gt;&lt;em&gt;9 min read&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Most real-world data starts messy — inconsistent CSV exports from legacy systems, spreadsheets with merged cells, date formats that vary by row. A good data pipeline transforms this chaos into clean, normalized database records.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pipeline Architecture
&lt;/h2&gt;

&lt;p&gt;The classic ETL (Extract, Transform, Load) pattern remains the foundation. Each stage has a clear boundary and failure mode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Extract     → Read raw data from source (CSV, API, FTP)
Transform   → Normalize, validate, enrich, deduplicate
Load        → Write clean records to target database
Monitor     → Log anomalies, send alerts on threshold breaches
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Handling Messy Data
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Date normalization:&lt;/strong&gt; Parse multiple formats (MM/DD/YYYY, DD-MM-YYYY, ISO 8601) into a single canonical format&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Address standardization:&lt;/strong&gt; Normalize street abbreviations (St → Street, Ave → Avenue) and validate against postal databases&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deduplication:&lt;/strong&gt; Use fuzzy matching (Levenshtein distance, Jaro-Winkler) to identify duplicate records with slight variations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type coercion:&lt;/strong&gt; Convert "yes"/"no"/"1"/"0"/"true"/"false" to consistent booleans&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  AI-Assisted Normalization
&lt;/h2&gt;

&lt;p&gt;For particularly messy data, LLMs can classify and normalize fields that rule-based systems struggle with — company name variations, free-text product descriptions, and ambiguous category labels.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;normalizeWithAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Normalize this &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; value into a standard format.\nInput: "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;rawValue&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"\nOutput (just the normalized value, nothing else):`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;maxTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Validation Layer
&lt;/h2&gt;

&lt;p&gt;Every record should pass through validation before loading. Reject invalid records into a quarantine table for manual review rather than silently dropping data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Data pipelines are unglamorous but critical. The difference between a good pipeline and a bad one shows up in data quality — and data quality directly impacts every business decision downstream.&lt;/p&gt;




&lt;p&gt;Explore &lt;a href="https://tools.elunari.uk" rel="noopener noreferrer"&gt;85+ free developer tools&lt;/a&gt; or &lt;a href="https://buymeacoffee.com/moonlitcapy" rel="noopener noreferrer"&gt;support this work&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Keep Leveling Up
&lt;/h2&gt;

&lt;p&gt;If you found this useful, check out my &lt;strong&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/dev-reference-card" rel="noopener noreferrer"&gt;Dev Reference Card&lt;/a&gt;&lt;/strong&gt; - a downloadable cheat sheet with essential developer patterns, shortcuts, and references condensed into one page.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/dev-reference-card" rel="noopener noreferrer"&gt;Grab it here&lt;/a&gt; for the price of a coffee.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Browse all my tools and templates at &lt;a href="https://moonlitcapy.gumroad.com" rel="noopener noreferrer"&gt;moonlitcapy.gumroad.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>dataengineering</category>
      <category>automation</category>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>Building a Developer Portfolio That Actually Gets You Hired</title>
      <dc:creator>Moonlit Capy</dc:creator>
      <pubDate>Sat, 21 Feb 2026 08:42:54 +0000</pubDate>
      <link>https://dev.to/moonlitcapy/building-a-developer-portfolio-that-actually-gets-you-hired-ajb</link>
      <guid>https://dev.to/moonlitcapy/building-a-developer-portfolio-that-actually-gets-you-hired-ajb</guid>
      <description>&lt;p&gt;&lt;em&gt;7 min read&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A developer portfolio isn't a resume — it's proof of work. The most effective portfolios I've seen share a common formula: strong project showcases, clean UI, fast load times, and proper SEO.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Next.js for Portfolios
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Static generation&lt;/strong&gt; — pages are pre-built at deploy time, resulting in instant loads&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in SEO&lt;/strong&gt; — metadata API, sitemap generation, robots.txt&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React ecosystem&lt;/strong&gt; — use any UI library, animation library, or component system&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free hosting&lt;/strong&gt; — Vercel deploys Next.js with zero configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Project Showcase Structure
&lt;/h2&gt;

&lt;p&gt;Each project page should answer three questions: what problem does it solve, what was the technical approach, and what was the measurable outcome.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app/
  page.tsx              # Hero + project cards
  projects/
    [slug]/
      page.tsx          # Individual project showcase
  sitemap.ts            # Auto-generated sitemap
  robots.ts             # Search engine directives
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  SEO Essentials
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Set unique &lt;code&gt;title&lt;/code&gt; and &lt;code&gt;description&lt;/code&gt; for every page&lt;/li&gt;
&lt;li&gt;Use semantic HTML: &lt;code&gt;h1&lt;/code&gt;, &lt;code&gt;h2&lt;/code&gt;, &lt;code&gt;article&lt;/code&gt;, &lt;code&gt;nav&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Generate a sitemap with &lt;code&gt;sitemap.ts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Submit your sitemap to Google Search Console and Bing Webmaster Tools&lt;/li&gt;
&lt;li&gt;Add structured data (JSON-LD) for &lt;code&gt;Person&lt;/code&gt; and &lt;code&gt;WebSite&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Performance Tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;next/image&lt;/code&gt; for automatic image optimization&lt;/li&gt;
&lt;li&gt;Minimize client-side JavaScript — most portfolio pages can be static&lt;/li&gt;
&lt;li&gt;Use system fonts or limit web fonts to one family&lt;/li&gt;
&lt;li&gt;Aim for 90+ Lighthouse score across all categories&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;A live portfolio with real projects beats a polished resume every time. Focus on shipping a clean version 1, then iterate. Start the first project today, write the first showcase this weekend.&lt;/p&gt;




&lt;p&gt;Explore &lt;a href="https://tools.elunari.uk" rel="noopener noreferrer"&gt;85+ free developer tools&lt;/a&gt; or &lt;a href="https://buymeacoffee.com/moonlitcapy" rel="noopener noreferrer"&gt;support this work&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Keep Leveling Up
&lt;/h2&gt;

&lt;p&gt;If you found this useful, check out my &lt;strong&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/dev-reference-card" rel="noopener noreferrer"&gt;Dev Reference Card&lt;/a&gt;&lt;/strong&gt; - a downloadable cheat sheet with essential developer patterns, shortcuts, and references condensed into one page.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/dev-reference-card" rel="noopener noreferrer"&gt;Grab it here&lt;/a&gt; for the price of a coffee.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Browse all my tools and templates at &lt;a href="https://moonlitcapy.gumroad.com" rel="noopener noreferrer"&gt;moonlitcapy.gumroad.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>career</category>
      <category>portfolio</category>
      <category>webdev</category>
    </item>
    <item>
      <title>API Integration Patterns for Production Systems</title>
      <dc:creator>Moonlit Capy</dc:creator>
      <pubDate>Sat, 21 Feb 2026 08:42:35 +0000</pubDate>
      <link>https://dev.to/moonlitcapy/api-integration-patterns-for-production-systems-4i37</link>
      <guid>https://dev.to/moonlitcapy/api-integration-patterns-for-production-systems-4i37</guid>
      <description>&lt;p&gt;&lt;em&gt;10 min read&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Building API integrations that work in production — not just in Postman — requires patterns for handling the real world: flaky networks, rate limits, schema changes, and partial failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retry with Exponential Backoff
&lt;/h2&gt;

&lt;p&gt;Network errors and 5xx responses are inevitable. A retry strategy with exponential backoff prevents overwhelming a recovering service while maximizing your chances of success.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchWithRetry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;maxRetries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;maxRetries&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Client error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;maxRetries&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jitter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jitter&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Circuit Breaker
&lt;/h2&gt;

&lt;p&gt;When an upstream service is down, continuing to send requests wastes resources and slows down your entire system. A circuit breaker short-circuits failed requests after a threshold.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CircuitBreaker&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;failures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;lastFailure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;closed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;threshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;resetMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastFailure&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resetMs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;half-open&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Circuit is open&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;failures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;closed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;failures&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastFailure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;failures&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Idempotency Keys
&lt;/h2&gt;

&lt;p&gt;For mutating operations (payments, order creation), an idempotency key ensures that retried requests don't duplicate side effects — the server reuses the original response.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;idempotencyKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randomUUID&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/payments&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Idempotency-Key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;idempotencyKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4999&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Rate Limiting (Client Side)
&lt;/h2&gt;

&lt;p&gt;Respect the API's rate limits before they enforce them. A token bucket algorithm gives you smooth, predictable request pacing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RateLimiter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;lastRefill&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;maxTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;refillRate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="c1"&gt;// tokens per second&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;maxTokens&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastRefill&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;acquire&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refill&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;waitMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;refillRate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;waitMs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refill&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;refill&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;elapsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastRefill&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxTokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;elapsed&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;refillRate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastRefill&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;These patterns aren't optional for production systems. Retries handle transient failures, circuit breakers prevent cascade failures, idempotency keys prevent duplicates, and rate limiting keeps you within bounds. Layer them together for integrations that survive the real world.&lt;/p&gt;




&lt;p&gt;Explore &lt;a href="https://tools.elunari.uk" rel="noopener noreferrer"&gt;85+ free developer tools&lt;/a&gt; or &lt;a href="https://buymeacoffee.com/moonlitcapy" rel="noopener noreferrer"&gt;support this work&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Keep Leveling Up
&lt;/h2&gt;

&lt;p&gt;If you found this useful, check out my &lt;strong&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/dev-reference-card" rel="noopener noreferrer"&gt;Dev Reference Card&lt;/a&gt;&lt;/strong&gt; - a downloadable cheat sheet with essential developer patterns, shortcuts, and references condensed into one page.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/dev-reference-card" rel="noopener noreferrer"&gt;Grab it here&lt;/a&gt; for the price of a coffee.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Browse all my tools and templates at &lt;a href="https://moonlitcapy.gumroad.com" rel="noopener noreferrer"&gt;moonlitcapy.gumroad.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>backend</category>
      <category>architecture</category>
      <category>api</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The Complete Git Workflow Guide for Teams in 2026</title>
      <dc:creator>Moonlit Capy</dc:creator>
      <pubDate>Sat, 21 Feb 2026 08:37:05 +0000</pubDate>
      <link>https://dev.to/moonlitcapy/the-complete-git-workflow-guide-for-teams-in-2026-4gk8</link>
      <guid>https://dev.to/moonlitcapy/the-complete-git-workflow-guide-for-teams-in-2026-4gk8</guid>
      <description>&lt;p&gt;&lt;em&gt;12 min read&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Git is the backbone of modern software development, but most teams use only a fraction of its capabilities. Here are the workflows, conventions, and strategies that consistently lead to clean histories and reliable deployments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the Right Branching Strategy
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Trunk-Based Development
&lt;/h3&gt;

&lt;p&gt;Works best for teams shipping multiple times per day. Everyone commits to main directly with short-lived feature branches lasting hours, not days.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; feat/add-search-filter
&lt;span class="c"&gt;# ... make changes ...&lt;/span&gt;
git add &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"feat: add search filter component"&lt;/span&gt;
git push origin feat/add-search-filter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  GitHub Flow
&lt;/h3&gt;

&lt;p&gt;Ideal for teams shipping daily or weekly. One main branch, feature branches for all work, pull requests for everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Merge vs Rebase
&lt;/h2&gt;

&lt;p&gt;Use &lt;strong&gt;merge&lt;/strong&gt; by default (preserves history, safer for shared branches). Use &lt;strong&gt;rebase&lt;/strong&gt; only for personal branches you haven't pushed yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Commit Message Conventions
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;feat(auth): add SSO login with Google
fix(api): handle null response from payment gateway
docs(readme): update deployment instructions
refactor(db): extract query builder into utility
chore(deps): bump next.js to 16.1.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Git Aliases That Save Hours
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[alias]&lt;/span&gt;
  &lt;span class="py"&gt;s&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;status -sb&lt;/span&gt;
  &lt;span class="py"&gt;lg&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;log --oneline --graph --decorate -20&lt;/span&gt;
  &lt;span class="py"&gt;co&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;checkout&lt;/span&gt;
  &lt;span class="py"&gt;cb&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;checkout -b&lt;/span&gt;
  &lt;span class="py"&gt;cm&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;commit -m&lt;/span&gt;
  &lt;span class="py"&gt;wip&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;!git add -A &amp;amp;&amp;amp; git commit -m "wip: work in progress"&lt;/span&gt;
  &lt;span class="py"&gt;up&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;!git fetch origin &amp;amp;&amp;amp; git rebase origin/main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;The best Git workflow is the one your entire team actually follows. Start simple with GitHub Flow and conventional commits. Add complexity only when you have a real problem.&lt;/p&gt;




&lt;p&gt;Explore &lt;a href="https://tools.elunari.uk" rel="noopener noreferrer"&gt;85+ free developer tools&lt;/a&gt; or &lt;a href="https://buymeacoffee.com/moonlitcapy" rel="noopener noreferrer"&gt;support this work&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Keep Leveling Up
&lt;/h2&gt;

&lt;p&gt;If you found this useful, check out my &lt;strong&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/dev-reference-card" rel="noopener noreferrer"&gt;Dev Reference Card&lt;/a&gt;&lt;/strong&gt; - a downloadable cheat sheet with essential developer patterns, shortcuts, and references condensed into one page.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/dev-reference-card" rel="noopener noreferrer"&gt;Grab it here&lt;/a&gt; for the price of a coffee.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Browse all my tools and templates at &lt;a href="https://moonlitcapy.gumroad.com" rel="noopener noreferrer"&gt;moonlitcapy.gumroad.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>devops</category>
      <category>workflow</category>
      <category>programming</category>
    </item>
    <item>
      <title>TypeScript Patterns Every Developer Should Know in 2026</title>
      <dc:creator>Moonlit Capy</dc:creator>
      <pubDate>Sat, 21 Feb 2026 07:23:08 +0000</pubDate>
      <link>https://dev.to/moonlitcapy/typescript-patterns-every-developer-should-know-in-2026-4oak</link>
      <guid>https://dev.to/moonlitcapy/typescript-patterns-every-developer-should-know-in-2026-4oak</guid>
      <description>&lt;p&gt;TypeScript has matured far beyond "JavaScript with types." The type system is powerful enough to encode complex business logic at compile time. Here are the patterns that make the biggest difference in production codebases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Discriminated Unions
&lt;/h2&gt;

&lt;p&gt;Model states where different variants carry different data. TypeScript narrows the type automatically based on the discriminant.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;AsyncState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;idle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;loading&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;renderState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AsyncState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;idle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Ready&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;loading&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Loading...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`Data: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`Error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the foundation of type-safe state management. Every React app with async data should use this pattern instead of separate &lt;code&gt;isLoading&lt;/code&gt;, &lt;code&gt;isError&lt;/code&gt;, &lt;code&gt;data&lt;/code&gt; booleans.&lt;/p&gt;

&lt;h2&gt;
  
  
  Branded Types
&lt;/h2&gt;

&lt;p&gt;Prevent mixing up values that are the same primitive type but represent different things.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UserId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="na"&gt;__brand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UserId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;OrderId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="na"&gt;__brand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;OrderId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createUserId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;UserId&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;UserId&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OrderId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createUserId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user_123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// getOrder(userId) // Compile error! Can't pass UserId where OrderId expected&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Zero runtime cost. The brand exists only in the type system. Use this for any ID type, currency amount, or validated string.&lt;/p&gt;

&lt;h2&gt;
  
  
  Template Literal Types
&lt;/h2&gt;

&lt;p&gt;Generate string unions from combinations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;EventName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;order&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;created&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;updated&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;deleted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
&lt;span class="c1"&gt;// Result: "user.created" | "user.updated" | "user.deleted" | "order.created" | "order.updated" | "order.deleted"&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;CSSProperty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;HexColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`#&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is powerful for event systems, CSS-in-JS, and any API where string patterns matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Result Types for Error Handling
&lt;/h2&gt;

&lt;p&gt;Stop throwing exceptions. Return typed results instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;E&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;E&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;parseConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ParseError&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ParseError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// TypeScript knows this is Config&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// TypeScript knows this is ParseError&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The caller is forced to handle both cases. No more uncaught exceptions in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exhaustive Matching
&lt;/h2&gt;

&lt;p&gt;Use the &lt;code&gt;never&lt;/code&gt; type to ensure you handle every case in a union:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;assertNever&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Unexpected value: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AsyncState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;idle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Ready&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;loading&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Loading...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Done&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Failed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;assertNever&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Compile error if a case is missing&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you add a new variant to the union, TypeScript will flag every switch statement that doesn't handle it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Start with discriminated unions and exhaustive matching — they change how you think about state management. Layer in branded types and Result types as your codebase grows. The goal: &lt;strong&gt;make illegal states unrepresentable&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;These patterns have zero runtime overhead. They exist purely in the type system, disappearing completely after compilation. That's the beauty of TypeScript done right.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Want more dev content? Check out the &lt;a href="https://blog.elunari.uk" rel="noopener noreferrer"&gt;blog&lt;/a&gt; or &lt;a href="https://buymeacoffee.com/moonlitcapy" rel="noopener noreferrer"&gt;buy me a coffee&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Keep Leveling Up
&lt;/h2&gt;

&lt;p&gt;If you found this useful, check out my &lt;strong&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/dev-reference-card" rel="noopener noreferrer"&gt;Dev Reference Card&lt;/a&gt;&lt;/strong&gt; - a downloadable cheat sheet with essential developer patterns, shortcuts, and references condensed into one page.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/dev-reference-card" rel="noopener noreferrer"&gt;Grab it here&lt;/a&gt; for the price of a coffee.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Browse all my tools and templates at &lt;a href="https://moonlitcapy.gumroad.com" rel="noopener noreferrer"&gt;moonlitcapy.gumroad.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>25 Essential Free Developer Tools You Should Be Using in 2026</title>
      <dc:creator>Moonlit Capy</dc:creator>
      <pubDate>Sat, 21 Feb 2026 07:20:52 +0000</pubDate>
      <link>https://dev.to/moonlitcapy/25-essential-free-developer-tools-you-should-be-using-in-2026-4k7o</link>
      <guid>https://dev.to/moonlitcapy/25-essential-free-developer-tools-you-should-be-using-in-2026-4k7o</guid>
      <description>&lt;p&gt;Every developer has a toolkit — a set of utilities they reach for daily. The best tools are the ones that work instantly in your browser, require no account, and just get the job done. Here are 25 free online tools that belong in every developer's bookmarks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Format Tools
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. JSON Formatter &amp;amp; Validator
&lt;/h3&gt;

&lt;p&gt;Paste malformed JSON, get it beautifully formatted with syntax highlighting and error detection. Essential for debugging API responses and config files.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. JSON to CSV Converter
&lt;/h3&gt;

&lt;p&gt;Converting API responses to spreadsheet-friendly formats is a daily task. Tools like &lt;a href="https://tools.elunari.uk/json-to-csv" rel="noopener noreferrer"&gt;DevKit's JSON to CSV converter&lt;/a&gt; make this instant.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. YAML to JSON Converter
&lt;/h3&gt;

&lt;p&gt;Docker Compose, CI configs, Kubernetes manifests — YAML is everywhere. A reliable YAML/JSON converter saves time when switching between formats.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. XML to JSON Converter
&lt;/h3&gt;

&lt;p&gt;Legacy APIs and SOAP services still use XML. Converting XML responses to JSON for modern frontends is a common need.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. CSV Viewer &amp;amp; Editor
&lt;/h3&gt;

&lt;p&gt;Preview CSV files without opening Excel. Good viewers handle large files, detect delimiters automatically, and let you sort/filter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Encoding &amp;amp; Security Tools
&lt;/h2&gt;

&lt;h3&gt;
  
  
  6. Base64 Encoder/Decoder
&lt;/h3&gt;

&lt;p&gt;Data URIs, API tokens, email attachments — Base64 encoding is everywhere. A fast encoder/decoder is essential.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. URL Encoder/Decoder
&lt;/h3&gt;

&lt;p&gt;Debugging query parameters with special characters? URL encoding issues are among the most common API bugs.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. JWT Decoder
&lt;/h3&gt;

&lt;p&gt;Decode JWT tokens to inspect headers, payloads, and expiration times without any external library.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Hash Generator (MD5/SHA)
&lt;/h3&gt;

&lt;p&gt;Generate checksums for file integrity verification, password hashing comparisons, and data deduplication.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. Password Generator
&lt;/h3&gt;

&lt;p&gt;Generate secure, random passwords with configurable length, character sets, and entropy indicators.&lt;/p&gt;

&lt;h2&gt;
  
  
  CSS &amp;amp; Design Tools
&lt;/h2&gt;

&lt;h3&gt;
  
  
  11. CSS Gradient Generator
&lt;/h3&gt;

&lt;p&gt;Visual gradient editors save hours of tweaking CSS. The best ones generate complex multi-stop gradients.&lt;/p&gt;

&lt;h3&gt;
  
  
  12. Box Shadow Generator
&lt;/h3&gt;

&lt;p&gt;Layered shadows create depth. Interactive generators let you preview and copy production-ready CSS.&lt;/p&gt;

&lt;h3&gt;
  
  
  13. Flexbox Playground
&lt;/h3&gt;

&lt;p&gt;Understanding flex properties visually is 10x faster than reading docs. Interactive playgrounds show results in real time.&lt;/p&gt;

&lt;h3&gt;
  
  
  14. CSS Grid Generator
&lt;/h3&gt;

&lt;p&gt;Grid layouts are powerful but the syntax is complex. Visual generators help you prototype layouts quickly.&lt;/p&gt;

&lt;h3&gt;
  
  
  15. Color Palette Generator
&lt;/h3&gt;

&lt;p&gt;Generate harmonious color schemes from a base color. Essential for design systems and brand consistency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Transformation Tools
&lt;/h2&gt;

&lt;h3&gt;
  
  
  16. JSON to TypeScript
&lt;/h3&gt;

&lt;p&gt;Paste a JSON response, get TypeScript interfaces. The &lt;a href="https://tools.elunari.uk/json-to-typescript" rel="noopener noreferrer"&gt;DevKit converter&lt;/a&gt; handles nested objects and arrays intelligently.&lt;/p&gt;

&lt;h3&gt;
  
  
  17. Regex Tester
&lt;/h3&gt;

&lt;p&gt;Test and debug regular expressions with real-time matching, group highlighting, and explanation of pattern components.&lt;/p&gt;

&lt;h3&gt;
  
  
  18. JavaScript/CSS Minifier
&lt;/h3&gt;

&lt;p&gt;Quick minification for one-off scripts or inline styles. Useful when build tools feel like overkill.&lt;/p&gt;

&lt;h3&gt;
  
  
  19. SQL Formatter
&lt;/h3&gt;

&lt;p&gt;Transform single-line SQL queries into readable, indented format. Makes complex joins and subqueries comprehensible.&lt;/p&gt;

&lt;h3&gt;
  
  
  20. Markdown Preview
&lt;/h3&gt;

&lt;p&gt;Write and preview Markdown in real time. Useful for README files, documentation, and blog posts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Utility Tools
&lt;/h2&gt;

&lt;h3&gt;
  
  
  21. Cron Expression Parser
&lt;/h3&gt;

&lt;p&gt;Cron syntax reads like hieroglyphics. A parser that shows the next execution times in plain English is invaluable.&lt;/p&gt;

&lt;h3&gt;
  
  
  22. Timestamp Converter
&lt;/h3&gt;

&lt;p&gt;Convert between Unix timestamps, ISO 8601, and human-readable dates. Debug time zone issues instantly.&lt;/p&gt;

&lt;h3&gt;
  
  
  23. UUID/ULID Generator
&lt;/h3&gt;

&lt;p&gt;Generate unique identifiers for database records, API keys, and session tokens.&lt;/p&gt;

&lt;h3&gt;
  
  
  24. HTTP Status Code Reference
&lt;/h3&gt;

&lt;p&gt;Quick lookup for all HTTP status codes with descriptions and common use cases. Faster than searching the RFC.&lt;/p&gt;

&lt;h3&gt;
  
  
  25. Placeholder Image Generator
&lt;/h3&gt;

&lt;p&gt;Generate placeholder images of any size for mockups and prototypes without external services.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to Find These
&lt;/h2&gt;

&lt;p&gt;All of these tools (and many more) are available for free at &lt;a href="https://tools.elunari.uk" rel="noopener noreferrer"&gt;DevKit (tools.elunari.uk)&lt;/a&gt;. No login, no tracking, no installs — just paste and go.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Found this useful? Check out &lt;a href="https://tools.elunari.uk" rel="noopener noreferrer"&gt;85+ free dev tools&lt;/a&gt; or &lt;a href="https://buymeacoffee.com/moonlitcapy" rel="noopener noreferrer"&gt;buy me a coffee&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Keep Leveling Up
&lt;/h2&gt;

&lt;p&gt;If you found this useful, check out my &lt;strong&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/dev-reference-card" rel="noopener noreferrer"&gt;Dev Reference Card&lt;/a&gt;&lt;/strong&gt; - a downloadable cheat sheet with essential developer patterns, shortcuts, and references condensed into one page.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://moonlitcapy.gumroad.com/l/dev-reference-card" rel="noopener noreferrer"&gt;Grab it here&lt;/a&gt; for the price of a coffee.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Browse all my tools and templates at &lt;a href="https://moonlitcapy.gumroad.com" rel="noopener noreferrer"&gt;moonlitcapy.gumroad.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>productivity</category>
      <category>tooling</category>
    </item>
  </channel>
</rss>
