<?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: Stephen Akugbe</title>
    <description>The latest articles on DEV Community by Stephen Akugbe (@osalumense).</description>
    <link>https://dev.to/osalumense</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%2F572665%2Feb1fbe7c-6c37-49c9-9acd-b7616ee5d200.jpg</url>
      <title>DEV Community: Stephen Akugbe</title>
      <link>https://dev.to/osalumense</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/osalumense"/>
    <language>en</language>
    <item>
      <title>Stop writing custom scrapers. We built an AI app that generates local lead lists in 30 seconds.</title>
      <dc:creator>Stephen Akugbe</dc:creator>
      <pubDate>Wed, 04 Mar 2026 21:05:02 +0000</pubDate>
      <link>https://dev.to/osalumense/stop-writing-custom-scrapers-we-built-an-ai-app-that-generates-local-lead-lists-in-30-seconds-46f9</link>
      <guid>https://dev.to/osalumense/stop-writing-custom-scrapers-we-built-an-ai-app-that-generates-local-lead-lists-in-30-seconds-46f9</guid>
      <description>&lt;p&gt;Every developer has fallen for the "quick script" trap at least once. &lt;/p&gt;

&lt;p&gt;You need a list of local businesses for a project, a client, or your own sales outreach. You think to yourself, &lt;em&gt;"I'll just write a quick script to pull this data. It'll take 20 minutes."&lt;/em&gt; Three days later, you're knee-deep in proxy rotations, fighting rate limits, getting blocked by CAPTCHAs, and trying to figure out why the website's DOM completely changed overnight. It’s soul-crushing work. &lt;/p&gt;

&lt;p&gt;A few months ago, my co-founder and I finally got completely sick of this cycle. We realized that nobody actually &lt;em&gt;wants&lt;/em&gt; to maintain scrapers or copy-paste from Google Maps until their eyes bleed. You just want the damn data so you can get to work. &lt;/p&gt;

&lt;p&gt;So, we put our heads down and built &lt;strong&gt;DensOps&lt;/strong&gt;—an AI-powered lead generation app. &lt;/p&gt;

&lt;h3&gt;
  
  
  How it actually works ⚙️
&lt;/h3&gt;

&lt;p&gt;The UX is entirely AI-driven. You literally just search in plain English, like &lt;em&gt;"4-star plumbers in Chicago,"&lt;/em&gt; and the AI figures out exactly what you need. In about 30 seconds, DensOps hands you a clean, export-ready CSV complete with validated emails, phone numbers, and social links. No proxies, no coding, no bullshit.&lt;/p&gt;

&lt;p&gt;But as developers, you know that doing that reliably at scale takes more than just a basic API wrapper. We had to build a serious engine to handle the messy data extraction in the background:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Core API (NestJS &amp;amp; TypeScript):&lt;/strong&gt; We use NestJS to handle all the standard backend operations—user routing, state management, and API endpoints. The strict typing of TypeScript keeps our core logic solid and maintainable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Enrichment Engine (Python &amp;amp; FastAPI):&lt;/strong&gt; For the heavy lifting—the actual data extraction, standardization, and AI enrichment—we spun up a dedicated microservice using Python and FastAPI. Python’s data ecosystem is unmatched for this kind of work, and FastAPI ensures the service stays lightning-fast and highly concurrent.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s been a massive challenge getting these two services to communicate seamlessly while keeping latency low. But we finally nailed it. &lt;/p&gt;

&lt;h3&gt;
  
  
  The Ask: We just launched on Product Hunt yesterday 🚀
&lt;/h3&gt;

&lt;p&gt;I’ll be honest—it’s terrifying putting something you’ve poured your soul into out into the public. You always wonder if people will actually care. But we’re incredibly proud of what we’ve built, and we really believe this will save devs and sales teams hundreds of hours. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Want to test it out?&lt;/strong&gt; We set it up so that new sign-ups get one free search. Go run your hardest query, see how fast the backend actually processes it, and look at the data quality yourself. You can try it out at &lt;a href="https://densops.com" rel="noopener noreferrer"&gt;DensOps.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you like what we've built:&lt;/strong&gt;&lt;br&gt;
It would mean the absolute world to us if you checked out our launch today on Product Hunt. Drop a comment, tell us what we got right, tell us what sucks about the UX, and if you think it's a great tool, your support and upvotes would mean everything to us right now. &lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://www.producthunt.com/products/densops?utm_source=other&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;Support DensOps on Product Hunt here&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let me know what you think of the app in the comments! I'm open to answering any questions you have about the tool or the stack.&lt;/p&gt;

&lt;p&gt;Thanks for reading, and back to the monitors.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>typescript</category>
      <category>startup</category>
      <category>webdev</category>
    </item>
    <item>
      <title>My 2025 as a Software Engineer: Building Less, Understanding More</title>
      <dc:creator>Stephen Akugbe</dc:creator>
      <pubDate>Wed, 31 Dec 2025 20:13:50 +0000</pubDate>
      <link>https://dev.to/osalumense/my-2025-as-a-software-engineer-building-less-understanding-more-1pli</link>
      <guid>https://dev.to/osalumense/my-2025-as-a-software-engineer-building-less-understanding-more-1pli</guid>
      <description>&lt;p&gt;2025 was not a loud year for me.&lt;br&gt;
It was a builder year and a thinking year.&lt;/p&gt;

&lt;p&gt;I spent most of the year working across both backend and frontend systems. On the backend, I worked with Node, TypeScript, PHP, Laravel, Express, NestJS, PostgreSQL, MySQL, MongoDB, AWS, GCP and Docker. On the frontend, I worked with React, Next.js, Vue, and modern TypeScript workflows. These were real production systems with real constraints and tradeoffs.&lt;/p&gt;

&lt;p&gt;But this year was not just about building. It was about understanding.&lt;br&gt;
I slowed down and started thinking more deeply about architecture, scale, abstractions, and long term impact. I became more intentional about decisions and less interested in clever solutions that only worked in the short term. &lt;br&gt;
&lt;em&gt;Clarity started to matter more than speed.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Alongside my technical growth, I spent the year learning French and living within a new culture. Learning a new language forces you to listen more than you speak. It changes how you process ideas and express intent. I realized how closely this mirrors software engineering. You cannot express a good solution until you truly understand the problem.&lt;/p&gt;

&lt;p&gt;Because of this shift, I cared less about shipping fast and more about meaning. &lt;br&gt;
I asked better questions. What problem does this system actually solve. How will this decision age. What happens when this codebase grows.&lt;/p&gt;

&lt;p&gt;I worked across different domains including elearning platforms, gaming APIs, and AI products. Each domain reinforced the same lesson. Depth beats speed. &lt;br&gt;
&lt;em&gt;Systems tend to fail long before code does.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I also explored AI thoughtfully. I looked into RAG (Retrieval Augmented Generation), LLM powered tools, and practical SaaS ideas. Instead of chasing hype, I focused on what could be built lean and sustainably.&lt;/p&gt;

&lt;p&gt;On the product side, I planned and built real things. I co founded a product and currently close to finishing the MVP. I planned and built a social media post generation tool using NestJS and PostgreSQL with a Nextjs frontend.&lt;/p&gt;

&lt;p&gt;Giving back remained important to me, I’m mentoring someone to become a great backend dev, I published an npm package, worked on open source repositories, and wrote developer articles. My goal was to document real fixes and real lessons, not recycled advice.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;2025 taught me that growth can be quiet.&lt;/em&gt;&lt;br&gt;
It comes from thinking deeply, learning continuously, and building with intent.&lt;/p&gt;

&lt;p&gt;Going into 2026, my focus is clear. Fewer projects, deeper execution, and visible impact.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>2025wrapped</category>
    </item>
    <item>
      <title>Why NestJS Hot Reload Does Not Work in Docker and How to Fix It Properly</title>
      <dc:creator>Stephen Akugbe</dc:creator>
      <pubDate>Mon, 22 Dec 2025 21:51:00 +0000</pubDate>
      <link>https://dev.to/osalumense/why-nestjs-hot-reload-does-not-work-in-docker-and-how-to-fix-it-properly-4de4</link>
      <guid>https://dev.to/osalumense/why-nestjs-hot-reload-does-not-work-in-docker-and-how-to-fix-it-properly-4de4</guid>
      <description>&lt;p&gt;If you are running NestJS inside Docker and your code changes are not reflecting, you are not alone. This is one of the most common pain points developers hit when combining NestJS, Docker, and macOS or Windows.&lt;/p&gt;

&lt;p&gt;You save a file.&lt;br&gt;
Nothing happens.&lt;br&gt;
You rebuild the container.&lt;br&gt;
Still confused.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Sidenote: I have actually fixed this exact problem before on another project. But when I hit it again on a new NestJS setup, I realized I could not remember all the details. That was the moment I decided to document it properly this time.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;At some point, you install webpack because someone on the internet said it fixes the issue.&lt;/p&gt;

&lt;p&gt;This article explains what is really going on, why Docker behaves this way, when webpack is actually needed, and what the correct setup looks like for NestJS development.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core misunderstanding
&lt;/h2&gt;

&lt;p&gt;Docker does not watch your files.&lt;/p&gt;

&lt;p&gt;Docker only sees what exists inside the container. Whether changes reflect or not depends entirely on how files get into the container and how NestJS is running.&lt;/p&gt;

&lt;p&gt;There are two very different worlds that often get mixed up.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Development mode&lt;/li&gt;
&lt;li&gt;Production mode&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you confuse the two, hot reload will never work.&lt;/p&gt;

&lt;h2&gt;
  
  
  How NestJS hot reload works without Docker
&lt;/h2&gt;

&lt;p&gt;When you run NestJS locally using&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm run start:dev&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The Nest CLI uses a file watcher. When a file changes, the process restarts automatically.&lt;/p&gt;

&lt;p&gt;No Webpack is involved here.&lt;br&gt;
No HMR.&lt;br&gt;
Just process a restart.&lt;/p&gt;

&lt;p&gt;This works because your filesystem events are available directly to Node.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changes when you introduce Docker
&lt;/h2&gt;

&lt;p&gt;Once NestJS runs inside a container, file watching depends on three things.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How files get into the container&lt;/li&gt;
&lt;li&gt;How NestJS is started&lt;/li&gt;
&lt;li&gt;Whether filesystem events propagate correctly&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If any of these is wrong, hot reload breaks.&lt;/p&gt;

&lt;h2&gt;
  
  
  The only setup that works reliably for development
&lt;/h2&gt;

&lt;p&gt;For NestJS changes to reflect instantly inside Docker, all of the following must be true.&lt;/p&gt;

&lt;p&gt;Your source code is mounted into the container using volumes&lt;br&gt;
NestJS runs in watch mode using start dev&lt;br&gt;
File watching works inside Docker&lt;/p&gt;

&lt;p&gt;If even one is missing, you will be rebuilding images unnecessarily.&lt;/p&gt;

&lt;p&gt;Volumes are non-negotiable in development&lt;/p&gt;

&lt;p&gt;If your Dockerfile copies files like this&lt;/p&gt;

&lt;p&gt;&lt;code&gt;COPY . .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then your container has a snapshot of your code. Docker has no idea when you edit files locally.&lt;/p&gt;

&lt;p&gt;That setup is correct for production but wrong for development.&lt;/p&gt;

&lt;p&gt;In development, your compose file must mount the project into the container.&lt;/p&gt;

&lt;p&gt;Example conceptually:&lt;/p&gt;

&lt;p&gt;Local files&lt;br&gt;
Shared into the container&lt;br&gt;
Changes appear instantly&lt;/p&gt;

&lt;p&gt;This is exactly what your compose file already does.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.:/usr/src/app&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That line is the backbone of hot reload.&lt;/p&gt;

&lt;p&gt;Why node_modules must be excluded&lt;/p&gt;

&lt;p&gt;This line is subtle but important.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/usr/src/app/node_modules&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It prevents your local node_modules from overwriting the container dependencies. Without it, you get native module issues and random crashes.&lt;/p&gt;

&lt;p&gt;This is a best practice, and you got it right.&lt;/p&gt;

&lt;p&gt;start dev is not optional&lt;/p&gt;

&lt;p&gt;NestJS will only watch files if you explicitly run it in watch mode.&lt;/p&gt;

&lt;p&gt;This means your command must be&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm run start:dev&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and not&lt;/p&gt;

&lt;p&gt;&lt;code&gt;node dist/main.js&lt;/code&gt;&lt;br&gt;
or&lt;br&gt;
&lt;code&gt;nest start&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The moment you run compiled JavaScript, hot reload is gone. That is expected behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  The macOS and Windows file watching problem
&lt;/h2&gt;

&lt;p&gt;Even with volumes and start dev, many developers still see no reload.&lt;/p&gt;

&lt;p&gt;This is not a NestJS bug.&lt;/p&gt;

&lt;p&gt;On macOS and Windows, Docker Desktop runs Linux containers inside a virtual machine. Native filesystem events often do not propagate correctly into the container.&lt;/p&gt;

&lt;p&gt;That is why NestJS does not detect changes.&lt;/p&gt;

&lt;p&gt;The fix is polling.&lt;/p&gt;

&lt;p&gt;These environment variables force Node-based watchers to actively check for changes instead of relying on filesystem events.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CHOKIDAR_USEPOLLING=true&lt;br&gt;
WATCHPACK_POLLING=true&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is not a hack. It is a known workaround and widely used.&lt;/p&gt;

&lt;p&gt;Once enabled, NestJS reliably restarts when files change.&lt;/p&gt;

&lt;h2&gt;
  
  
  The webpack confusion explained
&lt;/h2&gt;

&lt;p&gt;This is where most people go wrong.&lt;/p&gt;

&lt;p&gt;NestJS supports two different reload strategies.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Process restart using the Nest CLI watcher&lt;/li&gt;
&lt;li&gt;Hot Module Replacement using webpack&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Webpack is only required for HMR.&lt;/p&gt;

&lt;p&gt;If you never enabled HMR, you don't need Webpack at all.&lt;/p&gt;

&lt;p&gt;So why do people install it?&lt;/p&gt;

&lt;p&gt;Because they accidentally enable HMR.&lt;/p&gt;

&lt;p&gt;If you see any of these, Webpack becomes mandatory.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;module.hot&lt;/code&gt; in main.ts&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;webpack: true&lt;/code&gt; in nest cli config&lt;/li&gt;
&lt;li&gt;Custom HMR setup&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At that point, NestJS expects Webpack and Webpack CLI to exist.&lt;/p&gt;

&lt;p&gt;Many developers install Webpack, thinking it fixes Docker reload issues, when in reality, polling was the missing piece.&lt;/p&gt;

&lt;p&gt;When webpack actually makes sense&lt;/p&gt;

&lt;p&gt;Webpack HMR can be useful if:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your application startup time is slow&lt;/li&gt;
&lt;li&gt;You want instant reload without restarting the process&lt;/li&gt;
&lt;li&gt;You know you enabled HMR intentionally&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But it adds complexity and is not required for most backend APIs.&lt;/p&gt;

&lt;p&gt;For many projects, a simple restart on change is stable and good enough.&lt;/p&gt;

&lt;p&gt;Development versus production mental model&lt;/p&gt;

&lt;p&gt;This simple rule will save you hours.&lt;/p&gt;

&lt;p&gt;In development:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use volumes&lt;/li&gt;
&lt;li&gt;Run start dev&lt;/li&gt;
&lt;li&gt;Enable polling&lt;/li&gt;
&lt;li&gt;Never rebuild&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In production:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do not use volumes&lt;/li&gt;
&lt;li&gt;Copy files during build&lt;/li&gt;
&lt;li&gt;Run compiled JavaScript&lt;/li&gt;
&lt;li&gt;Rebuild on every change&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you mix these two worlds, things break.&lt;/p&gt;

&lt;p&gt;Final thoughts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker is not broken.&lt;/li&gt;
&lt;li&gt;NestJS is not broken.&lt;/li&gt;
&lt;li&gt;Hot reload is not magic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you understand how files enter the container and how NestJS watches them, everything becomes predictable.&lt;/p&gt;

&lt;p&gt;If you ever find yourself rebuilding Docker images just to see a console log update, something in your setup is wrong.&lt;/p&gt;

&lt;p&gt;And if you installed Webpack just to make file watching work, you probably did not need it.&lt;/p&gt;

&lt;p&gt;If this article saved you time, chances are it will save someone else hours of frustration too.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>nestjs</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Why You Should Care About Pre-Commit Hooks (and How Husky Makes It Easier)</title>
      <dc:creator>Stephen Akugbe</dc:creator>
      <pubDate>Sat, 01 Nov 2025 08:52:36 +0000</pubDate>
      <link>https://dev.to/osalumense/why-you-should-care-about-pre-commit-hooks-and-how-husky-makes-it-easier-4im4</link>
      <guid>https://dev.to/osalumense/why-you-should-care-about-pre-commit-hooks-and-how-husky-makes-it-easier-4im4</guid>
      <description>&lt;p&gt;I thought about writing this because pre-commit checks are one of the most overlooked parts of the development process. Many developers push code straight to GitHub or GitLab without realizing that a simple setup could save them countless hours of debugging and keep their projects clean and consistent.  &lt;/p&gt;

&lt;p&gt;So, let’s talk about pre-commit hooks and how Husky helps make them easy to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are Pre-Commit Hooks?
&lt;/h2&gt;

&lt;p&gt;Pre-commit hooks are scripts that run automatically &lt;strong&gt;before a Git commit&lt;/strong&gt; is finalized.&lt;br&gt;&lt;br&gt;
They allow you to run checks or commands that ensure your code meets certain standards before it’s saved into the repository.&lt;/p&gt;

&lt;p&gt;Think of them as automated gatekeepers for your commits.&lt;/p&gt;

&lt;p&gt;For example, a pre-commit hook can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run your tests and stop the commit if something fails
&lt;/li&gt;
&lt;li&gt;Lint and format your code automatically
&lt;/li&gt;
&lt;li&gt;Enforce commit message standards
&lt;/li&gt;
&lt;li&gt;Prevent large or sensitive files from being committed
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main goal is simple: &lt;strong&gt;catch issues early and maintain consistency across your team&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Problem With Manual Git Hooks
&lt;/h2&gt;

&lt;p&gt;Git actually supports hooks natively. You can find them in the &lt;code&gt;.git/hooks&lt;/code&gt; folder of any repository.&lt;br&gt;&lt;br&gt;
However, these hooks aren’t shared when you clone or pull a repo because they’re stored locally.&lt;br&gt;&lt;br&gt;
That means every developer has to set them up manually — and that’s both inconvenient and error-prone.&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;Husky&lt;/strong&gt; comes in.&lt;/p&gt;
&lt;h2&gt;
  
  
  Enter Husky
&lt;/h2&gt;

&lt;p&gt;Husky is a tool that makes it easy to manage and share Git hooks within your project.&lt;br&gt;&lt;br&gt;
Instead of manually editing &lt;code&gt;.git/hooks&lt;/code&gt;, Husky lets you configure hooks right inside your repository so everyone benefits automatically.  &lt;/p&gt;

&lt;p&gt;With Husky, you can automate tasks like linting, formatting, or running tests before every commit or push — all version-controlled and consistent for every developer.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting Up Husky
&lt;/h2&gt;

&lt;p&gt;Here’s how you can set it up quickly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Step 1: Install Husky
npm install husky --save-dev

# Step 2: Enable Git hooks
npx husky install

# Step 3: Add a pre-commit hook
npx husky add .husky/pre-commit "npm test"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, every time you commit, your tests will run automatically.&lt;br&gt;
If they fail, the commit won’t go through, protecting your main branch from broken code.&lt;/p&gt;

&lt;p&gt;You can also use tools like ESLint, Prettier, or lint-staged to format and lint your code before commits.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;code&gt;npx husky add .husky/pre-commit "npx lint-staged"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And in your package.json:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "lint-staged": {
    "*.{js,ts,jsx,tsx}": ["eslint --fix", "prettier --write"]
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures only the staged files are linted and formatted, making the process faster.&lt;br&gt;
Other Pre-Commit Tools You Should Know&lt;/p&gt;

&lt;p&gt;Different languages and ecosystems have their own pre-commit tools. Here are a few popular ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JavaScript/TypeScript: Husky, Lefthook, Yorkie&lt;/li&gt;
&lt;li&gt;Python: pre-commit&lt;/li&gt;
&lt;li&gt;Ruby: Overcommit&lt;/li&gt;
&lt;li&gt;Go: pre-commit-go&lt;/li&gt;
&lt;li&gt;Java: Spotless&lt;/li&gt;
&lt;li&gt;C#/.NET: GitHooks.NET&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No matter what stack you’re working with, the idea remains the same: &lt;strong&gt;ensure quality before the code lands in your repo.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why I Think This Matters
&lt;/h3&gt;

&lt;p&gt;Developers often focus on writing features and fixing bugs, but forget to automate the boring parts that ensure quality.&lt;br&gt;
Pre-commit hooks are one of those simple setups that can dramatically improve your workflow and team collaboration.&lt;/p&gt;

&lt;p&gt;Husky, in particular, makes it effortless for JavaScript and TypeScript projects to keep their codebase clean, consistent, and ready for production, every single commit.&lt;/p&gt;

&lt;p&gt;So if you’ve never used pre-commit hooks before, now’s a good time to start.&lt;/p&gt;

</description>
      <category>tooling</category>
      <category>git</category>
      <category>automation</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Never Miss a Cloud Run Error: A Guide to Comprehensive GCP Alerting</title>
      <dc:creator>Stephen Akugbe</dc:creator>
      <pubDate>Mon, 25 Aug 2025 17:13:06 +0000</pubDate>
      <link>https://dev.to/osalumense/never-miss-a-cloud-run-error-a-guide-to-comprehensive-gcp-alerting-1f2n</link>
      <guid>https://dev.to/osalumense/never-miss-a-cloud-run-error-a-guide-to-comprehensive-gcp-alerting-1f2n</guid>
      <description>&lt;p&gt;Deploying an application to Google Cloud Run is an exhilarating experience. The serverless magic, the automatic scaling, the elegant containerization—it all works seamlessly. But what happens when things go wrong? When your NestJS API throws an unhandled exception, or your Next.js app starts returning 5xx errors?&lt;/p&gt;

&lt;p&gt;Without a proper alerting system, you're flying blind. You'll most likely not be aware of the problem until a user reports it. In this post, We’ll walk through the definitive guide to setting up a comprehensive, &lt;em&gt;"catch-all"&lt;/em&gt; alerting system for all your Cloud Run applications using Google's built-in tools: Cloud Logging and Cloud Monitoring.&lt;/p&gt;

&lt;p&gt;We'll cover the right way to query logs, how to create a single, unified metric for all errors, and how to configure an email alert that notifies you the second a problem occurs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: The Core Principle: From Logs to Alerts
&lt;/h2&gt;

&lt;p&gt;The foundation of our strategy is that both of your applications (NestJS and Next.js) automatically write all their standard output and errors to Cloud Logging. Anything written to &lt;code&gt;stderr&lt;/code&gt; is automatically given a &lt;code&gt;severity: ERROR&lt;/code&gt; label. We'll leverage this to build our alerting system.&lt;/p&gt;

&lt;p&gt;Our goal is to create a single &lt;strong&gt;Logs-based Metric&lt;/strong&gt; that acts as a central counter for every error from every Cloud Run service in your project. Once we have that metric, we can set an alert policy that triggers on the very first error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Creating a Unified Logs-Based Metric
&lt;/h2&gt;

&lt;p&gt;Instead of creating separate alerts for each service, we'll create one metric to rule them all.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Navigate to Logs-based Metrics: In the Google Cloud Console, find and navigate to Cloud Monitoring and select Logs-based Metrics from the left-hand menu.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a New Metric: Click the "Create Metric" button at the top of the page.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure the Metric:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Metric Type: Select Counter. This will count the number of matching log entries.&lt;/li&gt;
&lt;li&gt;Name: Give it a clear name like &lt;code&gt;cloud-run-errors&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Description: Add a helpful description: "A counter for all log entries with a severity of ERROR or higher from all Cloud Run services."&lt;/li&gt;
&lt;li&gt;Log Filter: This is the most crucial part. Paste this query into the "Build filter" box. This query finds all logs with an ERROR severity from any Cloud Run revision in your project.
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource.type="cloud_run_revision" AND severity&amp;gt;=ERROR
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finalize: Click "Create Metric". The metric is now created but won't be visible in the alerting policy selector until it receives its first data point.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 3: Setting Up a "Zero-Tolerance" Alerting Policy
&lt;/h2&gt;

&lt;p&gt;Now we'll create the policy that sends you a notification as soon as a new error is logged.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create an Alerting Policy: Go to Cloud Monitoring &amp;gt; Alerting &amp;gt; Create Policy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select Your Metric: In the "Select a metric" dialog, search for the name of the metric you just created: cloud-run-all-errors.&lt;br&gt;
&lt;em&gt;Note: If it doesn't appear, you need to wait for a new error to&lt;br&gt;
be logged in your service. The metric won't be searchable until &lt;br&gt;
it has received its first data point.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure the Trigger:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Condition: Any time series violates a value threshold&lt;/li&gt;
&lt;li&gt;Threshold: Is above&lt;/li&gt;
&lt;li&gt;Value: 0&lt;/li&gt;
&lt;li&gt;For: 1 minute (This ensures you get an alert as soon as the first error occurs, and the metric count goes above zero).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add Your Notification Channel: If you haven't already, you need to create a notification channel (e.g., your email address) in Alerting &amp;gt; Edit notification channels.&lt;br&gt;
Select your email channel to receive notifications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finalize the Alert: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Give the policy a descriptive name, like "Cloud Run: First Error Detected."&lt;/li&gt;
&lt;li&gt;In the Documentation section, add a helpful message. This is essential, as it will be included in the email. It should tell you where to go to find the error. A perfect addition is a link to the Logs Explorer with a pre-filled query:&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Troubleshoot this issue by checking the logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://console.cloud.google.com/logs/query;query=resource.type%3D"cloud_run_revision"%20AND%20severity%3E%3DERROR;timeRange=1h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, click "Create Policy" and you're all set!&lt;/p&gt;

&lt;p&gt;By following these steps, you've established a robust, centralized alerting system for your Cloud Run environment. You've moved beyond reactive troubleshooting and can now proactively respond to issues the moment they happen. This "set it and forget it" approach not only gives you peace of mind but is a critical step in building reliable and scalable cloud-native applications.&lt;/p&gt;

</description>
      <category>googlecloud</category>
      <category>devops</category>
      <category>monitoring</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Efficiently Migrating Data Between PostgreSQL Databases: A Practical Guide</title>
      <dc:creator>Stephen Akugbe</dc:creator>
      <pubDate>Sun, 17 Aug 2025 22:01:52 +0000</pubDate>
      <link>https://dev.to/osalumense/efficiently-migrating-data-between-postgresql-databases-a-practical-guide-1np5</link>
      <guid>https://dev.to/osalumense/efficiently-migrating-data-between-postgresql-databases-a-practical-guide-1np5</guid>
      <description>&lt;p&gt;Migrating or syncing data between PostgreSQL databases is a common task for developers. Whether consolidating user data, archiving old records, or migrating production data to a reporting database, having a reliable and simple method can save hours of headaches.&lt;/p&gt;

&lt;p&gt;PostgreSQL’s &lt;code&gt;dblink&lt;/code&gt; extension makes this process straightforward, allowing you to query one database from another as if the two were connected tables.&lt;/p&gt;

&lt;p&gt;Before using &lt;code&gt;dblink&lt;/code&gt;, you need to make sure the extension is created in your target database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE EXTENSION IF NOT EXISTS dblink;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This only needs to be done once per database. After that, you can safely use &lt;code&gt;dblink&lt;/code&gt; to query other PostgreSQL databases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example Scenario
&lt;/h2&gt;

&lt;p&gt;Imagine you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Source database: &lt;code&gt;user_data_archive&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Target database: &lt;code&gt;user_data_main&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Target table: &lt;code&gt;users&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;users&lt;/code&gt; table has unique constraints on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;username&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;email&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is to copy users from the archive to the main database without violating these constraints.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;dblink&lt;/code&gt; to Move Data&lt;/p&gt;

&lt;p&gt;Here’s a simple example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSERT INTO users (username, email, created_at, updated_at)
SELECT DISTINCT
    username,
    lower(email) AS email,
    NOW() AS created_at,
    NOW() AS updated_at
FROM dblink(
    'dbname=user_data_archive user=app_user password=securepass',
    'SELECT username, email FROM archived_users'
) AS t(username text, email text)
ON CONFLICT DO NOTHING;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How This Works:
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;dblink&lt;/code&gt; allows the target database (&lt;code&gt;user_data_main&lt;/code&gt;) to query the source (&lt;code&gt;user_data_archive&lt;/code&gt;) directly.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DISTINCT&lt;/code&gt; removes duplicate rows from the incoming data.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ON CONFLICT DO NOTHING&lt;/code&gt; ensures that unique constraints on the target table (like unique usernames or emails) do not cause the query to fail.&lt;/p&gt;

&lt;p&gt;This keeps the insert process safe while letting you move large amounts of data efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use This Approach?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Simple setup: No need to dump and restore SQL files manually.&lt;/li&gt;
&lt;li&gt;Flexible: You can filter, transform, or normalize data as part of the select.&lt;/li&gt;
&lt;li&gt;Reliable: Works even when the source and target databases live on the same server or different servers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Practical Use Cases:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Migrating &lt;code&gt;users&lt;/code&gt;, &lt;code&gt;products&lt;/code&gt;, or content from a legacy database to a new system.&lt;/li&gt;
&lt;li&gt;Populating a reporting or analytics database from production tables.&lt;/li&gt;
&lt;li&gt;Syncing staging and production data safely during testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;dblink&lt;/code&gt; is a powerful tool for querying one PostgreSQL database from another.&lt;/p&gt;

&lt;p&gt;Combining &lt;code&gt;DISTINCT&lt;/code&gt; and &lt;code&gt;ON CONFLICT DO NOTHING&lt;/code&gt; allows you to safely insert data without worrying about violating unique constraints.&lt;/p&gt;

&lt;p&gt;This approach keeps your workflow clean, efficient, and maintainable, especially for large tables or ongoing migrations.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>database</category>
    </item>
    <item>
      <title>Fixing Global npm Install Permissions on macOS</title>
      <dc:creator>Stephen Akugbe</dc:creator>
      <pubDate>Sat, 05 Jul 2025 04:38:49 +0000</pubDate>
      <link>https://dev.to/osalumense/fixing-global-npm-install-permissions-on-macos-21ll</link>
      <guid>https://dev.to/osalumense/fixing-global-npm-install-permissions-on-macos-21ll</guid>
      <description>&lt;p&gt;&lt;em&gt;&amp;gt; PS: This is also a note to myself in case I need it again in future&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I recently switched to macOS and tried installing some global npm packages like &lt;code&gt;pnpm&lt;/code&gt; using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g pnpm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But I got a permissions error saying it couldn't create a folder in &lt;code&gt;/usr/local/lib/...&lt;/code&gt;. This happens because macOS doesn't allow normal users to write to that system directory by default.&lt;/p&gt;

&lt;p&gt;Here’s how I fixed it:&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create a folder to store global npm packages
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; ~/.npm-global
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why&lt;/strong&gt;: This creates a new directory in your home folder where you’ll install global npm packages safely, without needing admin rights.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Tell npm to use that folder
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm config &lt;span class="nb"&gt;set &lt;/span&gt;prefix &lt;span class="s1"&gt;'~/.npm-global'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why&lt;/strong&gt;: This changes npm’s settings so it knows to install global packages into the new folder you just created instead of the system one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Add that folder to your system PATH
&lt;/h3&gt;

&lt;p&gt;Open your terminal and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add this line at the bottom of the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.npm-global/bin:&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why&lt;/strong&gt;: This tells your system where to find the npm packages you install globally, so you can run them like any other command (e.g., &lt;code&gt;pnpm&lt;/code&gt; or &lt;code&gt;eslint&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Apply the changes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why&lt;/strong&gt;: This reloads your terminal settings so the PATH change takes effect immediately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Install the global package again
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; pnpm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why&lt;/strong&gt;: Now that everything is set up, this should install without any permission error.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Verify it works
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why&lt;/strong&gt;: This checks if &lt;code&gt;pnpm&lt;/code&gt; was installed correctly and is available to run.&lt;/p&gt;

&lt;p&gt;What If You Installed pnpm But It Still Says "command not found"?&lt;br&gt;
After installing pnpm, I ran this in my project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pnpm install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the terminal said:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;zsh: command not found: pnpm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means macOS can’t find the pnpm command yet. Here’s how I fixed it:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step A: Check where pnpm was installed&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm config get prefix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it shows something like /Users//.npm-global, then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ls ~/.npm-global/bin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If pnpm is listed, we just need to make sure the terminal can see it.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step B: Add it to your PATH (if not already done)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Open your terminal config again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nano ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure this line exists at the bottom:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export PATH="$HOME/.npm-global/bin:$PATH"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then save and close the file.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step C: Reload your terminal settings&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now try:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pnpm -v
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it works, then run pnpm install in your project folder again. Everything should now work smoothly.&lt;/p&gt;

</description>
      <category>npm</category>
      <category>programming</category>
    </item>
    <item>
      <title>Introducing Postimy: Your Personal Content Assistant for Social Media</title>
      <dc:creator>Stephen Akugbe</dc:creator>
      <pubDate>Tue, 10 Jun 2025 21:05:09 +0000</pubDate>
      <link>https://dev.to/osalumense/introducing-postimy-your-personal-content-assistant-for-social-media-ko0</link>
      <guid>https://dev.to/osalumense/introducing-postimy-your-personal-content-assistant-for-social-media-ko0</guid>
      <description>&lt;p&gt;Hello, I’m excited to finally share what I’ve been working on: &lt;strong&gt;Postimy&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Postimy is your virtual assistant for all things social media. It helps you generate posts that actually sound like you, learning your tone, voice, and style over time. Whether you're trying to stay consistent on LinkedIn or Twitter, schedule posts across platforms, or brainstorm content ideas, &lt;strong&gt;Postimy&lt;/strong&gt; is here to make it easier.&lt;/p&gt;

&lt;p&gt;You can join the waitlist &lt;a href="https://postimy.com" rel="noopener noreferrer"&gt;here&lt;/a&gt; if you want to try it early.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Started &lt;strong&gt;Postimy&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I’ve always struggled with the consistency part of social media. I have ideas, I know what I want to say, but actually sitting down to write content every few days? That was always the problem.&lt;/p&gt;

&lt;p&gt;Then it hit me! What if I could automate the content creation process but still make it feel authentic?&lt;/p&gt;

&lt;p&gt;There are already tons of AI writing tools out there, but most of them generate stuff that feels... generic... They don't sound like you. They don't evolve with you. And most importantly, they don't help you build a personal brand in a meaningful way.&lt;/p&gt;

&lt;p&gt;That’s what I’m aiming for with &lt;strong&gt;Postimy&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Is It For?
&lt;/h2&gt;

&lt;p&gt;Postimy is built for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Founders &amp;amp; indie hackers trying to build in public&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Creatives and professionals growing their audience&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Freelancers wanting to showcase expertise&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Anyone who’s tired of figuring out what to post&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Whether you're building a product, a personal brand, or just want to stay relevant on social, &lt;em&gt;&lt;strong&gt;Postimy&lt;/strong&gt; helps you write consistently, without sounding robotic or generic.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Started Using It (And What Happened)
&lt;/h2&gt;

&lt;p&gt;Before turning this into a web app, I started with a simple CLI tool that used OpenAI to generate LinkedIn posts based on my background and industry. I’d just run a command, and out came a few post options tailored to my style.&lt;/p&gt;

&lt;p&gt;To my surprise, they weren’t just “good enough”, they were actually getting me results. I started seeing more engagement, more connections, and even more DMs from potential recruiters, founders and some others peeking at my profile (thanks to LinkedIn's profile viewers section).&lt;/p&gt;

&lt;p&gt;That’s when I knew I was onto something.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works (Right Now)
&lt;/h2&gt;

&lt;p&gt;Currently, Postimy has:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A Next.js frontend (for user interface, onboarding, dashboard)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An Express.js server (handling post generation, user data, auth)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Uses OpenAI’s API to generate posts based on user background and goals&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Simple scheduling logic and a content calendar to help users stay consistent&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The idea is to start lean but scalable enough to get value from day one, while setting the stage for personalization and smarter content generation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s Next: Learning You
&lt;/h2&gt;

&lt;p&gt;Here’s where it gets fun. I want Postimy to become more than a content generator... I want it to learn how you think.&lt;/p&gt;

&lt;p&gt;Here’s a breakdown of what I’m working on:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Voice + Style Adaptation: As you generate more posts, &lt;strong&gt;Postimy&lt;/strong&gt; starts recognizing your tone, sentence structure, emoji usage, word choices, even preferred themes, and uses that to make future posts sound more like you.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Smart Onboarding: You’ll be able to set tone preferences (casual, formal), emoji habits, platform focus, and more (still not so sure about other preferences) so Postimy gets your voice right from day one.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Content Memory (RAG): I’m planning to store generated posts as embeddings in a vector database (e.g., pgvector or Pinecone). When generating new content, the system retrieves similar past posts to make each one context-aware.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Custom ML Pipeline: Eventually, I’ll be spinning up a Python Docker microservice to handle more advanced ML tasks, like Hugging Face-based embedding, tone scoring, and maybe even fine-tuning on user data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;LangChain (Possibly, still unsure): For better chaining of user context → memory retrieval → structured prompt → post generation, I’m exploring LangChain as an orchestration tool — or building a custom version of it if needed.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of this is to ensure &lt;strong&gt;Postimy&lt;/strong&gt; grows with you, becoming more accurate, more personal, and more useful over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want to Try It?
&lt;/h2&gt;

&lt;p&gt;If you’re tired of staring at a blank text box trying to figure out what to say online, Postimy can help.&lt;/p&gt;

&lt;p&gt;Join the &lt;a href="https://postimy.com" rel="noopener noreferrer"&gt;waitlist&lt;/a&gt; to be part of the early access group.&lt;/p&gt;

&lt;p&gt;Thanks for reading. If you’ve ever tried building your dev tools to solve your own problem, I’d love to hear your story.&lt;/p&gt;

&lt;p&gt;Let’s build better tools for ourselves.&lt;/p&gt;

</description>
      <category>saas</category>
      <category>buildinpublic</category>
      <category>news</category>
      <category>ai</category>
    </item>
    <item>
      <title>Mental RAM: Why You're Tired But Haven't Done Much</title>
      <dc:creator>Stephen Akugbe</dc:creator>
      <pubDate>Fri, 30 May 2025 18:19:19 +0000</pubDate>
      <link>https://dev.to/osalumense/mental-ram-why-youre-tired-but-havent-done-much-3cbl</link>
      <guid>https://dev.to/osalumense/mental-ram-why-youre-tired-but-havent-done-much-3cbl</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Understanding the invisible drain of cognitive load and how you can reclaim mental clarity as a dev.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Have you ever wrapped up your day feeling drained, yet your GitHub commits, PRs, or task tracker don't reflect much progress? You're not alone. What you're experiencing is likely a depletion of &lt;em&gt;mental RAM&lt;/em&gt;, that limited pool of attention and cognitive energy we all rely on to work effectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Mental RAM?
&lt;/h2&gt;

&lt;p&gt;Just like a machine, your brain has limited memory to juggle multiple tasks, decisions, and distractions. Developers, especially, burn through this "RAM" quickly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Context-switching between different codebases&lt;/li&gt;
&lt;li&gt;Keeping track of logic while debugging&lt;/li&gt;
&lt;li&gt;Mentally holding todos or unsaved thoughts&lt;/li&gt;
&lt;li&gt;Background concerns (meetings, Slack pings, personal stress)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These micro-loads add up fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mental Load is Real Work
&lt;/h2&gt;

&lt;p&gt;Even if you're not actively coding, you're &lt;em&gt;processing&lt;/em&gt;, replaying a bug, planning the next sprint, reviewing edge cases. This cognitive multitasking wears you down like CPU cycles running on high without delivering real output.&lt;/p&gt;

&lt;p&gt;It’s why you can be tired after a day of “not much,” and still feel like your brain's fried.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Is a Problem for Developers
&lt;/h2&gt;

&lt;p&gt;When your mental RAM is full, it leads to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduced problem-solving capacity&lt;/li&gt;
&lt;li&gt;Slow task switching&lt;/li&gt;
&lt;li&gt;More errors and bugs&lt;/li&gt;
&lt;li&gt;Decision fatigue (yes, even choosing between &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;forEach&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Burnout over time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can't optimize code with a laggy IDE. The same goes for your brain.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Free Up Mental Bandwidth
&lt;/h2&gt;

&lt;p&gt;Here's how to reclaim clarity and energy:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Write It Down, Don’t Hold It&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Use a personal notepad, digital app (like Notion, Obsidian), or even your notes app on your device. Get those mental tabs out of your head.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Your brain is for having ideas, not holding them.” – David Allen&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Reduce Context Switching&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Batch similar tasks. Avoid reviewing a PR while debugging an unrelated issue. If possible, block notifications during deep work.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Do a Brain Dump Each Morning&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Before coding, jot down what's in your head—tasks, worries, ideas. It clears the cache.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Close Open Loops&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;An open loop is anything that demands mental attention (e.g., unanswered emails, pending bugs). Either address them or park them on a trusted list for later.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. &lt;strong&gt;Set Mental Bookmarks&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When pausing work, write a quick comment like &lt;code&gt;// stopped here, was checking data flow&lt;/code&gt;. You’ll re-enter the context faster.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. &lt;strong&gt;Use Daily Shutdown Rituals&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;End your workday with a short review:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What did I complete?&lt;/li&gt;
&lt;li&gt;What’s pending?&lt;/li&gt;
&lt;li&gt;What's on deck tomorrow?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It tells your brain it’s okay to stop thinking about work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clarity is a Developer Superpower
&lt;/h2&gt;

&lt;p&gt;Your ability to think clearly is just as important as your ability to write clean code. Guarding your mental RAM means you'll get more meaningful work done with less stress.&lt;/p&gt;

&lt;p&gt;So if you're feeling exhausted and unsure why, pause. Clear your head. Empty the mental RAM. Your future self (and your stack traces) will thank you.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Written for developers who are tired of feeling tired.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What are your go-to ways to reclaim mental clarity? Drop them in the comments.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>mentalhealth</category>
      <category>developers</category>
    </item>
    <item>
      <title>Why Caching Matters More Than You Think (A Real-World Example)</title>
      <dc:creator>Stephen Akugbe</dc:creator>
      <pubDate>Wed, 21 May 2025 14:59:33 +0000</pubDate>
      <link>https://dev.to/osalumense/why-caching-matters-more-than-you-think-a-real-world-example-1l5l</link>
      <guid>https://dev.to/osalumense/why-caching-matters-more-than-you-think-a-real-world-example-1l5l</guid>
      <description>&lt;p&gt;We all love to build things that “just work.”&lt;/p&gt;

&lt;p&gt;But sometimes, the very things that seem perfect on the surface can silently rack up technical debt, or worse, financial cost.&lt;/p&gt;

&lt;p&gt;Let’s talk about caching.&lt;br&gt;
Not in theory, but from a real-world, high-stakes experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem That Wasn’t a Problem (Until It Was)
&lt;/h2&gt;

&lt;p&gt;Sometime last year, I implemented a payment integration flow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generate a token&lt;/li&gt;
&lt;li&gt;Authorize the request&lt;/li&gt;
&lt;li&gt;Create a payment link&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It was seamless. This setup successfully handled hundreds of thousands of deposits. No errors. No downtime. Everything looked rock solid.&lt;/p&gt;

&lt;p&gt;Until about 6 months later.&lt;/p&gt;

&lt;p&gt;Our payment gateway provider reached out:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"We’re seeing a spike in token generation. It’s burning through our resources."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My first reaction: &lt;em&gt;Wait, what?&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem?
&lt;/h2&gt;

&lt;p&gt;We followed the docs and generated a new token before every payment. Nothing seemed wrong. But here’s what we missed: each token had a 20-minute lifespan. Yet, we hit the token endpoint on every transaction, ignoring reuse.&lt;/p&gt;

&lt;p&gt;At scale, that “works fine” code turned into resource-heavy behavior, burning unnecessary compute on the provider’s side.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fix: Caching to the Rescue
&lt;/h2&gt;

&lt;p&gt;We introduced a simple but powerful fix: &lt;strong&gt;caching&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Store the token once it’s generated&lt;/li&gt;
&lt;li&gt;For subsequent requests, we check if it’s still valid&lt;/li&gt;
&lt;li&gt;If valid, we reuse it; if not, we generate a fresh one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now here’s where it gets interesting.&lt;/p&gt;

&lt;p&gt;Even though the token is valid for 20 minutes, we decided to cache and reuse it for only 15 minutes.&lt;/p&gt;

&lt;p&gt;Why leave 5 minutes on the table?&lt;/p&gt;

&lt;p&gt;Because using a token right up to its expiration is risky.&lt;br&gt;
Factors like network latency, server clock differences, and the provider's internal buffer could cause the token to expire mid-request.&lt;/p&gt;

&lt;p&gt;By shaving off 5 minutes, we:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avoid last-second expiry errors&lt;/li&gt;
&lt;li&gt;Ensure predictable behavior&lt;/li&gt;
&lt;li&gt;Maintain a healthy buffer for time-sensitive requests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s a minor trade-off that massively improved reliability.&lt;/p&gt;

&lt;p&gt;The Result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Over 90% reduction in token requests&lt;/li&gt;
&lt;li&gt;Better performance across board&lt;/li&gt;
&lt;li&gt;Happier provider&lt;/li&gt;
&lt;li&gt;Zero disruption to our users&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just a simple cache, and we went from unintentionally wasteful to clean and efficient.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bigger Lesson
&lt;/h2&gt;

&lt;p&gt;Caching isn’t just about speed.&lt;br&gt;
It’s about cost, efficiency, resilience, and being a responsible API consumer.&lt;/p&gt;

&lt;p&gt;Whether you're dealing with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication tokens (Like in my case)&lt;/li&gt;
&lt;li&gt;Frequently accessed data&lt;/li&gt;
&lt;li&gt;Static assets&lt;/li&gt;
&lt;li&gt;Third-party API responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Caching can be the difference between a system that just works... and one that scales gracefully.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;“It works” is not the finish line&lt;/li&gt;
&lt;li&gt;Success at scale can hide deep inefficiencies&lt;/li&gt;
&lt;li&gt;Always consider the cost behind your architecture decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Would You Do?
&lt;/h2&gt;

&lt;p&gt;Have you ever shipped something that worked great, only to discover it wasn’t as efficient or considerate as it looked?&lt;/p&gt;

&lt;p&gt;If you were in this situation, how would you approach the fix?&lt;br&gt;
Would you use a cache? Adjust the token strategy? Something else entirely?&lt;/p&gt;

</description>
      <category>api</category>
      <category>backenddevelopment</category>
      <category>redis</category>
    </item>
    <item>
      <title>Using NestJS Interceptors for Performance Monitoring</title>
      <dc:creator>Stephen Akugbe</dc:creator>
      <pubDate>Mon, 05 May 2025 18:23:04 +0000</pubDate>
      <link>https://dev.to/osalumense/using-nestjs-interceptors-for-performance-monitoring-3e3c</link>
      <guid>https://dev.to/osalumense/using-nestjs-interceptors-for-performance-monitoring-3e3c</guid>
      <description>&lt;p&gt;When APIs feel slow, most developers start by blaming the database or trying to "optimize the code."&lt;br&gt;&lt;br&gt;
But here’s a better first step: &lt;strong&gt;instrument your endpoints&lt;/strong&gt; and find out exactly where the delays are.&lt;/p&gt;
&lt;h2&gt;
  
  
  What should you be asking instead?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Which endpoints are consistently slow?&lt;/li&gt;
&lt;li&gt;Which services take the longest to resolve?&lt;/li&gt;
&lt;li&gt;Are response times spiking under certain conditions?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This kind of visibility is where &lt;strong&gt;NestJS Interceptors&lt;/strong&gt; come in handy — and they’re seriously underrated.&lt;/p&gt;


&lt;h2&gt;
  
  
  🧠 What are NestJS Interceptors?
&lt;/h2&gt;

&lt;p&gt;Interceptors in NestJS let you hook into the &lt;strong&gt;request-response cycle&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
You can run logic &lt;strong&gt;before or after&lt;/strong&gt; a request is handled.&lt;/p&gt;

&lt;p&gt;They’re perfect for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logging&lt;/li&gt;
&lt;li&gt;Transforming responses&lt;/li&gt;
&lt;li&gt;Caching&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Measuring execution time&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the best part? You can do this &lt;strong&gt;without touching your business logic.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  🛠 Example: Measuring API Execution Time
&lt;/h2&gt;

&lt;p&gt;Let’s create a custom &lt;code&gt;MetricsInterceptor&lt;/code&gt; to log how long each endpoint takes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
  Injectable,
  NestInterceptor,
  ExecutionContext,
  CallHandler,
} from '@nestjs/common';
import { Observable, tap } from 'rxjs';

@Injectable()
export class MetricsInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable&amp;lt;any&amp;gt; {
    const now = Date.now();
    const req = context.switchToHttp().getRequest();
    const method = req.method;
    const url = req.url;

    return next.handle().pipe(
      tap(() =&amp;gt; {
        const timeTaken = Date.now() - now;
        console.log(`[${method}] ${url} took ${timeTaken}ms`);
        // Optionally push to Sentry, Datadog, Prometheus, etc.
      }),
    );
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can apply this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Globally&lt;/li&gt;
&lt;li&gt;Per controller&lt;/li&gt;
&lt;li&gt;On specific routes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why do this?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You measure what actually matters&lt;/li&gt;
&lt;li&gt;You catch performance outliers (e.g. admin-only or rarely used endpoints)&lt;/li&gt;
&lt;li&gt;You keep observability separate from your main code&lt;/li&gt;
&lt;li&gt;You reduce blind spots&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s also a great way to complement tools like Sentry or Datadog — especially when you need internal visibility fast.&lt;/p&gt;

&lt;p&gt;Some real-world use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Track slow DB or third-party calls per endpoint&lt;/li&gt;
&lt;li&gt;Set up alerts on endpoints crossing thresholds&lt;/li&gt;
&lt;li&gt;Visualize which modules need refactoring&lt;/li&gt;
&lt;li&gt;Add tags to identify patterns in traffic vs. performance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;NestJS Interceptors are a powerful yet lightweight way to gain observability into your backend APIs. No magic. No overhead. Just TypeScript and good architecture.&lt;/p&gt;

&lt;p&gt;How do you handle monitoring in your nestjs projects?&lt;/p&gt;

</description>
      <category>nestjs</category>
      <category>typescript</category>
      <category>performance</category>
      <category>backenddevelopment</category>
    </item>
    <item>
      <title>Install Tailwind CSS v4 in a Vue 3 + Vite Project</title>
      <dc:creator>Stephen Akugbe</dc:creator>
      <pubDate>Wed, 05 Feb 2025 08:27:16 +0000</pubDate>
      <link>https://dev.to/osalumense/install-tailwind-css-v4-in-a-vue-3-vite-project-319g</link>
      <guid>https://dev.to/osalumense/install-tailwind-css-v4-in-a-vue-3-vite-project-319g</guid>
      <description>&lt;p&gt;Tailwind CSS v4 is here, bringing a more streamlined installation process and performance improvements. However, if you check the official Tailwind CSS documentation, you might not find explicit installation instructions for Vue 3 with Vite. This guide will walk you through the process step-by-step.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What’s New in Tailwind CSS v4?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Tailwind CSS v4 introduces several improvements, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No PostCSS configuration required&lt;/strong&gt; – You no longer need &lt;code&gt;postcss.config.js&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster build times&lt;/strong&gt; – Thanks to better optimizations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;New &lt;code&gt;@tailwindcss/vite&lt;/code&gt; plugin&lt;/strong&gt; – Tailwind now integrates more seamlessly with Vite.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why Vue 3 Instead of Nuxt?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I'm sure you're wondering why I would need Vue 3 instead of just using Nuxt. Vue 3 is a great choice if you’re building a SPA or an SSR-ready app without the full complexity of Nuxt. Here’s why you might choose Vue over Nuxt:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Better Performance&lt;/strong&gt;: Vue 3 is lightweight and doesn’t add the overhead that Nuxt brings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More Control&lt;/strong&gt;: With Vue 3, you decide how your app is structured rather than following Nuxt’s conventions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Need for SSR&lt;/strong&gt;: If you don’t need server-side rendering (SSR) or static site generation (SSG), Vue 3 is simpler.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster Builds&lt;/strong&gt;: Since Nuxt includes additional features, Vue 3 + Vite can be faster for development and deployment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Installing Tailwind CSS v4 in Vue 3 + Vite&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1: Create a Vue 3 Project with Vite&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If you don’t already have a Vue 3 project set up, create one using Vite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm create vite@latest my-vue-app -- --template vue
cd my-vue-app
npm install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2: Install Tailwind CSS v4&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Run the following command to install Tailwind CSS v4 along with its Vite plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -D tailwindcss @tailwindcss/vite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3: Configure Vite to Use Tailwind CSS&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Edit &lt;code&gt;vite.config.ts&lt;/code&gt; (or &lt;code&gt;vite.config.js&lt;/code&gt; if using JavaScript) and add Tailwind CSS as a plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  plugins: [
    vue(),
    tailwindcss(),
  ],
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Step 4: Add Tailwind to Your Styles&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Edit the CSS file &lt;code&gt;src/style.css&lt;/code&gt; and add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@import 'tailwindcss';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Step 5: Import Tailwind CSS in main.ts&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Check your &lt;code&gt;src/main.ts&lt;/code&gt; and ensure your &lt;code&gt;style.css&lt;/code&gt; is imported:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createApp } from 'vue'
import App from './App.vue'
import './style.css'

createApp(App).mount('#app')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Step 6: Start Your Development Server&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Run the Vite development server:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;That’s it! You’ve successfully set up Tailwind CSS v4 in a Vue 3 project using Vite. With this new streamlined setup, you can enjoy faster builds and an even smoother development experience.&lt;/p&gt;

&lt;p&gt;Have you tried Tailwind CSS v4 yet? Share your thoughts in the comments! 🚀&lt;/p&gt;

</description>
      <category>learning</category>
      <category>vue</category>
      <category>tailwindcss</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
