<?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: Luca Restagno</title>
    <description>The latest articles on DEV Community by Luca Restagno (@ikoichi).</description>
    <link>https://dev.to/ikoichi</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%2F638949%2F08bb066f-cab6-4c53-a493-376de3d46fe8.jpeg</url>
      <title>DEV Community: Luca Restagno</title>
      <link>https://dev.to/ikoichi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ikoichi"/>
    <language>en</language>
    <item>
      <title>From 0 to $1.5k MRR: lessons from our first year building BlackTwist</title>
      <dc:creator>Luca Restagno</dc:creator>
      <pubDate>Sun, 20 Jul 2025 16:39:37 +0000</pubDate>
      <link>https://dev.to/ikoichi/from-0-to-15k-mrr-lessons-from-our-first-year-building-blacktwist-11id</link>
      <guid>https://dev.to/ikoichi/from-0-to-15k-mrr-lessons-from-our-first-year-building-blacktwist-11id</guid>
      <description>&lt;p&gt;Hey friends,&lt;/p&gt;

&lt;p&gt;Exactly one year ago, Mattia and I started building a small idea on the side.&lt;/p&gt;

&lt;p&gt;We didn’t have a team.&lt;/p&gt;

&lt;p&gt;We didn’t have an audience.&lt;/p&gt;

&lt;p&gt;Just an itch — and the belief that Threads would need its own ecosystem of tools.&lt;/p&gt;

&lt;p&gt;Today, &lt;a href="https://blacktwist.app" rel="noopener noreferrer"&gt;BlackTwist&lt;/a&gt; just passed $1.5k MRR.&lt;/p&gt;

&lt;p&gt;It’s still early. But it feels real.&lt;/p&gt;

&lt;p&gt;So I wanted to share a few things from behind the scenes — not just the wins, but the messy parts too.&lt;/p&gt;

&lt;h3&gt;
  
  
  🚀 The beginning
&lt;/h3&gt;

&lt;p&gt;We started from scratch.&lt;/p&gt;

&lt;p&gt;Zero followers. Zero traffic. Zero hype.&lt;/p&gt;

&lt;p&gt;Our only “unfair advantage” was that we had been power users of Twitter/X schedulers for years.&lt;/p&gt;

&lt;p&gt;So when Threads launched, I knew exactly what I wanted as a creator — and no one had built it yet.&lt;/p&gt;

&lt;p&gt;So we did.&lt;/p&gt;

&lt;h3&gt;
  
  
  🛠 Building and balancing
&lt;/h3&gt;

&lt;p&gt;I handled the tech.&lt;/p&gt;

&lt;p&gt;Mattia handled the marketing.&lt;/p&gt;

&lt;p&gt;At least… that’s what we tried to do.&lt;/p&gt;

&lt;p&gt;The reality is: we both love building, and sometimes that leads to blurred roles, duplicate work, or missed communication.&lt;/p&gt;

&lt;p&gt;Some weeks it works great.&lt;/p&gt;

&lt;p&gt;Other weeks it creates tension.&lt;/p&gt;

&lt;p&gt;We’re constantly learning how to work together better — how to trust, delegate, and stay in sync without losing the joy of creating.&lt;/p&gt;

&lt;h3&gt;
  
  
  📈 The growth (slow, then suddenly)
&lt;/h3&gt;

&lt;p&gt;We launched fast.&lt;/p&gt;

&lt;p&gt;Added scheduling, calendar view, carousels, auto-reposting, analytics.&lt;/p&gt;

&lt;p&gt;We also launched a #Threads100 challenge — post for 100 days straight, with a leaderboard and streak tracking.&lt;/p&gt;

&lt;p&gt;It was hard to measure the ROI directly, but it definitely brought attention.&lt;/p&gt;

&lt;p&gt;Brand awareness matters, even when it doesn’t “convert” immediately.&lt;/p&gt;

&lt;p&gt;Then we got our first paying users.&lt;/p&gt;

&lt;p&gt;Then more.&lt;/p&gt;

&lt;p&gt;Now, creators are writing about BlackTwist in their guides.&lt;/p&gt;

&lt;p&gt;They tag us.&lt;/p&gt;

&lt;p&gt;They share wins using our tools.&lt;/p&gt;

&lt;p&gt;They recommend us — not because we asked, but because it actually helps them grow.&lt;/p&gt;

&lt;h3&gt;
  
  
  💸 The business model (and how creators help us grow)
&lt;/h3&gt;

&lt;p&gt;One of the best decisions we made was launching an affiliate program.&lt;/p&gt;

&lt;p&gt;We wanted creators to feel like real partners — not just users.&lt;/p&gt;

&lt;p&gt;So we made it easy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creators use BlackTwist to schedule content, build streaks, and stay consistent&lt;/li&gt;
&lt;li&gt;They include us in their growth guides, newsletters, and tool stacks&lt;/li&gt;
&lt;li&gt;When someone signs up through them, they get paid&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No weird requirements. No gatekeeping.&lt;/p&gt;

&lt;p&gt;Just a way for people to earn by sharing something they genuinely use.&lt;/p&gt;

&lt;p&gt;And it’s working.&lt;/p&gt;

&lt;p&gt;We’re seeing more creators mention BlackTwist in their:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Growth strategy threads&lt;/li&gt;
&lt;li&gt;“Tools I use” posts&lt;/li&gt;
&lt;li&gt;YouTube videos&lt;/li&gt;
&lt;li&gt;Notion templates&lt;/li&gt;
&lt;li&gt;Even paid courses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What makes it special is: they’re not doing exclusively for the money.&lt;/p&gt;

&lt;p&gt;They do it because the tool helps them — and then the affiliate link becomes a bonus.&lt;/p&gt;

&lt;p&gt;This organic love has been one of the biggest drivers of momentum recently.&lt;/p&gt;

&lt;p&gt;It’s not explosive, but it’s steady.&lt;/p&gt;

&lt;p&gt;And it’s real.&lt;/p&gt;

&lt;p&gt;The win-win dynamic keeps us focused on making the product genuinely valuable — not just “marketable.”&lt;/p&gt;

&lt;h3&gt;
  
  
  🧭 What’s next
&lt;/h3&gt;

&lt;p&gt;We’re just getting started. Here’s what we’re focused on now:&lt;/p&gt;

&lt;p&gt;Keep building what creators ask for&lt;/p&gt;

&lt;p&gt;Double down on SEO&lt;/p&gt;

&lt;p&gt;Release more free tools (like our &lt;a href="https://blacktwist.app/free-tools/carousel-generator" rel="noopener noreferrer"&gt;Text Carousel Generator&lt;/a&gt; or &lt;a href="https://blacktwist.app/free-tools/fake-threads-post-generator" rel="noopener noreferrer"&gt;Fake Threads Post Generator&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Listen, iterate, repeat&lt;/p&gt;

&lt;h3&gt;
  
  
  💬 Final thoughts
&lt;/h3&gt;

&lt;p&gt;If you’re building something right now and it feels slow — keep going.&lt;/p&gt;

&lt;p&gt;We didn’t go viral. We didn’t launch on Product Hunt.&lt;/p&gt;

&lt;p&gt;We just showed up every week, fixed bugs, improved the product, and listened to users.&lt;/p&gt;

&lt;p&gt;Momentum is often invisible at the start.&lt;/p&gt;

&lt;p&gt;Thanks for reading — and for supporting our journey.&lt;/p&gt;

&lt;p&gt;Talk soon,&lt;/p&gt;

&lt;p&gt;Luca&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Best 11 React UI Component Libraries in 2025</title>
      <dc:creator>Luca Restagno</dc:creator>
      <pubDate>Tue, 11 Mar 2025 07:44:03 +0000</pubDate>
      <link>https://dev.to/ikoichi/best-11-react-ui-component-libraries-in-2025-ffe</link>
      <guid>https://dev.to/ikoichi/best-11-react-ui-component-libraries-in-2025-ffe</guid>
      <description>&lt;p&gt;As a developer deeply familiar with the React ecosystem, I've seen firsthand how &lt;strong&gt;React remains a dominant force in front-end development&lt;/strong&gt;. Its popularity isn't just hype; it's rooted in the framework's ability to enable developers to &lt;strong&gt;build modern, efficient, and accessible user interfaces&lt;/strong&gt;. The real game-changer, in my experience, has been the rise of React UI component libraries. These libraries provide a treasure trove of pre-built, reusable UI components that can be dropped into projects, saving countless hours of development time. From basic buttons and forms to complex data tables and charts, these libraries offer a wide range of elements that accelerate the development process. What I appreciate most is that these components aren't just about speed; they embody design and accessibility best practices, ensuring that the user interfaces are both visually appealing and highly functional.&lt;/p&gt;

&lt;p&gt;React UI component libraries offer tools for building efficient and accessible user interfaces by providing &lt;strong&gt;pre-designed UI elements&lt;/strong&gt; that simplify and accelerate software development. These elements, ranging from basic components like buttons and modals to more complex ones like data tables and charts, serve as building blocks for developers. By using these libraries, developers can &lt;strong&gt;implement common UI patterns&lt;/strong&gt; more efficiently, &lt;strong&gt;ensure consistency&lt;/strong&gt; across the project, and &lt;strong&gt;enhance the overall quality&lt;/strong&gt; of their applications. Many of these libraries also prioritize accessibility, making it easier to create applications that are usable by everyone. Furthermore, React UI component libraries help to &lt;strong&gt;reduce development costs&lt;/strong&gt;, &lt;strong&gt;increase productivity&lt;/strong&gt;, and &lt;strong&gt;minimize the risk&lt;/strong&gt; of introducing bugs into applications. Some libraries also integrate with design tools and offer improved TypeScript support, further streamlining the development process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of using component libraries
&lt;/h2&gt;

&lt;p&gt;In my experience, the &lt;strong&gt;benefits of using React UI component libraries&lt;/strong&gt; are substantial, impacting various facets of the development lifecycle. Here's a detailed look at the advantages I've observed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Efficiency and Speed:&lt;/strong&gt; One of the most immediate benefits I've noticed is the significant &lt;strong&gt;boost in development speed&lt;/strong&gt;. React component libraries offer pre-built solutions, which streamlines the implementation of design features and functionalities. Instead of writing code for every React component from scratch, you can simply import and use the available elements. This is particularly useful when implementing common UI patterns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency:&lt;/strong&gt; React UI libraries ensure a &lt;strong&gt;consistent look and feel&lt;/strong&gt; across your application. Since these libraries are designed with a cohesive style guide, the user interface maintains uniformity, which enhances the overall user experience. This is especially beneficial for large teams working on multiple projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quality Enhancement:&lt;/strong&gt; Top-tier React component libraries are &lt;strong&gt;well-tested and maintained&lt;/strong&gt;, which ensures high quality and reduces the risk of introducing bugs into applications. These libraries often follow accessibility best practices, making it easier to create applications usable by everyone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost Reduction:&lt;/strong&gt; By using pre-built components, the &lt;strong&gt;overall development costs&lt;/strong&gt; can be significantly reduced. The time and resources saved on designing and developing components from scratch can be allocated to other critical aspects of the project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Productivity Boost:&lt;/strong&gt; The use of pre-built components &lt;strong&gt;saves a significant amount of time and effort&lt;/strong&gt;, allowing developers to focus on the more complex and unique aspects of their applications. This increased productivity translates to faster project completion and more efficient resource utilization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access to Expertise:&lt;/strong&gt; Component libraries are often developed and maintained by &lt;strong&gt;experienced developers&lt;/strong&gt;. This means that when using these libraries, you benefit from the expertise and best practices embedded within the components.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community Support:&lt;/strong&gt; Many component libraries have &lt;strong&gt;active communities of users&lt;/strong&gt;. These communities provide support, help, and resources, making it easier to troubleshoot issues and find solutions. The continuous development, bug fixes, and extensive documentation further enhance the value of these libraries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customization&lt;/strong&gt;: Despite offering ready-to-use components, React UI libraries are &lt;strong&gt;highly customizable&lt;/strong&gt; to fit project-specific requirements. Theming and style props allow you to override and extend component styles, ensuring that the UI aligns with your design vision.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility&lt;/strong&gt;: Many UI libraries prioritize accessibility, making it &lt;strong&gt;easier to create applications&lt;/strong&gt; that are usable by everyone. By adhering to accessibility standards like WAI-ARIA, these libraries ensure that components are keyboard navigable, screen reader compatible, and adhere to WCAG guidelines.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In essence, React UI component libraries offer a blend of speed, consistency, quality, and community support, making them an indispensable tool in modern React development. The ability to customize and extend these components further enhances their value, allowing you to create unique and efficient user interfaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trends in 2025
&lt;/h2&gt;

&lt;p&gt;Based on what I've gathered, several key trends are apparent in React UI libraries as we move into 2025. These trends are all about making the development process smoother, ensuring higher code quality, and tackling the ever-changing demands of modern web applications.&lt;/p&gt;

&lt;p&gt;One of the most interesting things I'm seeing is the increasing use of &lt;strong&gt;Artificial Intelligence&lt;/strong&gt; in UI development. It's not just a gimmick; AI is being used to make some real improvements. For example, AI systems can now suggest the best component setups for a project, create color schemes that perfectly match a brand's style, and even study how users interact with the UI to fine-tune layouts. I've also noticed AI helping with tasks like writing component documentation and suggesting properties for components. While it's still early days, the potential of AI to transform UI development is hard to ignore.&lt;/p&gt;

&lt;p&gt;I'm also seeing React UI libraries &lt;strong&gt;integrating more closely with design tools&lt;/strong&gt; like Figma, Sketch, and Adobe XD. This means that changes in design can be synced with the component code in real-time. I've even seen tools that can automatically turn design files into React components. The goal here is to cut down on the time and effort it takes to turn designs into working code.&lt;/p&gt;

&lt;p&gt;Another big trend is the &lt;strong&gt;enhanced support for TypeScript&lt;/strong&gt;. As more and more developers adopt TypeScript with React, UI libraries are stepping up their game by providing better type definitions for components and utilities. I've found that this makes it easier to catch mistakes early on and work with complicated component APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to choose a React Component Library
&lt;/h2&gt;

&lt;p&gt;There are &lt;strong&gt;several key factors to consider when choosing a React UI library&lt;/strong&gt;. These considerations can help ensure that the selected library aligns well with the project’s specific needs, design goals, and technical constraints.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Project Needs:&lt;/strong&gt; A primary consideration is whether the library provides the necessary components and features required for the project. It's important to assess the project’s scale and type, and any specific requirements. For instance, a large enterprise application will require a library capable of supporting a high level of complexity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customizability:&lt;/strong&gt; Another important aspect is the degree to which the library can be tailored to fit the brand's design guidelines. Some libraries offer more customization options than others.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Longevity:&lt;/strong&gt; It's crucial to consider how frequently the library is updated and whether it is likely to be supported in the future. Choosing a library that is actively maintained ensures that you won't need to migrate to a new library in the near future.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learning Curve:&lt;/strong&gt; The ease with which a new developer can learn and use the library is also an important consideration. Selecting a library that is easy for new developers to learn is particularly important when working in a team.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community Support:&lt;/strong&gt; The presence of a large and active community can provide support and help when resolving issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation:&lt;/strong&gt; Well-written documentation can make it easier to learn how to use the library and find solutions to problems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility:&lt;/strong&gt; It's essential to ensure that the library follows accessibility best practices and guidelines, such as WAI-ARIA. This ensures that components function well with screen readers and are accessible to all users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance:&lt;/strong&gt; Performance is another critical factor to consider. If high performance is a priority, choose a React component library known for its speed and responsiveness.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency:&lt;/strong&gt; Libraries designed with a cohesive style guide ensure a consistent look and feel across the application, enhancing the overall user experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Specific Use Cases&lt;/strong&gt;: The best library for a project depends on your requirements. Some libraries may be more suited for dashboards, while others are better for static pages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By carefully evaluating these factors, you can choose a React component library that is a good fit for your project, enhancing both the development process and the final product.&lt;/p&gt;

&lt;p&gt;Let’s discover together the 11 best React UI Components Libraries, with an in-depth description of their characteristics.&lt;/p&gt;

&lt;h2&gt;
  
  
  MaterialUI (MUI)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://mui.com/" rel="noopener noreferrer"&gt;https://mui.com/&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Material UI (MUI) stands out as a prominent React component library&lt;/strong&gt; that implements Google's Material Design. It offers a comprehensive set of pre-built components ready for production use. With over 89.3k stars on GitHub and more than 3 million weekly downloads on NPM, it's clear that MUI is a popular choice among developers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Comprehensive Components&lt;/strong&gt;: MUI provides a wide array of pre-built components, including buttons, forms, tables, and charts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility&lt;/strong&gt;: Accessibility is a key focus, ensuring components meet high usability standards. MUI components are designed to be accessible by default, making it easier to create usable applications for everyone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customization&lt;/strong&gt;: It has customization options for implementing custom design systems. Developers can easily tailor components and themes to their preferred designs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Theme Support&lt;/strong&gt;: MUI supports theming, which allows for easy changes to the look and feel of an entire application. It offers theme toggling customization with support for dark and light modes. You can customize the theme to your preferred choice using the &lt;code&gt;ThemeProvider&lt;/code&gt; component.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strong Community&lt;/strong&gt;: A large and active community of users and contributors supports MUI. The documentation is well-written, so developers can easily understand and use the library.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Typography&lt;/strong&gt;: MUI follows its typography guidelines to ensure all text elements have consistent text styling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Icons&lt;/strong&gt;: It provides a collection of icons that can be used in your application. The icons can be imported from the &lt;code&gt;@mui/icons-material&lt;/code&gt; package.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form Controls&lt;/strong&gt;: MUI provides a range of form components like text fields, checkboxes, radio buttons, and select menus, to make creating a user-friendly form easy and accessible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsive Design&lt;/strong&gt;: MUI components are responsive to ensure your application works well on different screen sizes and devices.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Cases&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;MUI can be used to build various React applications, from simple websites to complex enterprise applications. It is particularly suitable for applications needing to be visually appealing and consistent. Also, it is a good choice for applications that need to be accessible to all users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Aesthetics&lt;/strong&gt;: Material UI has modern, beautiful designs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customization&lt;/strong&gt;: It offers customization options that allow developers to easily tailor components and themes to their preferred designs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility&lt;/strong&gt;: The library is designed to be accessible by default, making it easier to create usable applications for everyone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsive Design&lt;/strong&gt;: Material UI components are responsive to ensure your application works well on different screen sizes and devices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developer-Friendly&lt;/strong&gt;: The documentation is well-written, so developers can easily understand and use the library. The components are also easy to import and implement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Designed-friendlt:&lt;/strong&gt; MUI provides a Figma representation of React’s components, allowing designers and developers to easily collaborate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In summary, Material UI remains a robust choice for React developers, offering a blend of comprehensive components, strong community support, and continuous updates that keep it relevant in the evolving landscape of UI libraries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ant Design
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://ant.design/" rel="noopener noreferrer"&gt;https://ant.design/&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Ant Design is a React component library&lt;/strong&gt; that implements the Ant Design system, originally created by Ant Financial. It is particularly well-suited for building enterprise-level applications. With over 88k stars on GitHub and more than 1.3 million weekly downloads on NPM, it's a popular choice, especially for those needing robust, professional-looking components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise-Level Components&lt;/strong&gt;: Ant Design offers a wide range of enterprise-level components, such as data tables, form layouts, and organization charts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Professional Look&lt;/strong&gt;: The design system is heavily influenced by Chinese design principles, resulting in a more elegant and professional aesthetic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Out-of-the-Box Features&lt;/strong&gt;: Ant Design provides features not always available in other libraries, like internationalization support and type safety.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customizability&lt;/strong&gt;: It provides customizable options that simplify the implementation of custom design systems. It allows theming and customization, giving control over typography, style, and colors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internationalization Support&lt;/strong&gt;: Ant Design supports dozens of languages and has built-in internationalization support for global users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Theme&lt;/strong&gt;: Ant Design allows theme customization, so light and dark themes can be integrated, and the preferred theme mode customized.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Icons&lt;/strong&gt;: It offers a variety of icons from the &lt;code&gt;@ant-design/icons&lt;/code&gt; package.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Navigation Menus&lt;/strong&gt;: The library includes React components for navigation, like Menus and Sidebars.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Visualization&lt;/strong&gt;: Ant Design provides data visualization components like Charts and Graphs, accessible from the &lt;code&gt;@ant-design/charts&lt;/code&gt; package.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Date Pickers and Calendar&lt;/strong&gt;: It also provides customizable date pickers, time pickers, and calendars.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Popovers and Tooltips&lt;/strong&gt;: It offers popups and tooltips that show context-sensitive information.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Cases&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So, when would you actually use Ant Design for a project? Well, it's particularly great if you're &lt;strong&gt;building enterprise-level applications&lt;/strong&gt;, especially ones that involve a lot of complex data. Think projects that need intricate &lt;strong&gt;data tables, well-organized form layouts, or even organization charts&lt;/strong&gt;. It has components to solve a lot of common problems in this space. Also, consider Ant Design if you're going for &lt;strong&gt;an elegant and professional look&lt;/strong&gt; for your application. Ant Design's style takes cues from Chinese design principles, giving it a distinct feel. Finally, Ant Design is useful if you need to &lt;strong&gt;support multiple languages or ensure type safety&lt;/strong&gt;. Ant Design has built-in internationalization features, making it easier to cater to a global audience.&lt;/p&gt;

&lt;p&gt;In essence, &lt;strong&gt;Ant Design is a go-to when you need a robust, polished, and scalable solution for complex applications, especially in the enterprise domain&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Customization&lt;/strong&gt;: Ant Design allows theming and customization, giving you customization control over typography, style, and colors to fit your preferred design.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility&lt;/strong&gt;: It follows accessibility best practices, allowing you to build for all types of users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form Controls&lt;/strong&gt;: It has robust form validation that helps simplify form validation logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community Support&lt;/strong&gt;: The library has a large and active community of developers who are maintaining, contributing, and improving the library. There are also articles to help you as you build.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise-Grade&lt;/strong&gt;: It is designed and built with enterprise applications in mind and provides a well-designed and professional look for your enterprise or business applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ant Design remains a strong choice for developers focused on enterprise-level applications, offering a rich set of components, excellent internationalization support, and a professional design aesthetic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chakra UI
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://chakra-ui.com/" rel="noopener noreferrer"&gt;https://chakra-ui.com/&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Chakra UI is a modular and accessible React component library&lt;/strong&gt; that provides the building blocks needed to construct React applications. It is designed to be simple, flexible, and extensible. Chakra UI has over 34.7k stars on GitHub.&lt;/p&gt;

&lt;p&gt;Chakra UI offers a range of components, including buttons, forms, tables, and charts. It allows React developers to efficiently create newer components. In Chakra UI, the components are customizable, reusable, and adhere to the WAI-ARIA standards.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Style Props&lt;/strong&gt;: Chakra UI uses style props to style components.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Icons&lt;/strong&gt;: It provides a collection of icons from the &lt;code&gt;@chakra-ui/icons&lt;/code&gt; package.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form Controls&lt;/strong&gt;: Chakra UI also provides components like &lt;code&gt;Textarea&lt;/code&gt;, &lt;code&gt;Input&lt;/code&gt;, and &lt;code&gt;Checkbox&lt;/code&gt; that have built-in validations and form controls like &lt;code&gt;isDisabled&lt;/code&gt; and &lt;code&gt;isInvalid&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notification&lt;/strong&gt;: Chakra UI has notification components like &lt;code&gt;Toast&lt;/code&gt; and &lt;code&gt;Alert&lt;/code&gt; that display state notification messages to users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Theme&lt;/strong&gt;: Chakra UI is dark mode compatible by default.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Cases&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So, when would you actually use Chakra UI for a project? Well, it's particularly great if you're focused on &lt;strong&gt;building accessible React applications&lt;/strong&gt;. Also, consider Chakra UI if you're interested in &lt;strong&gt;building modular and reusable React components&lt;/strong&gt;. Furthermore, Chakra UI is useful when &lt;strong&gt;creating custom React themes&lt;/strong&gt;. Finally, Chakra UI is a good choice for &lt;strong&gt;building React applications with a consistent look and feel&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In essence, &lt;strong&gt;Chakra UI is a go-to when you prioritize accessibility, modularity, and theming in your React projects&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity&lt;/strong&gt;: Chakra UI is simple to use and understand, reducing the learning curve and allowing developers to focus on development.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility&lt;/strong&gt;: Chakra UI is built with accessibility in mind. Chakra UI components meet WAI-ARIA standards, making apps easily accessible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Theme&lt;/strong&gt;: Chakra UI is dark mode compatible by default. The theme color can be adjusted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customization&lt;/strong&gt;: All component styles can be overridden or extended via style props. Components, including colors and spacing, are easily customizable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation&lt;/strong&gt;: The documentation is comprehensive and well-written, with usage guidelines and examples.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developer Community&lt;/strong&gt;: It has an active and growing community of developers. Aside from the core team, approximately 100 developers are actively contributing to the project, so there are sure to be resources and improvements in the library.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Important UI Components&lt;/strong&gt;: Chakra UI provides customizable React components for web projects including buttons, menus, modals, and forms. Variations serve different purposes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Seamless Form Integrations&lt;/strong&gt;: Chakra UI’s form components work well with React Hook Form, Formik, and Final Form. This makes forms adaptable and accessible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coding Collaboration Tools&lt;/strong&gt;: Chakra UI Figma design kits ensure design-to-code fidelity between designers and developers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lightweight and Reusable Logic&lt;/strong&gt;: Built-in performance measures, such as automated code splitting, reduce bundle sizes. Composable component architecture maximizes logic reuse across an application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Chakra UI is a strong choice for developers focused on modularity, accessibility, and ease of use, offering a blend of comprehensive components, excellent documentation, and a growing community.&lt;/p&gt;

&lt;h2&gt;
  
  
  Headless UI
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://headlessui.com/" rel="noopener noreferrer"&gt;https://headlessui.com/&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Headless UI is a React component library that provides a set of unstyled UI components&lt;/strong&gt; that can be used to build custom UI components. This makes it a good choice for developers who want to have full control over the look and feel of their UI. Headless UI has over 22.5k stars on GitHub.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unstyled components&lt;/strong&gt;: The components in Headless UI are unstyled, which means that there is full control over their appearance. This makes it easy to create custom UI components that match the design of the application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessible&lt;/strong&gt;: All of the components in Headless UI are built to be accessible, so you can be sure that your applications will be accessible to users with disabilities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Well-documented&lt;/strong&gt;: Headless UI is well-documented, with clear and concise examples for each component. This makes it easy to learn how to use the library and to start building custom UI components right away.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind CSS Integration:&lt;/strong&gt; Headless UI seamlessly integrates with Tailwind CSS for rapid styling and customization.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Cases&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So, when would you actually use Headless UI for a project? Well, it's particularly great if you're focused on &lt;strong&gt;building custom UI components&lt;/strong&gt; and want to have full control over the look and feel of your UI. Also, consider Headless UI if you're interested in &lt;strong&gt;building complex UI components&lt;/strong&gt;, breaking them down into smaller, more manageable pieces.&lt;/p&gt;

&lt;p&gt;In essence, &lt;strong&gt;Headless UI is a go-to for React projects where complete customization, accessibility, and performance are top priorities&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Mantine
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://mantine.dev/" rel="noopener noreferrer"&gt;https://mantine.dev/&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Mantine is a fully functional React UI library&lt;/strong&gt; that has over 100 customizable components and 50 hooks that can be used to build React web applications. It is also open-source and TypeScript-supported. Mantine has over 21.9k stars on GitHub.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Theme engine:&lt;/strong&gt; Mantine provides a powerful theme engine that allows easy customization of the look and feel of an application. The theme engine is also extensible, allowing the creation of custom themes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hooks library:&lt;/strong&gt; Mantine provides hooks that can be used to manage state and side effects in React applications. Mantine hooks are designed to be easy to use and to work well with other React libraries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customize components:&lt;/strong&gt; Every Mantine component supports visual customizations with props, which facilitates quick prototyping and experimentation by modifying component props.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Styles overriding:&lt;/strong&gt; Each Mantine component supports styles overriding for every internal element inside with classes or inline styles. This feature, alongside other customization options, allows implementation of any visual modifications to components and adapts them to fit almost any design requirements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexible theming:&lt;/strong&gt; The default theme can be extended with any amount of additional colors, and properties such as shadows, radius, spacing, and fonts can be replaced to match design requirements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Components&lt;/strong&gt;: Mantine offers various UI components, from basic components like buttons and input fields to complete components like modals and notifications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Animations and Transitions&lt;/strong&gt;: Mantine has built-in support for smooth animations and transitions for a better user experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Icons&lt;/strong&gt;: This library supports icon libraries like react-icons, font awesome, and radix icons.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Cases&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's a more conversational take on Mantine's use cases, without bullet points:&lt;/p&gt;

&lt;p&gt;So, when would you actually use Mantine for a project? It's a great fit when you need to focus on &lt;strong&gt;customizing the appearance and behavior of components&lt;/strong&gt; using theme and context providers. Also, Mantine is useful when &lt;strong&gt;integrating with popular libraries&lt;/strong&gt; like react-hook-form, react-query, and react-table. Furthermore, consider Mantine when &lt;strong&gt;building complex layouts and interactions&lt;/strong&gt; with its hooks and utilities. Finally, Mantine can be helpful when you're &lt;strong&gt;developing and testing components in isolation&lt;/strong&gt; with Mantine/Prism.&lt;/p&gt;

&lt;p&gt;In essence, &lt;strong&gt;Mantine is a go-to when you need a highly customizable and integratable React UI library for a wide range of development tasks&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Developer Experience&lt;/strong&gt;: Mantine provides a good developer experience as the documentation is written well and arranged orderly for easy navigation. It is also easy to learn and use so that beginners can use it without hassle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customization&lt;/strong&gt;: Developers can customize the typography and themes and adjust stylings to their needs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community Support&lt;/strong&gt;: With a growing and active developer community, Mantine is well-maintained and updated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility&lt;/strong&gt;: This is also a priority for Mantine; all components are built to be fully accessible so that developers can build applications for all types of users.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Mantine is a strong choice for developers looking for a fully functional, customizable, and accessible React UI library with a wide range of components and hooks&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  HeroUI (previously NextUI)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.heroui.com/" rel="noopener noreferrer"&gt;https://www.heroui.com/&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;HeroUI is a React component library that provides pre-built components designed for speed, accessibility and being lightweight&lt;/strong&gt;. It is built on React and Tailwind CSS. Next UI has over 16.3k stars on GitHub.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Custom themes:&lt;/strong&gt; HeroUI provides a custom TailwindCSS plugin that allows customization of the default themes or creation of custom themes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility:&lt;/strong&gt; HeroUI components are built on top of React Aria ensuring accessibility support.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dark mode:&lt;/strong&gt; HeroUI comes with a default dark theme that can be applied by adding the dark attribute to the HTML.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy customizations:&lt;/strong&gt; HeroUI simplifies component slots customization while avoiding Tailwind class conflicts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Theme&lt;/strong&gt; : HeroUI has a default dark theme, and you can define themes, color schemes, and styles according to your project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lazy Loading&lt;/strong&gt; : Many HeroUI components support lazy loading, which can help improve your app’s performance by loading components and assets only when needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internationalization Support&lt;/strong&gt; : HeroUI includes internationalization support, making creating multilingual applications for a global user base easier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form Validation&lt;/strong&gt; : Form components in HeroUI come with built-in form validations, helping to simplify the process of handling form validation logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Animations and Transition&lt;/strong&gt; : HeroUI components often include animations and transition support for smooth and clean UI interactions. It uses Framer Motion to animate some components due to the complexity of the animations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Cases&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;HeroUI is a good choice when you want to utilize the &lt;strong&gt;React component model and hooks to manage the state and behavior of your UI elements&lt;/strong&gt;. HeroUI can be used for building web applications that need to be &lt;strong&gt;supported in both dark and light mode&lt;/strong&gt;. Also, consider HeroUI when building web applications that need to be &lt;strong&gt;translated into multiple languages&lt;/strong&gt;. Finally, HeroUI is useful because &lt;strong&gt;it is compatible with React, Vue, and Angular frameworks, and supports TypeScript and Sass&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In essence, &lt;strong&gt;HeroUI is a go-to when you need a versatile, themable, and accessible React UI library for a variety of web application needs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility&lt;/strong&gt; : HeroUI components are built on top of React Aria and follow WAI-ARIA guidelines to ensure accessibility support.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customization&lt;/strong&gt; : HeroUI allows easy customization for themes, typography, and styles, allowing for unique and beautiful UI designs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developer Experience&lt;/strong&gt; : HeroUI offers a user-friendly and intuitive API for beginner and advanced developers. The documentation also provides a thorough explanation with examples of using and configuring the library.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reusable Components&lt;/strong&gt; : HeroUI provides a comprehensive set of reusable UI components that can be easily integrated into your React application, reducing development time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community&lt;/strong&gt; : The community is active and growing. The library is actively maintained, bugs are fixed, and new features are regularly introduced and added.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;HeroUI is a strong choice for developers looking for a fully-featured, accessible, and customizable React UI library, especially when working with Next.js and requiring server-side rendering&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Semantic UI React
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://react.semantic-ui.com/" rel="noopener noreferrer"&gt;https://react.semantic-ui.com/&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Semantic UI React is a React component library that implements the Semantic UI CSS framework&lt;/strong&gt;. It provides pre-built components ready for use in production. As of the article's writing, Semantic UI React has over 13.1k stars on GitHub.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Semantic HTML:&lt;/strong&gt; Semantic UI React is built around semantic HTML, meaning components are named and structured to easily understand their purpose.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility:&lt;/strong&gt; Semantic UI React is committed to accessibility, with all components designed to meet Web Content Accessibility Guidelines (WCAG) standards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Theming:&lt;/strong&gt; Semantic UI React provides built-in theming support, allowing customization of the look and feel of your application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensibility:&lt;/strong&gt; Semantic UI React is extensible, so you can create custom components and themes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto Controlled State&lt;/strong&gt; : Components with states self-manage their states out-of-the-box, without wiring, so you don’t need to write the state logic explicitly, as it is handled automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shorthand props&lt;/strong&gt; : Semantic UI React uses shorthand props to generate markups. For instance, icon props can accept string names, can be object props, or an &lt;code&gt;&amp;lt;Icon /&amp;gt;&lt;/code&gt; instance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Augmentation&lt;/strong&gt; : A component can be rendered as another component using the as props.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Cases&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Semantic UI React is particularly useful when you're focused on &lt;strong&gt;building accessible React applications&lt;/strong&gt; or when you need your React applications to have &lt;strong&gt;a consistent look and feel&lt;/strong&gt;. It's also a good choice if you plan on &lt;strong&gt;creating custom React components and themes&lt;/strong&gt;. Furthermore, Semantic UI React is helpful when you're &lt;strong&gt;building React applications that need to be translated into multiple languages&lt;/strong&gt; or &lt;strong&gt;integrated with third-party libraries and services&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Semantic HTML&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accessibility&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Theming&lt;/strong&gt;: Semantic UI React offers theme support and allows you to customize the layout and styles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community Support&lt;/strong&gt;: Semantic UI React has an active community, so you will always find tutorials, third-party extensions, bug fixes, and answers to your questions and challenges.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developer Experience&lt;/strong&gt;: Semantic UI React is easy to use, and the documentation is also easy to work around and locate the things you need.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Semantic UI React appears to focus on providing a &lt;strong&gt;balance between ease of use, customization, and adherence to web standards, making it a solid choice for a variety of React projects&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Grommet
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://v2.grommet.io/" rel="noopener noreferrer"&gt;https://v2.grommet.io/&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Grommet UI is a React component library&lt;/strong&gt; that provides a comprehensive collection of accessible, reusable, and responsive components that can be used to build modern web applications. It is designed with a focus on accessibility, performance, and usability. As of the article's writing, Grommet has over 8.4k GitHub stars.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Theming:&lt;/strong&gt; Grommet UI provides a powerful theming system that allows easy customization of the look and feel of your application. It has built-in themes that you can choose from, allowing you to customize it with your preferred color scheme.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Styling:&lt;/strong&gt; Grommet UI components are styled with CSS-in-JS, which gives you full control over the appearance of your application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility:&lt;/strong&gt; Grommet UI is committed to accessibility, and all of its components are designed to meet the Web Content Accessibility Guidelines (WCAG) standards. Accessibility is also a top priority, and it follows the web accessibility standard for its components. This allows you to build applications for all users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsiveness&lt;/strong&gt;: Grommet is built with responsive design in mind so your application works well on multiple screen sizes. It is a mobile-first UI library that approaches design to ensure that it is responsive on mobile devices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form Validation&lt;/strong&gt;: The text inputs come with validation features, reducing the task of writing your validation logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Animation and Transition&lt;/strong&gt;: Grommet supports animation and transitions, allowing you to create smooth and user-interactive user interfaces.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Cases&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider Grommet when you want to &lt;strong&gt;create responsive and accessible web applications&lt;/strong&gt; that follow the WAI-ARIA guidelines and support keyboard navigation, screen reader, and typeahead. Also, Grommet is useful when you need to &lt;strong&gt;import individual components&lt;/strong&gt; without heavy dependencies and want to customize those components. Furthermore, Grommet works well when you plan to &lt;strong&gt;use React component model and hooks&lt;/strong&gt; to manage UI behavior. Finally, Grommet is a good choice for &lt;strong&gt;building web applications that need to support multiple languages&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Semantic UI React: Semantic UI React is particularly useful when you're focused on &lt;strong&gt;building accessible React applications&lt;/strong&gt; or when you need your React applications to have &lt;strong&gt;a consistent look and feel&lt;/strong&gt;. It's also a good choice if you plan on &lt;strong&gt;creating custom React components and themes&lt;/strong&gt;. Furthermore, Semantic UI React is helpful when you're &lt;strong&gt;building&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Responsiveness&lt;/strong&gt;: Grommet is designed to be responsive out-of-the-box, making your application look good on various screen sizes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility&lt;/strong&gt;: This benefits both the developer and the global user base.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developer Experience&lt;/strong&gt;: The developer's experience is good as it is easy to use and understand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community Support&lt;/strong&gt;: Grommet has an active community, and the documentation is updated as new features are added/introduced.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Grommet is known for its focus on usability, theming, and extensive intuitive components. It is a part design system and part framework.&lt;/p&gt;

&lt;p&gt;Here's a more conversational take on Grommet's use cases, without bullet points:&lt;/p&gt;

&lt;p&gt;Consider Grommet when you want to &lt;strong&gt;create responsive and accessible web applications&lt;/strong&gt; that follow the WAI-ARIA guidelines and support keyboard navigation, screen reader, and typeahead. Also, Grommet is useful when you need to &lt;strong&gt;import individual components&lt;/strong&gt; without heavy dependencies and want to customize those components. Furthermore, Grommet works well when you plan to &lt;strong&gt;use React component model and hooks&lt;/strong&gt; to manage UI behavior. Finally, Grommet is a good choice for &lt;strong&gt;building web applications that need to support multiple languages&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Grommet is a solid choice when you need a responsive, accessible, and themable React UI library with good community support&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shadcn UI
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://ui.shadcn.com/" rel="noopener noreferrer"&gt;https://ui.shadcn.com/&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Shadcn UI is a rapidly growing component library&lt;/strong&gt; that leverages &lt;strong&gt;Tailwind CSS and Radix UI for styling&lt;/strong&gt;. It offers a fresh approach to building user interfaces with a focus on simplicity, speed, and accessibility. Instead of installing a package, Shadcn UI takes a copy-and-paste approach and allows you to copy the code for any document directly into your project. As of the article’s writing, Shadcn UI has over 66k stars on GitHub.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Themes and Theme Editor&lt;/strong&gt;: It provides a robust theme editor that allows you to easily customize colors, border radius, and other visual elements to match your brand identity or project requirements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Light and Dark Mode&lt;/strong&gt;: Shadcn UI supports light and dark mode out of the box. You can use this feature to integrate theme toggling functionality into your application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supports Tailwind CSS:&lt;/strong&gt; It is built on top of Tailwind CSS and benefits from Tailwind’s utility-first approach. This means you can quickly create custom styles without writing extensive CSS code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Edit in v0:&lt;/strong&gt; This feature allows you to open a Shadcn UI component in the v0 app and adjust the component via prompts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use cases&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Shadcn UI is useful when &lt;strong&gt;building user interfaces with a focus on simplicity, speed, and accessibility&lt;/strong&gt;. It is also helpful when creating &lt;strong&gt;unique and branded user interfaces&lt;/strong&gt; that match a project's and brand's requirements, because of the freedom of customization offered by the theme editor and integration with Tailwind CSS. Consider Shadcn UI for projects where you want &lt;strong&gt;component ownership&lt;/strong&gt;, giving you more control and direct access to the components’ code. Furthermore, Shadcn UI is a good choice for &lt;strong&gt;building responsive, professional web applications&lt;/strong&gt;. It is also helpful for creating &lt;strong&gt;custom styles&lt;/strong&gt; that can offer consistent components across a project.&lt;/p&gt;

&lt;p&gt;Shadcn UI is suitable for projects where you want &lt;strong&gt;highly customizable components&lt;/strong&gt;, &lt;strong&gt;full control over your codebase&lt;/strong&gt;, and a &lt;strong&gt;streamlined development process leveraging Tailwind CSS&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tailored Designs:&lt;/strong&gt; The theme editor and its integration with Tailwind CSS provide greater freedom for customizations. It allows you to create unique and branded user interfaces that match your project’s and brand’s requirements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Component Ownership:&lt;/strong&gt; Shadcn UI gives you more control and ownership over its components by giving you direct access to the components’ code. With this approach, every component you use will live directly in your codebase.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Beautifully designed components&lt;/strong&gt; that you can copy and paste into your apps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools for theming&lt;/strong&gt; and a simple setup process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexible architecture&lt;/strong&gt; enables developers to create custom styles that can offer consistent components across the project.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Shadcn UI distinguishes itself through its copy-and-paste approach, integration with Tailwind CSS, and focus on customization and component ownership.&lt;/p&gt;

&lt;p&gt;There are varying perspectives on Shadcn UI within the React community. Some argue that Shadcn UI isn't a component library, but rather a collection of reusable components. Others highlight that by copying components into your app, you establish a foundation for your own component library and gain complete control over the component's functionality and styling.&lt;/p&gt;

&lt;h2&gt;
  
  
  React Aria
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://react-spectrum.adobe.com/react-aria/index.html" rel="noopener noreferrer"&gt;https://react-spectrum.adobe.com/react-aria/&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;React Aria is a library of React Hooks&lt;/strong&gt; that provides accessible UI primitives for your design system. As of January 2025, Adobe's React Aria has matured into a full-fledged component library, offering advanced accessibility and customization options for complex UI patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Offers over &lt;strong&gt;40 components with built-in behavior, adaptive interactions, accessibility, and internationalization&lt;/strong&gt;, ready for custom styles.&lt;/li&gt;
&lt;li&gt;Provides an &lt;strong&gt;excellent user experience&lt;/strong&gt;, notably with functions such as screen reader assistance, keyboard controls, focus handling, language translations, and additional features.&lt;/li&gt;
&lt;li&gt;Provides &lt;strong&gt;accessible components&lt;/strong&gt; out of the box and utilizes ARIA attributes and roles.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Cases&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;React Aria is useful when you need &lt;strong&gt;accessible UI primitives for your design system&lt;/strong&gt;. It is also helpful to consider when you need components with &lt;strong&gt;built-in behavior, adaptive interactions, accessibility, and internationalization&lt;/strong&gt;, ready for custom styles. Furthermore, consider React Aria when aiming for an &lt;strong&gt;excellent user experience&lt;/strong&gt;, notably with functions such as screen reader assistance, keyboard controls, focus handling, language translations, and additional features. It's also helpful to consider when you want &lt;strong&gt;accessible components&lt;/strong&gt; out of the box that utilize ARIA attributes and roles.&lt;/p&gt;

&lt;p&gt;React Aria is suitable for projects where you prioritize &lt;strong&gt;accessibility&lt;/strong&gt;, &lt;strong&gt;customization&lt;/strong&gt;, and &lt;strong&gt;meeting the needs of modern web applications&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Offers over &lt;strong&gt;40 components with built-in behavior, adaptive interactions, accessibility, and internationalization&lt;/strong&gt;, ready for custom styles.&lt;/li&gt;
&lt;li&gt;Provides an &lt;strong&gt;excellent user experience&lt;/strong&gt;, notably with functions such as screen reader assistance, keyboard controls, focus handling, language translations, and additional features.&lt;/li&gt;
&lt;li&gt;Provides &lt;strong&gt;accessible components&lt;/strong&gt; out of the box that utilize ARIA attributes and roles.&lt;/li&gt;
&lt;li&gt;Prioritizes &lt;strong&gt;accessibility from the ground up&lt;/strong&gt;, helping developers build inclusive applications that cater to users with disabilities.&lt;/li&gt;
&lt;li&gt;Evolves to &lt;strong&gt;meet the needs of modern web applications&lt;/strong&gt; by focusing on accessibility, performance, and developer experience.&lt;/li&gt;
&lt;li&gt;ARIA attributes are useful for Stylish and Greasemonkey because it's the only semantic way to target specific tags.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;React Aria prioritizes accessibility from the ground up, helping developers build inclusive applications that cater to users with disabilities. By focusing on accessibility, performance, and developer experience, React Aria evolves to meet the needs of modern web applications.&lt;/p&gt;

&lt;p&gt;In the React community, there is the perspective that React Aria, with Tailwind CSS, makes ARIA attributes useful for Stylish and Greasemonkey because it's the only semantic way to target specific tags.&lt;/p&gt;

&lt;h2&gt;
  
  
  Base UI
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://base-ui.com/" rel="noopener noreferrer"&gt;https://base-ui.com/&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Base UI is known for providing unstyled, accessible components&lt;/strong&gt;. It's designed to be a starting point for custom designs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Unstyled, accessible components&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tree-shakeable architecture&lt;/strong&gt; for optimized bundle sizes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexible styling options&lt;/strong&gt; (works with CSS Modules, Tailwind, or any CSS-in-JS solution)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in portal system&lt;/strong&gt; for complex components like modals and popovers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TypeScript support&lt;/strong&gt; out of the box&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Cases&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Base UI is useful when providing &lt;strong&gt;unstyled, accessible components&lt;/strong&gt;. It is also helpful as &lt;strong&gt;a starting point for custom designs&lt;/strong&gt;. Furthermore, Base UI is helpful because of its &lt;strong&gt;tree-shakeable architecture&lt;/strong&gt; for optimized bundle sizes and its &lt;strong&gt;flexible styling options&lt;/strong&gt; (works with CSS Modules, Tailwind, or any CSS-in-JS solution). In addition, Base UI has a built-in portal system for complex components like modals and popovers and supports TypeScript out of the box.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Offers &lt;strong&gt;unstyled, accessible components&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Has a &lt;strong&gt;tree-shakeable architecture&lt;/strong&gt; for optimized bundle sizes.&lt;/li&gt;
&lt;li&gt;Offers &lt;strong&gt;flexible styling options&lt;/strong&gt;, making it compatible with CSS Modules, Tailwind, or any CSS-in-JS solution.&lt;/li&gt;
&lt;li&gt;Includes a &lt;strong&gt;built-in portal system&lt;/strong&gt; for complex components such as modals and popovers.&lt;/li&gt;
&lt;li&gt;Provides &lt;strong&gt;TypeScript support&lt;/strong&gt; out of the box.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Base UI is relatively new and designed to be a starting point for custom designs.&lt;/p&gt;

&lt;p&gt;Other Notable Libraries&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://primereact.org/" rel="noopener noreferrer"&gt;PrimeReact&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://onsen.io/" rel="noopener noreferrer"&gt;Onsen UI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tailwindui.com/" rel="noopener noreferrer"&gt;Tailwind UI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://coreui.io/" rel="noopener noreferrer"&gt;Core UI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blueprintjs.com/" rel="noopener noreferrer"&gt;Blueprint UI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rsuitejs.com/" rel="noopener noreferrer"&gt;React Suite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marmelab.com/react-admin/" rel="noopener noreferrer"&gt;React Admin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://park-ui.com/" rel="noopener noreferrer"&gt;Park UI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://magicui.design/" rel="noopener noreferrer"&gt;Magic UI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rebass-v3.vercel.app/" rel="noopener noreferrer"&gt;Rebass&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.material-tailwind.com/" rel="noopener noreferrer"&gt;Material Tailwind - React&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.creative-tim.com/product/material-kit-react" rel="noopener noreferrer"&gt;Material Kit React&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://react-fabric.github.io/#/" rel="noopener noreferrer"&gt;React Fabric&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://react-toolbox.io/#/" rel="noopener noreferrer"&gt;React Toolbox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ariakit.org/" rel="noopener noreferrer"&gt;Aria Kit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ark-ui.com/" rel="noopener noreferrer"&gt;Ark UI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://reach.tech/" rel="noopener noreferrer"&gt;Reach UI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;When to use a React component library&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Using React component libraries can be a compelling choice for developers because they offer numerous advantages. However, the decision to use a component library should be based on the project and its specific requirements.&lt;/p&gt;

&lt;p&gt;When to consider using a React component library:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Implementing common UI patterns&lt;/strong&gt; React component libraries provide pre-built UI components that implement common UI patterns, saving developers time and effort.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ensuring consistency&lt;/strong&gt; Component libraries help ensure a consistent look and feel across projects, which is especially beneficial for large teams working on multiple projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Needing a Beautiful UI&lt;/strong&gt; UI libraries include nicely designed, ready-to-use components as application building blocks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reducing development costs&lt;/strong&gt; Using pre-built components can reduce overall development costs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Increasing productivity&lt;/strong&gt; Component libraries save time and effort, allowing developers to focus on more complex aspects of applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reducing risk&lt;/strong&gt; Well-tested and maintained libraries reduce the risk of introducing bugs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When Lacking Design Knowledge:&lt;/strong&gt; If you have an intuitive design idea but lack design knowledge, component libraries allow the creation of stunning layouts and rich user experiences.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Building administrative panels&lt;/strong&gt; Component libraries can help create functional and understandable user interfaces, and implement standard back-office apps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Having aligned interest projects:&lt;/strong&gt; It is important to ensure that all project participants are on the same page. Discuss the library’s benefits and downsides after the designer and client agree on the library and before proceeding. Start by explaining library functions to handle client expectations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For rapid prototyping&lt;/strong&gt; UI component libraries allow faster prototyping because implementation is faster. They help build user interfaces and test functionality with minimal resources.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, there are potential challenges to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Misunderstanding the library's philosophy&lt;/strong&gt; Each UI component has its ideology, which you must comprehend to implement it properly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inconsistent use&lt;/strong&gt; Developers must utilize React UI component libraries consistently to learn how they function. Switching component libraries takes time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Predetermined choices&lt;/strong&gt; React UI library selection for your projects must be flexible, as some libraries may not suit all projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In conclusion, &lt;strong&gt;React UI component libraries are essential tools&lt;/strong&gt;, offering a wide array of pre-built and customizable components that can significantly enhance development speed, ensure design consistency, and improve the overall user experience.&lt;/p&gt;

&lt;p&gt;Choosing the right library is a ****critical decision that should align with the specific requirements, design goals, and technical constraints of your project. Factors to consider include project needs, longevity, learning curve, customizability, community support, documentation, and performance.&lt;/p&gt;

&lt;p&gt;The rise of &lt;strong&gt;headless UI libraries&lt;/strong&gt; offers developers greater flexibility and control over styling, with libraries like Radix UI and Headless UI gaining popularity. &lt;strong&gt;Accessibility&lt;/strong&gt; has become a key focus, with many libraries now incorporating built-in accessibility features to ensure applications are usable by everyone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI integration&lt;/strong&gt; and &lt;strong&gt;innovative approaches&lt;/strong&gt; like Shadcn UI's copy-and-paste component code are emerging trends, further streamlining development and customization. While each library offers its unique strengths, the ultimate choice depends on the project's specific needs and priorities.&lt;/p&gt;

&lt;p&gt;See you next time!&lt;/p&gt;

&lt;p&gt;Luca&lt;/p&gt;

</description>
      <category>react</category>
      <category>web</category>
      <category>design</category>
      <category>ui</category>
    </item>
    <item>
      <title>How to validate your Next.js API with Zod and Typescript</title>
      <dc:creator>Luca Restagno</dc:creator>
      <pubDate>Tue, 03 Dec 2024 21:09:13 +0000</pubDate>
      <link>https://dev.to/ikoichi/how-to-validate-your-nextjs-api-with-zod-and-typescript-2bhl</link>
      <guid>https://dev.to/ikoichi/how-to-validate-your-nextjs-api-with-zod-and-typescript-2bhl</guid>
      <description>&lt;p&gt;Next.js is a popular React framework known for building end-to-end web applications. It enables developers to manage both the front-end and back-end of a project within a unified codebase, simplifying development and maintenance.&lt;/p&gt;

&lt;p&gt;When building web APIs, input validation becomes crucial because your routes may be consumed by various clients. These clients could range from the React UI you’re developing to external systems accessing your public APIs. Ensuring that your API only processes valid data is important for maintaining security and reliability, especially when inputs come from sources beyond your control.&lt;/p&gt;

&lt;p&gt;Zod is a popular library in the JavaScript and TypeScript ecosystem for schema validation. It offers an intuitive and expressive API, allowing you to define the structure (or schema) of your data and enforce validation rules. Zod is widely integrated with other tools and libraries, such as &lt;code&gt;react-hook-form&lt;/code&gt; for form handling, &lt;code&gt;tRPC&lt;/code&gt; for building type-safe APIs, and &lt;code&gt;zod-to-json-schema&lt;/code&gt; for generating JSON Schema definitions, making it a versatile choice for developers.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Why Validate API Inputs?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Input validation is important for enhancing the reliability and security of your software. It helps safeguard your application by preventing common vulnerabilities like injection attacks, cross-site scripting (XSS), and denial-of-service (DoS) exploits.&lt;/p&gt;

&lt;p&gt;Beyond security, validation also prevents application errors caused by invalid or unsupported data. Without proper checks, your API might encounter unexpected values or incorrect types, leading to runtime errors, application crashes, or unpredictable behavior. Ensuring only valid data reaches your code minimizes these risks and keeps your application running smoothly.&lt;/p&gt;

&lt;h3&gt;
  
  
  How can I use Zod?
&lt;/h3&gt;

&lt;p&gt;The key features of Zod are schema declaration, parsing, and type inference. Let’s see how to use Zod and how to leverage them.&lt;/p&gt;

&lt;p&gt;Let’s start by installing &lt;code&gt;zod&lt;/code&gt; into your project.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;With Zod we can create the schema definition of an object, like this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&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;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Name is required&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid email format&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;gte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Must be 18 or older&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;p&gt;This code defines the schema of an object with a mandatory &lt;code&gt;name&lt;/code&gt; property, a valid &lt;code&gt;email&lt;/code&gt; address, and a numeric integer value &lt;code&gt;age&lt;/code&gt;, greater than or equals to 18.&lt;/p&gt;

&lt;p&gt;With Zod you can also define the error message when the value provided doesn’t satisfy the conditions.&lt;/p&gt;

&lt;p&gt;Now that we have a schema definition, let’s parse an object to validate it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Luca&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hey@shipped.club&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;38&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;validatedUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userSchema&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;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the object provided is not correct, &lt;code&gt;.parse()&lt;/code&gt; throws an error.&lt;/p&gt;

&lt;p&gt;If you want to avoid throwing an error, you can use &lt;code&gt;.safeParse()&lt;/code&gt; that returns an object instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;userSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;safeParse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// =&amp;gt; { success: false; error: ZodError }&lt;/span&gt;

&lt;span class="nx"&gt;userSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;safeParse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// =&amp;gt; { success: true; data: { ...user } }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, you can infer the TypeScript types from your schema!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;userSchema&lt;/span&gt;&lt;span class="o"&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;
  
  
  How to use Zod in my Next.js App Route
&lt;/h3&gt;

&lt;p&gt;Now, let’s create a Next.js API POST route that receives a body payload that we want to validate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&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="c1"&gt;// Parse the request body&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;body&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;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userSchema&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;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Business logic here (e.g., save to database)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Registration successful&lt;/span&gt;&lt;span class="dl"&gt;'&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="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="mi"&gt;200&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &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="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;error&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ZodError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Return validation errors&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Validation error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;errors&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;errors&lt;/span&gt; &lt;span class="p"&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="mi"&gt;400&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="c1"&gt;// Handle unexpected errors&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Something went wrong&lt;/span&gt;&lt;span class="dl"&gt;'&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="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="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="mi"&gt;500&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This POST method receives a JSON payload, it reads and parses it through the Zod schema that we defined.&lt;/p&gt;

&lt;p&gt;If the validation succeeds, we can process the data, otherwise we return a validation error.&lt;/p&gt;

&lt;p&gt;This way we can ensure that our business logic uses only valid data.&lt;/p&gt;

&lt;p&gt;Zod works particularly well with Next.js, because you can define the Schema for the data expected on the API routes, and reuse the same schema and types when you need to build the same object on the frontend, to perform the request.&lt;/p&gt;

&lt;p&gt;Here’s an example of a React component that sends a POST request, using userSchema to validate the values provided by the user in a form.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// import the schema and inferred type created with Zod&lt;/span&gt;
&lt;span class="c1"&gt;// 👇👇👇&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;userSchema&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;User&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../schemas/userSchema&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;RegisterForm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setFormData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Default age&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&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;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSuccess&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&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;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&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;handleChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ChangeEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLInputElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&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;target&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Update state dynamically based on input name&lt;/span&gt;
    &lt;span class="nf"&gt;setFormData&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;age&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}));&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSubmit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FormEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&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="c1"&gt;// Validate the form data using the Zod schema&lt;/span&gt;
      &lt;span class="c1"&gt;// 👇👇👇&lt;/span&gt;
      &lt;span class="nx"&gt;userSchema&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;formData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// Send the POST request&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="s1"&gt;/api/register&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="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="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="s1"&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="s1"&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="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="nx"&gt;formData&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;response&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="nf"&gt;setSuccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Registration successful!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;errorResponse&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errorResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to register&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;setSuccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="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="na"&gt;err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&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;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// get all errors from Zod, and concatenate them in a string&lt;/span&gt;
        &lt;span class="nf"&gt;setError&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="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&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;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="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;An unexpected error occurred&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nf"&gt;setSuccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Register&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;green&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt; &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            Name:
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            Email:
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            Age:
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"number"&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"age"&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;To test your validation, you can use cURL in the terminal or Postman if you prefer to use a user interface.&lt;/p&gt;

&lt;p&gt;With cURL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;curl&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;X&lt;/span&gt; &lt;span class="nx"&gt;POST&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:3000/api/register \&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;H&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type: application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{"name": "Luca", "email": "hey@shipped.club", "age": 38}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusions
&lt;/h3&gt;

&lt;p&gt;I encourage you to use Zod extensively in your codebase, and to use it to define your types whenever you need validation or when you expose an interface to another client of your architecture, like a private or public API.&lt;/p&gt;

&lt;p&gt;Zod is extremely useful and expressive, it allows you to define complex data types and validation rules. You can read the full &lt;a href="https://github.com/colinhacks/zod" rel="noopener noreferrer"&gt;documentation on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope this article was useful, and helped you level up your coding skills.&lt;/p&gt;

&lt;p&gt;Cheers,&lt;br&gt;
Luca&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>typescript</category>
      <category>nextjs</category>
      <category>api</category>
    </item>
    <item>
      <title>How I Solved Common Prisma ORM Errors: Debugging Tips and Best Practices</title>
      <dc:creator>Luca Restagno</dc:creator>
      <pubDate>Sun, 01 Dec 2024 12:23:47 +0000</pubDate>
      <link>https://dev.to/ikoichi/how-i-solved-common-prisma-orm-errors-debugging-tips-and-best-practices-1505</link>
      <guid>https://dev.to/ikoichi/how-i-solved-common-prisma-orm-errors-debugging-tips-and-best-practices-1505</guid>
      <description>&lt;p&gt;The &lt;a href="https://www.prisma.io/" rel="noopener noreferrer"&gt;Prisma ORM&lt;/a&gt; is a powerful companion for every software engineer, indie maker, and SaaS founder who wants to add type safety to the queries executed on the database.&lt;/p&gt;

&lt;p&gt;I have been using Prisma for the last 2 years, and I have experience on troubleshooting different type of errors.&lt;/p&gt;

&lt;p&gt;In this article, I want to share it with you, so you don’t have to spend hours figuring out what I’ve already learned.&lt;/p&gt;

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

&lt;p&gt;I have been using Prisma for all my SaaS products. So far, I’ve built six SaaS products, and I hope to build more in the future (some of them are &lt;a href="https://blacktwist.app" rel="noopener noreferrer"&gt;BlackTwist&lt;/a&gt;, &lt;a href="https://usewuf.com" rel="noopener noreferrer"&gt;Wuf&lt;/a&gt;, &lt;a href="https://userdesk.io" rel="noopener noreferrer"&gt;Userdesk&lt;/a&gt;, &lt;a href="https://inboxs.io" rel="noopener noreferrer"&gt;Inboxs&lt;/a&gt;, &lt;a href="https://hivoe.com" rel="noopener noreferrer"&gt;Hivoe&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;And the Prisma ORM is also part of the SaaS Boilerplate I’ve built, called &lt;a href="http://shipped.club" rel="noopener noreferrer"&gt;Shipped.club&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The reason is simple, I want you to leverage the tools I have experience on, so that I can help the customers in the private Discord community, that’s available after the purchase.&lt;/p&gt;

&lt;p&gt;The key goals of using Prisma are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;keep under control your database schema

&lt;ul&gt;
&lt;li&gt;define tables and types&lt;/li&gt;
&lt;li&gt;apply migrations&lt;/li&gt;
&lt;li&gt;query your database with type safety&lt;/li&gt;
&lt;li&gt;avoid typing errors&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;protect from SQL injection&lt;/li&gt;

&lt;li&gt;leverage pooling&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Common issues
&lt;/h2&gt;

&lt;p&gt;Despite being a stable product, sometimes you can encounter some issues.&lt;/p&gt;

&lt;p&gt;Below I describe two common errors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;migration errors&lt;/li&gt;
&lt;li&gt;query errors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s start with the first one&lt;/p&gt;

&lt;h3&gt;
  
  
  Error with data migrations
&lt;/h3&gt;

&lt;p&gt;Sometimes your migrations emit an error, that’s not very simple to debug, like this one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nb"&gt;Error&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;prepared&lt;/span&gt; &lt;span class="nx"&gt;statement&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;s2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;does&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;exist&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You usually get this error when you run &lt;code&gt;npx prisma db push&lt;/code&gt; (apply your schema changes to the database) or &lt;code&gt;npx prisma generate&lt;/code&gt; (generate the types from your schema).&lt;/p&gt;

&lt;p&gt;But what this means?&lt;/p&gt;

&lt;p&gt;This error happens when using a relational database, like &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;PostgreSQL&lt;/a&gt; (one of the most popular, and advanced open-source SQL databases on the market).&lt;/p&gt;

&lt;p&gt;Specifically, a prepared statement in PostgreSQL is a feature that allows you to execute a query plan that is prepared and stored by the database server for reuse. It improves performance and security, especially when executing the same query multiple times with different parameter values.&lt;/p&gt;

&lt;p&gt;Prisma ORM leverages the prepared statements as part of its database query execution process, under the hood (but you don’t have to know or master prepared statements to use Prisma).&lt;/p&gt;

&lt;p&gt;The main issues arise with the confusion between the different database connections string configurations, pooling and PgBouncer.&lt;/p&gt;

&lt;p&gt;Let me go straight to the solution, then I explain you the different parts.&lt;/p&gt;

&lt;p&gt;The main solution I’ve found is to use two connection strings, one to run the migrations and the second for the execution of your web application / node.js server.&lt;/p&gt;

&lt;p&gt;First, identify the correct connection strings for your database.&lt;/p&gt;

&lt;p&gt;The connection string to run the migrations is the direct access to the database (no pooling or PgBouncer), like for instance&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;postgresql&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//username:password@host:5432/dbname&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save this connection string as an environment variable called &lt;code&gt;DATABASE_DIRECT_URL&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;DATABASE_DIRECT_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;postgresql://username:password@host:5432/dbname&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add it to your local &lt;code&gt;.env&lt;/code&gt; file and to your hosting service (Vercel, Netlify, Render, and so on).&lt;/p&gt;

&lt;p&gt;Secondly, get the connection string with the pool, for instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;postgresql&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//user:password@host:post/poolName&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Get this connection string from your database hosting provider, the parameters might be different.&lt;/p&gt;

&lt;p&gt;Save this connection string as an environment variables called &lt;code&gt;DATABASE_URL&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;postgresql://user:password@host:post/poolName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add it to your local &lt;code&gt;.env&lt;/code&gt; file and to your hosting service (Vercel, Netlify, Render, and so on).&lt;/p&gt;

&lt;p&gt;The second step is to update the Prisma configuration to use these two environment variables.&lt;/p&gt;

&lt;p&gt;Open the file &lt;code&gt;schema.prisma&lt;/code&gt; and update the section &lt;code&gt;datasource db&lt;/code&gt; to include this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;datasource&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;provider&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;postgresql&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;url&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;directUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DATABASE_DIRECT_URL&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;p&gt;Now, run the usual commands like &lt;code&gt;npx prisma db push&lt;/code&gt; and &lt;code&gt;npx prisma generate&lt;/code&gt; locally to ensure that everything is working correctly, and run your application locally.&lt;/p&gt;

&lt;p&gt;If all is good, push the modifications to your hosting service and trigger a new deployment for the modifications to take effect.&lt;/p&gt;

&lt;p&gt;Prisma is now correctly configured and you should not have the same issue again.&lt;/p&gt;

&lt;h3&gt;
  
  
  Query performance issues
&lt;/h3&gt;

&lt;p&gt;Recently, I got the "stack depth limit exceeded" error message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;PrismaClientUnknownRequestError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Invalid&lt;/span&gt; &lt;span class="s2"&gt;`prisma.table.findMany()`&lt;/span&gt; &lt;span class="nx"&gt;invocation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="nx"&gt;occurred&lt;/span&gt; &lt;span class="nx"&gt;during&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="nx"&gt;execution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ConnectorError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ConnectorError&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;user_facing_error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;QueryError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PostgresError&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;54001&lt;/span&gt;&lt;span class="dl"&gt;"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stack depth limit exceeded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;severity&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="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Increase the configuration parameter &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;max_stack_depth&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; (currently 2048kB), after ensuring the platform's stack depth limit is adequate.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="nx"&gt;transient&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means that the usage of memory exceeds the database configuration for a specific query.&lt;/p&gt;

&lt;p&gt;I ran this SQL command on my database and found this value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;SHOW&lt;/span&gt; &lt;span class="nx"&gt;max_stack_depth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;---&lt;/span&gt;
&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="nx"&gt;MB&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I had a query that was returning 1900+ records to aggregate some values.&lt;/p&gt;

&lt;p&gt;For each record I have to recalculate the sum of certain values.&lt;/p&gt;

&lt;p&gt;When this happens you have two options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;increase the &lt;code&gt;max_stack_depth&lt;/code&gt; value in your database&lt;/li&gt;
&lt;li&gt;refactor the logic in the code to avoid to run that big query&lt;/li&gt;
&lt;li&gt;optimize the query&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I tried to increase &lt;code&gt;max_stack_depth&lt;/code&gt; because it was the quickest solution (not the best one), but my database is hosted on DigitalOcean and I didn’t have the permissions to run the &lt;code&gt;ALTER&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;ALTER&lt;/span&gt; &lt;span class="nx"&gt;SYSTEM&lt;/span&gt; &lt;span class="nx"&gt;SET&lt;/span&gt; &lt;span class="nx"&gt;max_stack_depth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4MB&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="nx"&gt;permission&lt;/span&gt; &lt;span class="nx"&gt;denied&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="kd"&gt;set&lt;/span&gt; &lt;span class="nx"&gt;parameter&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;max_stack_depth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(I contacted DigitalOcean via a support ticket and they promptly provided a solution, I can alter the value using their web API).&lt;/p&gt;

&lt;p&gt;Then, I started to analyze the problem.&lt;/p&gt;

&lt;p&gt;The first thing I tried was to run the same query as plain SQL against the database using &lt;a href="https://www.pgadmin.org/" rel="noopener noreferrer"&gt;pgAdmin&lt;/a&gt;, and it perfectly worked.&lt;/p&gt;

&lt;p&gt;This was suspicious, it means that probably Prisma was executing a query too complex and expensive.&lt;/p&gt;

&lt;p&gt;Then, I refactored the code, using the Prisma method &lt;code&gt;$queryRaw&lt;/code&gt; to run the same query, and it worked!&lt;/p&gt;

&lt;p&gt;At this point, I didn’t want to manually define all the type for the values returned by the query, and I thought of using a new cool feature of Prisma called &lt;a href="https://www.prisma.io/docs/orm/prisma-client/using-raw-sql/typedsql" rel="noopener noreferrer"&gt;TypedSQL&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This way I can run a Raw Query against the database with the types automatically generated by Prisma for me.&lt;/p&gt;

&lt;p&gt;So, in the end, I refactored to code, and avoided to increase the value &lt;code&gt;max_stack_depth&lt;/code&gt; that would have increased the memory consumption in general.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;I hope that this article was useful, and it avoids you from spending hours on troubleshooting these kind of errors with Prisma.&lt;/p&gt;

&lt;p&gt;Overall my experience with the tool has been very good and exciting, and I see how they are releasing new versions,  features and improvements.&lt;/p&gt;

&lt;p&gt;You can find the &lt;a href="https://www.prisma.io/docs" rel="noopener noreferrer"&gt;documentation of Prisma at this link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As a side note, I’m not affiliated with Prisma in any way, I’m just a happy user of the product.&lt;/p&gt;

&lt;p&gt;Cheers,&lt;/p&gt;

&lt;p&gt;Luca&lt;/p&gt;

</description>
      <category>prisma</category>
      <category>webdev</category>
      <category>database</category>
      <category>postgres</category>
    </item>
    <item>
      <title>How to protect your Next.js Routes with reCAPTCHA</title>
      <dc:creator>Luca Restagno</dc:creator>
      <pubDate>Sun, 26 May 2024 06:58:04 +0000</pubDate>
      <link>https://dev.to/ikoichi/how-to-protect-your-nextjs-routes-with-recaptcha-4p3k</link>
      <guid>https://dev.to/ikoichi/how-to-protect-your-nextjs-routes-with-recaptcha-4p3k</guid>
      <description>&lt;p&gt;Protecting the public endpoints of your web app, is one of the most important tasks you could do.&lt;/p&gt;

&lt;p&gt;Even if you don’t expect much traffic on your websites, malicious attempts can always happen.&lt;/p&gt;

&lt;p&gt;It happened to me when I launched a waitlist website, I didn’t expect many eyes to visit the page, but someone noticed the &lt;code&gt;/api/waitlist&lt;/code&gt; endpoint, I used to collect the email of the interested users, and they started to call it repeatedly.&lt;/p&gt;

&lt;p&gt;One of the easiest mitigations is to add a captcha challenge to the web user interface.&lt;/p&gt;

&lt;p&gt;There are different types of captchas, and they have evolved quite a lot over the last few years.&lt;/p&gt;

&lt;p&gt;Usually, they are visual quizzes or simple puzzles (called challenges) to solve to unlock a feature on a website.&lt;/p&gt;

&lt;p&gt;This is an example, select all square images with traffic lights.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxmrqvybktaxasdha9n28.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxmrqvybktaxasdha9n28.jpeg" alt="captcha" width="800" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Robots can’t solve these puzzles, therefore the backend request doesn’t start.&lt;/p&gt;

&lt;p&gt;But how can you protect your backend with a puzzle solved on the frontend?&lt;/p&gt;

&lt;h2&gt;
  
  
  How Captcha Protection Works
&lt;/h2&gt;

&lt;p&gt;This is how it works.&lt;/p&gt;

&lt;p&gt;When the puzzle is successfully solved, the captcha service delivers a &lt;code&gt;token&lt;/code&gt; (a string).&lt;/p&gt;

&lt;p&gt;This token is unique for the puzzle resolution of a user, and you need to send it to your backend.&lt;/p&gt;

&lt;p&gt;In your backend, you need to validate the token, by calling the captcha service backend.&lt;/p&gt;

&lt;p&gt;In this article, I show you how you can implement a captcha protection using on the most famous service reCAPTCHA by Google and your Next.js website.&lt;/p&gt;

&lt;p&gt;reCAPTCHA by Google has been improved over time, and the latest version of it, version 3, doesn’t require every user to solve the challenge is the proprietary algorithm of Google doesn’t recognize a suspect client.&lt;/p&gt;

&lt;p&gt;Which is a great news for our real users!&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a reCAPTCHA
&lt;/h2&gt;

&lt;p&gt;First of all, create a reCAPTCHA. Visit the website &lt;a href="https://www.google.com/recaptcha/about/"&gt;https://www.google.com/recaptcha/about/&lt;/a&gt; and access the v3 Admin Console.&lt;/p&gt;

&lt;p&gt;Once in, click on the “+” plus icon to create a new reCAPTCHA.&lt;/p&gt;

&lt;p&gt;Add the label and the domain of your website.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffwj6vza30g3k20mr6i9z.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffwj6vza30g3k20mr6i9z.jpeg" alt="create captcha" width="800" height="1122"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can select v3 (score based) or v2.&lt;/p&gt;

&lt;p&gt;v2 always asks for a challenge, while v3 asks for a challenge only if the user score, automatically calculated, is not high. I select v3.&lt;/p&gt;

&lt;p&gt;Click on Submit.&lt;/p&gt;

&lt;p&gt;Now Google gives you the Site Key and the Secret Key. Copy them in a secure place.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71qs5sxuz3gb6ipdu2oz.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71qs5sxuz3gb6ipdu2oz.jpeg" alt="recaptcha keys" width="800" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let’s create two environment variables.&lt;/p&gt;

&lt;p&gt;Usually you have a .env file for your local development and you need to set them on your hosting solution, like Vercel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;NEXT_PUBLIC_RECAPTCHA_SITE_KEY="you_site_key"&lt;/span&gt;
&lt;span class="s"&gt;RECAPTCHA_SECRET_KEY="your_secret_key"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that one environment variables is prefixed with &lt;code&gt;NEXT_PUBLIC_&lt;/code&gt; while the other not.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;NEXT_PUBLIC_RECAPTCHA_SITE_KEY&lt;/code&gt; is accessible from the frontend, and therefore it’s publicly visible, while &lt;code&gt;RECAPTCHA_SECRET_KEY&lt;/code&gt; will be accessible only by the backend code, and therefore no one can read the value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create your client component
&lt;/h2&gt;

&lt;p&gt;Now, let’s create a Next.js client component with an input field and a button.&lt;/p&gt;

&lt;p&gt;For a waitlist it would look like this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; 
    &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"your@email.com"&lt;/span&gt;
    &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setEmail&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;target&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="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
        &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onAddToWaitlist&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    Join the waitlist
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we need to implement &lt;code&gt;onAddToWaitlist&lt;/code&gt; so that it calls the reCAPTCHA service.&lt;/p&gt;

&lt;p&gt;To integrate reCAPTCHA you need to integrate the Google JavaScript script.&lt;/p&gt;

&lt;p&gt;Open your &lt;code&gt;layout.tsx&lt;/code&gt; file (if you are using the App Router) and add this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;
    &lt;span class="na"&gt;defer&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text/javascript"&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`https://www.google.com/recaptcha/api.js?render=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_RECAPTCHA_SITE_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, the JavaScript object &lt;code&gt;grecaptcha&lt;/code&gt; will be globally available in our web app.&lt;/p&gt;

&lt;p&gt;Let’s implement &lt;code&gt;onAddToWaitlist&lt;/code&gt;&lt;br&gt;
&lt;/p&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;onAddToWaitlist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// @ts-ignore&lt;/span&gt;
    &lt;span class="nx"&gt;grecaptcha&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// @ts-ignore&lt;/span&gt;
      &lt;span class="nx"&gt;grecaptcha&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_RECAPTCHA_SITE_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;token&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="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;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;axios&lt;/span&gt;
              &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&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/waitlist&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;captchaToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="p"&gt;})&lt;/span&gt;
              &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                                &lt;span class="c1"&gt;// success&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="c1"&gt;// error&lt;/span&gt;
              &lt;span class="p"&gt;})&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I used &lt;code&gt;axios&lt;/code&gt; because it’s comfortable to use, but you can use &lt;code&gt;fetch&lt;/code&gt; as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Protect your API route
&lt;/h2&gt;

&lt;p&gt;At this point, we are only missing the backend api route (&lt;code&gt;src/app/api/waitlist/route.ts&lt;/code&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HttpStatusCode&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;qs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;qs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&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;body&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;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&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;captchaToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;captchaToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;captchaToken&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;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unauthorized&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;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpStatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Unauthorized&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;email&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;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Email is required&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;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpStatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BadRequest&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;options&lt;/span&gt; &lt;span class="o"&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/x-www-form-urlencoded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;qs&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;secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RECAPTCHA_SECRET_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;captchaToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://www.google.com/recaptcha/api/siteverify&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;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;axios&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;response&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;success&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unauthorized&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;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpStatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Unauthorized&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="c1"&gt;// the captcha token is valid&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Captchas are one of the most effective ways to protect a website, and the easiest solution to implement.&lt;/p&gt;

&lt;p&gt;The captcha service from Google has improved a lot lately, and it doesn’t always require to solve a challenge to our users, which is perfect to provide them a great user experience.&lt;/p&gt;

&lt;p&gt;I hope this was useful.&lt;/p&gt;

&lt;p&gt;Cheers&lt;/p&gt;

</description>
    </item>
    <item>
      <title>6 Profitable Micro SaaS Ideas in 2024</title>
      <dc:creator>Luca Restagno</dc:creator>
      <pubDate>Fri, 24 May 2024 12:50:07 +0000</pubDate>
      <link>https://dev.to/ikoichi/6-profitable-micro-saas-ideas-in-2024-55cl</link>
      <guid>https://dev.to/ikoichi/6-profitable-micro-saas-ideas-in-2024-55cl</guid>
      <description>&lt;p&gt;The term MicroSaaS refers to a category of software-as-a-service (SaaS) businesses that target a narrow, niche market with specialized software solutions.&lt;/p&gt;

&lt;p&gt;Some of the key characteristics that define a MicroSaaS are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Niche Focus&lt;/strong&gt;: MicroSaaS businesses typically address a specific problem or serve a specialized segment of users within a larger industry. This focus allows them to meet the needs of a particular customer base very effectively.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Small Team or Solo Founder&lt;/strong&gt;: Unlike larger SaaS companies, MicroSaaS businesses often operate with very small teams, sometimes just a solo founder. This lean operation helps keep costs low while maximizing flexibility and responsiveness to customer needs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Low Overhead&lt;/strong&gt;: Due to the small team size and niche focus, MicroSaaS companies generally have low operational costs. They often use existing platforms and technologies to reduce the need for heavy infrastructure investment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subscription Model&lt;/strong&gt;: Like other SaaS businesses, MicroSaaS companies typically rely on a subscription-based revenue model, where users pay a recurring fee to use the software.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated and Efficient&lt;/strong&gt;: These businesses strive to be highly automated, minimizing manual processes and relying on digital tools to manage customer relations, billing, and service delivery.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Global Reach&lt;/strong&gt;: Despite their small size, MicroSaaS businesses often serve a global customer base, enabled by the internet and cloud computing technologies that allow them to reach customers anywhere.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Due to its characteristics, MicroSaaS products perfectly fit the needs of professionals who want to get started with entrepreneurship, even on the side of a full-time job.&lt;/p&gt;

&lt;p&gt;In this article, I describe the most interesting MicroSaaS product ideas, already validated on the market, and that you can use to start making money online.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. SEO Indexer
&lt;/h2&gt;

&lt;p&gt;SEO is one of the most important distribution channels for companies. They invest a ton of money to create content, that needs to be indexed by Google, to be served in the search results to the queries of the users.&lt;/p&gt;

&lt;p&gt;A popular technique to create content in a relatively amount of time is &lt;strong&gt;programmatic SEO (pSEO)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Programmatic SEO is a strategy that involves using software and automation to generate a large number of pages optimized for search engines, typically targeting long-tail keywords. This approach is especially useful for websites that have the potential to rank for numerous search queries due to the breadth of topics they cover, such as e-commerce sites, travel booking sites, or any service with a wide range of products or offerings.&lt;/p&gt;

&lt;p&gt;The problem that companies face, is that Google takes time to index all the pages, and this process can easily take weeks, if not months, even if the new pages are present in the sitemap of the website.&lt;/p&gt;

&lt;p&gt;Google allows you to manually submit the pages via the Google Search Console, but there’s a limit of 20 pages per day.&lt;/p&gt;

&lt;p&gt;This process is time-consuming and can be automated via the Google APIs.&lt;/p&gt;

&lt;p&gt;You can build a MicroSaaS that asks for a sitemap of a website, and periodically submits the new pages to Google until they are all indexed.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. SEO Keywords Research
&lt;/h2&gt;

&lt;p&gt;Content creation is the key activity of SEO. Companies create huge amounts of content to satisfy the search intent of the users on the search engines, and drive traffic to their websites.&lt;/p&gt;

&lt;p&gt;creating the right content and targeting the right keywords requires a certain amount of analytics, which is called keyword research.&lt;/p&gt;

&lt;p&gt;The key information needed by companies are keywords related to specific topics, the amount of traffic, and the difficulty of ranking.&lt;/p&gt;

&lt;p&gt;There are some very established products in the market like ahrefs or SEMrush, but they are quite expensive, and keyword research is a critical aspect for companies.&lt;/p&gt;

&lt;p&gt;Google provides an API to retrieve this information, the &lt;a href="https://developers.google.com/adwords/api/docs/guides/targeting-idea-service#use_case"&gt;Ads Targeting Idea Service and Traffic Estimator Service&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These properties make SEO Keyword search MicroSaaS one of the most interesting product ideas.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Social Animations
&lt;/h2&gt;

&lt;p&gt;Social media platforms are one of the most common channels used by professionals, creators, agencies, and SaaS owners, to find potential customers for their businesses.&lt;/p&gt;

&lt;p&gt;These platforms show a feed of content, and everyone needs to compete with the others for the attention of the users.&lt;/p&gt;

&lt;p&gt;And as you can imagine, nothing works better than an eye-catching video.&lt;/p&gt;

&lt;p&gt;For instance, the platform X (former Twitter) increases the reach of the content, based on the amount of time people spend looking at it. If you publish a post with text and a video, the latter will catch the attention of people scrolling through the feed, and later they will read the text of the post.&lt;/p&gt;

&lt;p&gt;The MicroSaaS idea consists of a platform to easily and quickly generate video animations, video predefined templates for different situations and celebrations like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;new number of follower milestone&lt;/li&gt;
&lt;li&gt;new launch on Product Hunt&lt;/li&gt;
&lt;li&gt;new revenues milestone&lt;/li&gt;
&lt;li&gt;and so on&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Save people’s time and increase their content reach via video animations.&lt;/p&gt;

&lt;p&gt;The fact that the output of your MicroSaaS is video, shared on social media platforms, will create a product-led growth mechanism. People will notice the video, ask for the source of it, and discover your product.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Screenshots Maker
&lt;/h2&gt;

&lt;p&gt;Like videos, screenshots are the most common and used media on social media (and not only).&lt;/p&gt;

&lt;p&gt;Make it super easy for your customers to create stunning screenshots in seconds, ready to be shared on social media.&lt;/p&gt;

&lt;p&gt;Think of your product as a mini-Canva, specialized only in screenshots, and with the minimum amount of features needed.&lt;/p&gt;

&lt;p&gt;Like the social videos, screenshots will drive product-led growth. People will notice the screenshots, ask for the source of it, and discover your product.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Form Builder
&lt;/h2&gt;

&lt;p&gt;This is one of the most simple and underrated product ideas possible.&lt;/p&gt;

&lt;p&gt;Form Builders are a must for people that need to collect information only, just by sharing the link of a form previously configured.&lt;/p&gt;

&lt;p&gt;The most common product is Typeform, but the market is so big, that there’s space for new players.&lt;/p&gt;

&lt;p&gt;Build an alternative version, cheaper, but functional.&lt;/p&gt;

&lt;p&gt;Also, this product has product-led growth. Simply allow users to create a limited number of forms for free, and add the logo of your company (Built with CompanyName).&lt;/p&gt;

&lt;p&gt;People will notice it, and they will probably try out your product soon.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Text-to-video
&lt;/h2&gt;

&lt;p&gt;AI is an incredibly powerful technology, we all know the capabilities of AI to generate text and even images.&lt;/p&gt;

&lt;p&gt;But the new frontier is the creation of videos.&lt;/p&gt;

&lt;p&gt;Creating videos requires time and skills. People need to know how to use complex software like Adobe After Effects and similar.&lt;/p&gt;

&lt;p&gt;Creating videos is hard.&lt;/p&gt;

&lt;p&gt;Text-to-video technologies are becoming more and more powerful, with results that improve from one month to the next.&lt;/p&gt;

&lt;p&gt;This product idea is interesting because it solves a painful problem, and there are a few competitors in the market, giving you the possibility to be one of the first players to offer such a solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;I hope that this article gave you some good hints to get started with your MicroSaaS, and some key elements to determine what makes a good product.&lt;/p&gt;

&lt;p&gt;If you want to ship your product very quickly, you might be interested in my Next.js Startup Boilerplate — &lt;a href="https://shipped.club"&gt;Shipped.club&lt;/a&gt; — 200+ devs are already shipping faster using it.&lt;/p&gt;

</description>
      <category>saas</category>
      <category>webdev</category>
      <category>product</category>
    </item>
    <item>
      <title>Query string params in Next.js (14) with App Router</title>
      <dc:creator>Luca Restagno</dc:creator>
      <pubDate>Tue, 30 Apr 2024 07:10:02 +0000</pubDate>
      <link>https://dev.to/ikoichi/query-string-params-in-nextjs-14-with-app-router-4eca</link>
      <guid>https://dev.to/ikoichi/query-string-params-in-nextjs-14-with-app-router-4eca</guid>
      <description>&lt;p&gt;The query string is a part of the URL (Uniform Resource Locator) that assigns values to specific parameters.&lt;/p&gt;

&lt;p&gt;While developing our web apps, we might use query string values to dynamically render a part of the user interface with specific parameters.&lt;/p&gt;

&lt;p&gt;For instance, I provide a shareable link with the Timezone Checker web app, including the user configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://timezonechecker.app/embed?timeFormat=24h&amp;amp;timezones=Europe/London,Europe/Nicosia&amp;amp;Europe/Rome=luca&amp;amp;Europe/London=lars,erik,john
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The query string parameters and values are (parameter=value):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;timeFormat=24h
timezones=Europe/London,Europe/Nicosia
Europe/Rome=luca
Europe/London=lars,erik,john
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Next.js with App Router, there are different components: client components, pages, layouts, and routes.&lt;br&gt;
Let’s see how we can read the query strings in each one of those.&lt;/p&gt;
&lt;h2&gt;
  
  
  Client components
&lt;/h2&gt;

&lt;p&gt;In a client component you can use the React Hooks &lt;code&gt;useSearchParams&lt;/code&gt; to return a read only version of the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams"&gt;URLSearchParams&lt;/a&gt; JavaScript interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useSearchParams&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/navigation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;SearchBar&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;searchParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSearchParams&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;timeFormat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;timeFormat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// URL -&amp;gt; `/embed?timeFormat=24h`&lt;/span&gt;
  &lt;span class="c1"&gt;// `timeFormat` -&amp;gt; '24h'&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;Time format: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;timeFormat&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use the URLSearchParams method has() to determine if a query string param is present or not.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;URL&lt;/th&gt;
&lt;th&gt;searchParams.has(”timeFormat”)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;/embed&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/embed?timeFormat=24h&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The URLSearchParams interface has other read-only methods, like &lt;a href="https://developer.mozilla.org/docs/Web/API/URLSearchParams/getAll"&gt;getAll()&lt;/a&gt;, &lt;a href="https://developer.mozilla.org/docs/Web/API/URLSearchParams/keys"&gt;keys()&lt;/a&gt;, &lt;a href="https://developer.mozilla.org/docs/Web/API/URLSearchParams/values"&gt;values()&lt;/a&gt;, &lt;a href="https://developer.mozilla.org/docs/Web/API/URLSearchParams/entries"&gt;entries()&lt;/a&gt;, &lt;a href="https://developer.mozilla.org/docs/Web/API/URLSearchParams/forEach"&gt;forEach()&lt;/a&gt;, and &lt;a href="https://developer.mozilla.org/docs/Web/API/URLSearchParams/toString"&gt;toString()&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pages
&lt;/h2&gt;

&lt;p&gt;In pages, you can use the searchParams prop to access the query string params.&lt;/p&gt;

&lt;p&gt;In this case, an object is returned.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;EmbedPage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;searchParams&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// URL -&amp;gt; `/embed?timeFormat=24h`&lt;/span&gt;
  &lt;span class="c1"&gt;// searchParams['timeFormat'] -&amp;gt; '24h'&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;Time format: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;timeFormat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Routes
&lt;/h2&gt;

&lt;p&gt;In routes (backend endpoints), you can access the URLSearchParams interface this way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// URL -&amp;gt; `/api/embed?timeFormat=24h`&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timeFormat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;timeFormat&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="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;timeFormat&lt;/span&gt; &lt;span class="p"&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="mi"&gt;200&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;
  
  
  Layouts
&lt;/h2&gt;

&lt;p&gt;In layouts, you cannot access the query string params. Instead, access them from the pages or client components, rendered inside the layout.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Query strings are the comfortable way to save and transmit data into the URL, to allow the users to easily share configurations via the URL, and send data from the client to the server.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>webdev</category>
      <category>querystring</category>
      <category>beginners</category>
    </item>
    <item>
      <title>I've sold my 4th SaaS as a solopreneur. The backstory.</title>
      <dc:creator>Luca Restagno</dc:creator>
      <pubDate>Thu, 04 Apr 2024 12:30:46 +0000</pubDate>
      <link>https://dev.to/ikoichi/ive-sold-my-4th-saas-as-a-solopreneur-the-backstory-jcb</link>
      <guid>https://dev.to/ikoichi/ive-sold-my-4th-saas-as-a-solopreneur-the-backstory-jcb</guid>
      <description>&lt;p&gt;I have great news, I sold my 4th SaaS product!&lt;/p&gt;

&lt;p&gt;Userdesk, it’s an AI Chatbot platform for businesses I launched in June 2023 with a pre-launch and a subscription-based model a few weeks later.&lt;/p&gt;

&lt;p&gt;This is my 4th exit since 2021.&lt;/p&gt;

&lt;p&gt;2021 — I sold Iterspace pre-revenues (quite unusual, but it happened)&lt;br&gt;
2023 — I sold Hivoe and Inboxs, two Twitter-related SaaS&lt;br&gt;
2024 — I sold Userdesk&lt;/p&gt;

&lt;p&gt;Each time, the context and the reasons to sell were completely different, as well as the process. Let’s see the context and the lessons learned with each one (so you can learn from them too).&lt;/p&gt;

&lt;h2&gt;
  
  
  iterspace
&lt;/h2&gt;

&lt;p&gt;I started working on Iterspace in 2019 with one of my former colleagues (designer). I built it on the side of my full-time job at that time, as a team lead / senior software engineer. We worked on it for a couple of years, more or less. During the COVID, I was working from home and the time I saved from commuting, was dedicated to it.&lt;/p&gt;

&lt;p&gt;At the beginning of 2021, we launched on Product Hunt, we got 70 upvotes (not that much but we didn’t have any distribution channel at that time), but Giulio Michelon noticed it, he wanted to meet us (two Italians launching a cool SaaS? it’s quite unusual), and he connected us with the final buyer.&lt;/p&gt;

&lt;p&gt;I have to say that we didn’t set clear goals since the beginning. I wanted to make a living out of my businesses, but for my co-founder that was not realistic.&lt;/p&gt;

&lt;p&gt;So when the possibility of selling arrived, he was completely convinced of the decision.&lt;/p&gt;

&lt;p&gt;That was my first exit ever, and the amount of money was astonishing for a product with no revenues, so I accepted the deal.&lt;/p&gt;

&lt;p&gt;The product hand-off was quite painful, as I created all the cloud resources on AWS with my personal account, and it was not possible to migrate them to another account (weird). So they had to re-create the whole infrastructure with their AWS account, and it took some time.&lt;/p&gt;

&lt;p&gt;From the next SaaS on, I learned to create accounts with dedicated email, so the hand-off takes as long as sending the credentials to the buyer. And that’s it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hivoe &amp;amp; Inboxs
&lt;/h2&gt;

&lt;p&gt;Very quickly, I had to sell these two Twitter-related products, due to the crazy new Twitter API pricing (from 0 to $42k/month). Thankfully, I was able to sell them to HypeFury, because the alternative was to shut down both of them—not a great deal.&lt;/p&gt;

&lt;p&gt;The journey has been amazing, because since 2021 I started being active on Twitter daily, and that’s how I discovered some pain points related to DM management. The products were growing quite well (up to $4k MRR). It was shocking to sell them, especially for an unexpected reason.&lt;/p&gt;

&lt;p&gt;Lesson learned: platform risk is real. Next time, I want to diversify more or avoid platform risk much more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Userdesk
&lt;/h2&gt;

&lt;p&gt;There’s much more to say about the exit of Userdesk.&lt;/p&gt;

&lt;p&gt;I started working on Userdesk after the crazy hype I’ve seen about AI Chatbots around February / March 2023. AI was even more hyped than now, and as a SaaS owner, the value provided was simply incredible.&lt;/p&gt;

&lt;p&gt;The platform allows you to “train” an AI Chatbot using your website (and other sources) and embed a live AI chatbot on your website. Simple, yet so powerful for customer support.&lt;/p&gt;

&lt;p&gt;I pre-launched it with a $69 lifetime deal, and I sold 20 licenses in 24 hours. That was a validation for me (but I was wrong). A month later, the product was live and public, but a very small percentage of the pre-sale users signed up and used it.&lt;/p&gt;

&lt;p&gt;I was perplexed.&lt;/p&gt;

&lt;p&gt;This is my explanation. At that time, I already had a good reputation on Twitter / X. This sometimes brings to impulsive purchase from people who follows and appreciates you. This is great, don’t get me wrong, but it leads to misleading validation results.&lt;/p&gt;

&lt;p&gt;Also, the product was poorly positioned, it was not targeting a specific niche and I didn’t know exactly who I was targeting: SaaS products, IT agencies looking for AI Chatbot platforms to resell, coaching services, and many others very different from each other.&lt;/p&gt;

&lt;p&gt;This is a problem. I didn’t know how to write the copy of my landing pages, which content to write for my blog, and so on.&lt;/p&gt;

&lt;p&gt;At the same time, a large number of competitors were already present and arrived in the short future.&lt;/p&gt;

&lt;p&gt;Plus, in the end, I didn’t feel a great founder product fit. I have built a community on Twitter/X of 20k followers, and almost nobody was in overlap with the target audience of Userdesk. This meant an extra effort for me to find new clients.&lt;/p&gt;

&lt;p&gt;In December 2023 I launched my Next.js SaaS Boilerplate Shipped.club, and I loved working on it, and helping other developers and aspiring SaaS owners to achieve their goals. This fits much better with my expertise and values—it’s simply a better fit for me.&lt;/p&gt;

&lt;p&gt;Lesson learned: founder product fit matters much more than I expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  What did go well?
&lt;/h2&gt;

&lt;p&gt;I loved working with AI tech, and I think it has huge potential, now and in the future. It’s not a bubble. And who knows, maybe in the future I will work on an AI product again.&lt;/p&gt;

&lt;p&gt;I found my customers mainly from AI directories. A lot of AI enthusiasts use them to discover new products, and it also brought a good domain rate, with very few blog posts written.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fd2bzf0z2yzi3mc.cloudfront.net%2Farticles_images%2F4th_saas_sold_1.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fd2bzf0z2yzi3mc.cloudfront.net%2Farticles_images%2F4th_saas_sold_1.jpeg" alt="Userdesk SEO"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of the main differentiation factors of Userdesk over the competition had been the UI and UX. Many people told me it was the best they tried between similar products, and it made me proud of the skills I’ve built over time. I am a software engineer, not a designer, but I’ve built many SaaS products now and the effort on the UI and UX paid off.&lt;/p&gt;

&lt;p&gt;MRR-wise, the journey had been quite slow, but still brought good results, $1.1k MRR it’s difficult to achieve in less than 12 months.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fd2bzf0z2yzi3mc.cloudfront.net%2Farticles_images%2F4th_saas_sold_2.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fd2bzf0z2yzi3mc.cloudfront.net%2Farticles_images%2F4th_saas_sold_2.jpeg" alt="Userdesk MRR"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’re wondering what’s the big spike in September, it’s an enterprise customer ($500/month) who subscribed. The fact the subscription plans start at $19/month up, it’s another explanation for the “rapid” increase in MRR.&lt;/p&gt;

&lt;p&gt;I know I could have grown it much more with more marketing effort: positioning, content, social—but I still think I did the right thing with selling it, and I’ll focus more on Shipped.club and other SaaS products soon.&lt;/p&gt;

&lt;p&gt;What’s the legal process for selling?&lt;br&gt;
I used the platform Acquired for the first time to list my product. I got around 20 people potentially interested, and a couple of offers.&lt;/p&gt;

&lt;p&gt;The process is: when you find a good offer, you sign a Letter of Intent between you and the buyer. It blocks you from accepting offers from other potential buyers.&lt;br&gt;
In this period they do the due diligence on your product, you need to describe the technical aspects of your product and the business. And you can still negotiate on the final price.&lt;/p&gt;

&lt;p&gt;If this phase goes well and everyone is happy, you sign an Asset Purchase Agreement (APA) which is a contract that finalizes the exchange of assets of your product between you and the buyer, and it sets the payment method, amount, and date.&lt;/p&gt;

&lt;p&gt;When you sign the APA, you’re done with the deal. The remaining part is the hand-off of the assets.&lt;/p&gt;

&lt;p&gt;I hope this article was helpful and inspiring, even if a bit long.&lt;/p&gt;

&lt;p&gt;If you have any questions, drop me a message.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How I generated $15k revenues in &lt;4 months</title>
      <dc:creator>Luca Restagno</dc:creator>
      <pubDate>Wed, 20 Mar 2024 14:40:50 +0000</pubDate>
      <link>https://dev.to/ikoichi/15k-revenues-in-4-months-ke9</link>
      <guid>https://dev.to/ikoichi/15k-revenues-in-4-months-ke9</guid>
      <description>&lt;p&gt;If you follow me on &lt;a href="https://x.com/ikoichi"&gt;Twitter/X&lt;/a&gt; or &lt;a href="https://www.threads.net/@luca.restagno.dev"&gt;Threads&lt;/a&gt; you know that I’m a strong believer in the build in public philosophy.&lt;/p&gt;

&lt;p&gt;It’s a way of building products in public, which means sharing the ups and downs, the experiments done, the struggles and wins, and also being open about the revenues.&lt;br&gt;
Recently, &lt;a href="http://Shipped.club"&gt;Shipped.club&lt;/a&gt; hit a new revenue milestone, $15k total revenues, and 126 customers since the 4th of December 2023 (the original launch date).&lt;/p&gt;

&lt;p&gt;And I want to share with you what I did to get here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Who I am and my background.
&lt;/h3&gt;

&lt;p&gt;I am Luca, senior software engineer by profession. I started building products on the side of my 9-5 job in 2019.&lt;/p&gt;

&lt;p&gt;I’ve followed the usual (wrong) path of engineers when approaching product building.&lt;/p&gt;

&lt;p&gt;I spent two years working on it, launched it on Product Hunt in 2021, and got no interest.&lt;/p&gt;

&lt;p&gt;That’s when I realized that a good product is not enough to get attention and customers, you need marketing.&lt;/p&gt;

&lt;p&gt;I started being active on Twitter and never abandoned that habit.&lt;/p&gt;

&lt;p&gt;In 2022 I launched my second SaaS product, a tool for Twitter. I spotted some interesting usages of the platform, especially related to Direct Messages.&lt;/p&gt;

&lt;p&gt;The product was a real success. Fast forward to June 2023: $3k MRR in 1.5 years.&lt;/p&gt;

&lt;p&gt;In 2022 I also decided to start doing build in public on Twitter. Over time I created relationships with people with a similar mindset, and people active on Twitter as well (other entrepreneurs, aspiring ones, developers searching for more freedom, and so on).&lt;/p&gt;

&lt;p&gt;Again, fast forward to today, I have built a community of 21k people on Twitter.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flg5p5mi232kh8zev3pu2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flg5p5mi232kh8zev3pu2.png" alt="ikoichi's Twitter Profile" width="800" height="771"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why did I launch a SaaS Boilerplate?
&lt;/h3&gt;

&lt;p&gt;After shipping 6 other SaaS products, I have solved all the issues of building and launching a SaaS.&lt;/p&gt;

&lt;p&gt;Landing pages that sell, waitlist, pre-sales, sign up, collect payments, affiliate programs, integrate email services, UI kits for fast development, blog, and more.&lt;/p&gt;

&lt;p&gt;So &lt;strong&gt;creating a boilerplate was a no-brainer decision for me&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I already copied and pasted the code of my previous SaaS products to create a new one, so why not make it available to others as well?&lt;/p&gt;

&lt;p&gt;The boilerplate is a huge time saver, you don’t need to spend time on figuring things out, and you already get components well-designed for you, in short, you don’t have to reinvent the wheel, it’s already sorted out for you.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Why is this product working for me?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I think the are some reasons why this product is working quite well for me.&lt;/p&gt;

&lt;p&gt;First of all, I love coding and building products. What I provide is of great quality.&lt;/p&gt;

&lt;p&gt;I always loved helping people, that’s my characteristic. Building a new feature or solving a bug to unlock the job of others, is so rewarding.&lt;/p&gt;

&lt;p&gt;That’s also why I provide a private Discord community to all the customers, I want to help them even after the purchase and create a community of like-minded people. They also help each other. It’s simply amazing.&lt;/p&gt;

&lt;p&gt;Lastly, I know the developer’s world (most of the customers are software engineers) and I know their mindset and needs, so it’s easier for me to come up with blog posts and tool ideas to serve them even better.&lt;/p&gt;

&lt;p&gt;So far I’ve created blog posts on how to use &lt;a href="https://shipped.club/blog/schema-org-nextjs-app-router"&gt;Schema.org&lt;/a&gt;, how to &lt;a href="https://shipped.club/blog/sentry-nextjs"&gt;track errors with Sentry&lt;/a&gt;, the &lt;a href="https://shipped.club/blog/best-vs-code-themes-2024"&gt;best VS Code themes&lt;/a&gt; and &lt;a href="https://shipped.club/blog/9-best-fonts-for-programming"&gt;fonts&lt;/a&gt;, but also how to &lt;a href="https://shipped.club/blog/micro-saas-founder-9-5-job"&gt;become a Micro SaaS founder on the side of a 9-5 job&lt;/a&gt;, and &lt;a href="https://shipped.club/blog/10-lessons-saas-revenues"&gt;10 lessons learned to earn $137k+ revenues&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which are my distribution channels?
&lt;/h3&gt;

&lt;p&gt;As you can imagine, Twitter plays a big role. Most of the traffic and customers are coming from there.&lt;/p&gt;

&lt;p&gt;But I also get interested people from other sources. I do build in public, and I share my milestones. It means that I have some exposure and I was included in some newsletters, which brought customers. Shipped was also mentioned in a video by a YouTube influencer, which led to additional purchases.&lt;/p&gt;

&lt;p&gt;I've also tried paid ads in December, but they didn't work well. There are no quick wins in marketing. I suppose you need to spend more time (and money) to fine-tune your ad messaging, even if you have product Market Fit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Provide value for free
&lt;/h3&gt;

&lt;p&gt;A great way to generate interest in your product is to provide value for free.&lt;br&gt;
You may ask, how? Here’s an example.&lt;/p&gt;

&lt;p&gt;I’ve written a free guide on &lt;strong&gt;How to build and launch a Micro SaaS in 7 days&lt;/strong&gt; using Notion, and I launched it on Twitter with a giveaway.&lt;br&gt;
The interest was so intense, that I decided to convert it into a free email course, that I added to the website of Shipped. Actually, I’m using a trick. I show a pop-up whenever the user is going to leave the website (exit intent). The free course is so appealing that they enter their email and use the course (one email per day, for 7 days).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcixumduouma2avmjs5h7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcixumduouma2avmjs5h7.png" alt="Free Email Course Modal" width="800" height="788"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope this was useful to you all.&lt;br&gt;
See you at the next update for the 200 customers milestone (I hope soon!).&lt;/p&gt;

</description>
      <category>entrepreneur</category>
      <category>boilerplate</category>
    </item>
    <item>
      <title>23 Best VS Code Themes in 2024</title>
      <dc:creator>Luca Restagno</dc:creator>
      <pubDate>Wed, 06 Mar 2024 10:01:10 +0000</pubDate>
      <link>https://dev.to/ikoichi/23-best-vs-code-themes-in-2024-45g1</link>
      <guid>https://dev.to/ikoichi/23-best-vs-code-themes-in-2024-45g1</guid>
      <description>&lt;p&gt;Visual Studio Code (VS Code) is an open-source code editor developed by Microsoft.&lt;/p&gt;

&lt;p&gt;It has been my favorite code editor since 2018, while previously I was using Sublime Text.&lt;/p&gt;

&lt;p&gt;The set of features of VS Code and the deep integration with TypeScript (from Microsoft too) made it my favorite and daily choice.&lt;/p&gt;

&lt;p&gt;I can confirm that is currently broadly adopted by the community of frontend developers (React, Vue, Angular, but not only).&lt;/p&gt;

&lt;p&gt;The different story is for the backend developers, who usually prefer IntelliJ products.&lt;/p&gt;

&lt;p&gt;Considering VS Code is the editor we use daily, we want to select the best theme possible for some reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;nice color scheme (aesthetics is important)&lt;/li&gt;
&lt;li&gt;improve the readability of the code&lt;/li&gt;
&lt;li&gt;reduce eye strain&lt;/li&gt;
&lt;li&gt;increase productivity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Follows a selection of 23 themes, some of them very popular, others not that much.&lt;/p&gt;

&lt;p&gt;Scroll the list until the end, you never know when you can find the theme you’ll fall in love with.&lt;/p&gt;

&lt;p&gt;I won’t tell you which is my favorite theme to avoid influencing you 🙂&lt;/p&gt;

&lt;p&gt;Before the list, let’s discover how to install a new theme on VS Code.&lt;/p&gt;

&lt;h1&gt;
  
  
  How to install a theme in VS Code
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Open the Extension tab (Shift + Cmd + X)&lt;/li&gt;
&lt;li&gt;Type the theme name&lt;/li&gt;
&lt;li&gt;Click on Install&lt;/li&gt;
&lt;li&gt;Select and Set the Color Theme&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s get started with the themes.&lt;/p&gt;

&lt;h1&gt;
  
  
  Themes
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. One Dark Pro
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpn8hrw4lhyxy5ypr0iwj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpn8hrw4lhyxy5ypr0iwj.png" alt="One Dark Pro Theme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Installs: 8,878,463&lt;/p&gt;

&lt;p&gt;Widely used theme, which is the Atom’s dark theme with a black background.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Dracula Official
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa2wkfl9gibu5xcu3nv6k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa2wkfl9gibu5xcu3nv6k.png" alt="Dracula Official Theme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Installs: 6,678,172&lt;/p&gt;

&lt;p&gt;One of the most popular themes in the development space.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. GitHub Theme Dark
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsrqihwj5thjr59r6ofc0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsrqihwj5thjr59r6ofc0.png" alt="GitHub Theme Dark"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Installs: 11,813,086&lt;/p&gt;

&lt;p&gt;Designed by GitHub, this theme replicates the UI of the GitHub’s website.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. GitHub Theme Light
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffrl9ptf5apdyjrzo74vn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffrl9ptf5apdyjrzo74vn.png" alt="GitHub Theme Light"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Installs: 11,813,086&lt;/p&gt;

&lt;p&gt;Light variant of the GitHub website theme.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Winter Is Coming
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl30hv7esdcy2pic5oy4r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl30hv7esdcy2pic5oy4r.png" alt="Winter Is Coming Theme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Installs: 2,707,566&lt;/p&gt;

&lt;p&gt;This theme mixes pleasant and high-contrast colors, with font styles, like italics.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Night Owl
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Floqropuqkkya84fkcanm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Floqropuqkkya84fkcanm.png" alt="Night Owl Theme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Installs: 2,443,039&lt;/p&gt;

&lt;p&gt;This theme has a dark blue background, with contrasting text colors. It has a light variant called Light Owl.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Monokai Pro
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffuro6puionsg9wjk6lfn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffuro6puionsg9wjk6lfn.png" alt="Monokai Pro Theme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Installs: 2,711,098&lt;/p&gt;

&lt;p&gt;One of the most known themes (I remember using it with Sublime Text).&lt;/p&gt;

&lt;p&gt;It’s made of three main colors, dark red, yellow and light blue. &lt;/p&gt;

&lt;h2&gt;
  
  
  8. One Monokai
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe04w8hooh5c3jxdphyyg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe04w8hooh5c3jxdphyyg.png" alt="One Monokai Theme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Installs: 2,117,317&lt;/p&gt;

&lt;p&gt;This theme is a spin-off of Monokai Pro.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Shades of Purple
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy0dtdws4opxymdwxeg76.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy0dtdws4opxymdwxeg76.png" alt="Shades of Purple Theme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Installs: 1,756,519&lt;/p&gt;

&lt;p&gt;If you like purple, you’ll love this theme.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Ayu
&lt;/h2&gt;

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

&lt;p&gt;Installs: 2,331,017&lt;/p&gt;

&lt;p&gt;Highly contrasted theme with pleasant text colours, orange, green, and light blue.&lt;/p&gt;

&lt;h2&gt;
  
  
  11. Palenight
&lt;/h2&gt;

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

&lt;p&gt;Installs: 639,141&lt;/p&gt;

&lt;p&gt;This theme is on the shades of purple, but not as heavily purple as Shades of Purple.&lt;/p&gt;

&lt;h2&gt;
  
  
  12. Cobalt2
&lt;/h2&gt;

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

&lt;p&gt;Installs: 1,436,181&lt;/p&gt;

&lt;p&gt;Super high contrast theme, with almost fluorescent colors.&lt;/p&gt;

&lt;h2&gt;
  
  
  13. SynthWave '84
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhlwgdmbkiexc8e2xw5fx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhlwgdmbkiexc8e2xw5fx.png" alt="SynthWave '84 Theme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Installs: 1,743,153&lt;/p&gt;

&lt;p&gt;Iconic theme if you like the 80s and the synthwave style.&lt;/p&gt;

&lt;h2&gt;
  
  
  14. Noctis
&lt;/h2&gt;

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

&lt;p&gt;Installs: 1,004,008&lt;/p&gt;

&lt;p&gt;Theme designed on the shades of green.&lt;/p&gt;

&lt;h2&gt;
  
  
  15. Panda
&lt;/h2&gt;

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

&lt;p&gt;Installs: 928,562&lt;/p&gt;

&lt;p&gt;If you like pandas and the Japanese world, you’ll love Panda.&lt;/p&gt;

&lt;h2&gt;
  
  
  16. Nord
&lt;/h2&gt;

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

&lt;p&gt;Installs: 905,995&lt;/p&gt;

&lt;p&gt;The theme Nord wasn’t to bring you the colors or a nordic landscape into your code editor.&lt;/p&gt;

&lt;p&gt;Soft and cold colors are making this theme very stylish.&lt;/p&gt;

&lt;h2&gt;
  
  
  17. Sublime Material
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkdl1jcv2vyejgoa2gfoo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkdl1jcv2vyejgoa2gfoo.png" alt="Sublime Material Theme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Installs: 821,819&lt;/p&gt;

&lt;h2&gt;
  
  
  18. Slack Theme
&lt;/h2&gt;

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

&lt;p&gt;Installs: 395,047&lt;/p&gt;

&lt;p&gt;If you want to keep using the Slack theme in your code editor, this is the perfect theme for you.&lt;/p&gt;

&lt;p&gt;It comes in many variants.&lt;/p&gt;

&lt;h2&gt;
  
  
  19. Tokyo Night
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F18b0lxbh81vc602qmyl4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F18b0lxbh81vc602qmyl4.png" alt="Tokyo Night Theme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Installs: 1,359,936&lt;/p&gt;

&lt;p&gt;Popular theme that reminds me of movies like Ghost in the Shell. So stylish.&lt;/p&gt;

&lt;h2&gt;
  
  
  20. Rouge
&lt;/h2&gt;

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

&lt;p&gt;Installs: 34,931&lt;/p&gt;

&lt;p&gt;VSCode theme created for a dark, material feel with a flushed color palette. Inspiration was drawn from Atom's Material.&lt;/p&gt;

&lt;h2&gt;
  
  
  21. Poimandres
&lt;/h2&gt;

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

&lt;p&gt;Installs: 52,108&lt;/p&gt;

&lt;p&gt;Poimandres is a minimal, frameless dark-theme inspired mostly by &lt;a href="https://github.com/peymanslh/vscode-blueberry-dark-theme" rel="noopener noreferrer"&gt;blueberry&lt;/a&gt;. This theme tries to focus on semantic meaning instead of color variety. You'll find that it colors things like errors, voids, throws and deletes in red, types are slighty darker so that the spotlight is on the code, green new's, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  22. Flate
&lt;/h2&gt;

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

&lt;p&gt;Installs: 15,435&lt;/p&gt;

&lt;p&gt;Colorful and dark theme. I love the contrast between the syntax keywords like &lt;code&gt;import&lt;/code&gt; and &lt;code&gt;from&lt;/code&gt; and the variables names.&lt;/p&gt;

&lt;h2&gt;
  
  
  23. Bluloco Dark
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7g2vfma4afar9ymfufb3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7g2vfma4afar9ymfufb3.png" alt="Bluloco Dark Theme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Installs: 337,834&lt;/p&gt;

&lt;p&gt;A fancy but yet sophisticated dark designer color scheme / theme for Visual Studio Code.&lt;/p&gt;

&lt;p&gt;This theme features a much more comprehensive usage of syntax scopes and color consistency, with due regard to aesthetics, contrast, and readability. Originally forked from the beautiful One Dark Theme, enhanced with the meaningful intuitive Bluloco color palette.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;That’s all for this sequence of great themes for Visual Studio Code.&lt;/p&gt;

&lt;p&gt;If you liked them, or you want to suggest more themes, feel free to reach out to me via &lt;a href="https://www.notion.so/46bae42e4fe747cc9d4969677e84bbcf?pvs=21" rel="noopener noreferrer"&gt;email&lt;/a&gt; or on &lt;a href="https://x.com/ikoichi" rel="noopener noreferrer"&gt;Twitter/X&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>vscode</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to become a Micro SaaS founder on the side of a 9-5 job</title>
      <dc:creator>Luca Restagno</dc:creator>
      <pubDate>Fri, 01 Mar 2024 16:56:51 +0000</pubDate>
      <link>https://dev.to/ikoichi/how-to-become-a-micro-saas-founder-on-the-side-of-a-9-5-job-2np6</link>
      <guid>https://dev.to/ikoichi/how-to-become-a-micro-saas-founder-on-the-side-of-a-9-5-job-2np6</guid>
      <description>&lt;p&gt;Starting an entrepreneurial journey is not easy.&lt;/p&gt;

&lt;p&gt;I started my journey as a solopreneur back in 2021, on the side of a 9-5 job to escape the rat race.&lt;/p&gt;

&lt;p&gt;And I truly believe that’s the best way to start it, the reason is simple: it takes a lot of time to start making money and understand how marketing works.&lt;/p&gt;

&lt;p&gt;Most software engineers think that a great product is enough to succeed. Well, let me tell you that it is not the truth. But let’s go in order.&lt;/p&gt;

&lt;h3&gt;
  
  
  The software engineer's product bias
&lt;/h3&gt;

&lt;p&gt;We are all tempted to think, that if the product is cool, people will come and pay for it.&lt;/p&gt;

&lt;p&gt;Our product references are products like Facebook, WhatsApp, Instagram, Google, etc.&lt;/p&gt;

&lt;p&gt;But their growth model is very different than ours. They were not bootstrapped but VC-funded.&lt;/p&gt;

&lt;p&gt;They received so much money to conquer the world, and even with all that money, most of the startups just failed. It’s a different game. We, as bootstrapped solopreneurs, play a different game.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a bootstrapped company?
&lt;/h3&gt;

&lt;p&gt;It’s simply a company that doesn’t take any funding money, no external money from angel investors, Venture Capital, and so on. The founders use their own money to run the business and reinvest the revenues into the business.&lt;/p&gt;

&lt;p&gt;Here’s how I suggest you start your own online business, like a Micro SaaS, or any other digital product: start with the problem to solve.&lt;/p&gt;

&lt;p&gt;The more painful is the problem, the better. The customers need to think, “I need this product to save me and my company time or money” (they are both linked anyway).&lt;/p&gt;

&lt;p&gt;Once you identify the problem, it’s the right moment to start building the product.&lt;/p&gt;

&lt;h3&gt;
  
  
  Organize your time
&lt;/h3&gt;

&lt;p&gt;Most people I know are amazed when they discover I am a solopreneur on the side of a 9-5 job.&lt;/p&gt;

&lt;p&gt;I was able to achieve quite some good results (6 SaaS, sold 3 of them) while working as a senior software engineer and team lead for different companies.&lt;/p&gt;

&lt;p&gt;But let’s give you the exact daily schedule I use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I wake up around 7/7:30 AM (I’m not an early bird, I can’t wake up before, I tried, but it’s not for me)&lt;/li&gt;
&lt;li&gt;I do some house stuff, like preparing breakfast for the family and so on&lt;/li&gt;
&lt;li&gt;I work out a bit, (usually push-ups)&lt;/li&gt;
&lt;li&gt;At 8 AM I’m in front of my desk, I work for an hour on my stuff (coding my products, or scheduling posts on X and engaging)&lt;/li&gt;
&lt;li&gt;At 9 AM I start working for my employer, until 1 PM, launch break of 1 hour, employer work until 6 PM&lt;/li&gt;
&lt;li&gt;The evening is usually dedicated to personal time, I watch some TV series or go out for dinner. I rarely work.&lt;/li&gt;
&lt;li&gt;During the weekend I might do something, or not, but I never overwork. I try to keep a good work-life balance because I want to do this in the long term and avoid burning out at all costs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s it, do this every day, and your effort will compound over time to build something bigger.&lt;/p&gt;

&lt;p&gt;You don’t need morning routines, to wake up at 5 AM, or any other fancy technique.&lt;/p&gt;

&lt;p&gt;Do just a little bit every day.&lt;/p&gt;

&lt;p&gt;Of course, I work from home, and I don’t have commuting time.&lt;/p&gt;

&lt;p&gt;Having a 9-5 removes from you the money pressure, the pressure to make money to pay the bills. And you can reinvest part of your salary into your businesses (sponsorships, paid ads, consultancies, etc.).&lt;/p&gt;

&lt;p&gt;This is what I was able to achieve by being consistent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Between 2019 and 2021, I built the SaaS iterspace.com and sold it.&lt;/li&gt;
&lt;li&gt;In 2021 I started building an audience on Twitter talking about web development (by the way, grab the &lt;a href="https://lucarestagno.gumroad.com/l/200webdevslides/?utm_source=solop&amp;amp;utm_medium=email&amp;amp;utm_campaign=issue_9_5"&gt;free 200+ slides&lt;/a&gt; about JavaScript, React, CSS if you haven’t already).&lt;/li&gt;
&lt;li&gt;In 2022 I started building &lt;a href="http://hivoe.com"&gt;hivoe.com&lt;/a&gt; in public, a Twitter DM automation micro SaaS, and &lt;a href="http://inboxs.io"&gt;inboxs.io&lt;/a&gt;, a Twitter DM productivity inbox micro SaaS (I sold both of them in 2023)&lt;/li&gt;
&lt;li&gt;In 2023 I built &lt;a href="https://omniwrite.ai"&gt;OmniWrite&lt;/a&gt; an AI writing Chrome extension, &lt;a href="https://userdesk.io"&gt;Userdesk&lt;/a&gt; an AI Chatbots platform for businesses, &lt;a href="https://usewuf.com"&gt;Wuf&lt;/a&gt; a mobile push notifications Micro SaaS, and launched &lt;a href="http://shipped.club"&gt;Shipped.club&lt;/a&gt;, the Next.js Micro SaaS Boilerplate for busy founders.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I strongly suggest that everyone start indie hacking on the side, it’s the most sustainable and stress-free way of approaching it.&lt;/p&gt;

&lt;p&gt;Also because there’s a lot to learn, and it takes time.&lt;/p&gt;

&lt;h3&gt;
  
  
  My tech stack
&lt;/h3&gt;

&lt;p&gt;Over the years I’ve consolidated my tech stack into something optimized for speed.&lt;/p&gt;

&lt;p&gt;Here’s what I use, so you can steal it and use it as well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://react.dev/"&gt;React&lt;/a&gt; great UI library based on &lt;strong&gt;reusable&lt;/strong&gt; components, I’m so quick building web app using React&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://chakra-ui.com/"&gt;ChakraUI&lt;/a&gt; is one of the best open source Design Systems and UI kits for React. I get many components from it and responsive props.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nextjs.org/"&gt;Next.js&lt;/a&gt; is a full-stack framework for React based on node.js (JavaScript). It makes it so easy to build full-stack apps, with client and server code in one single codebase.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vercel.com/"&gt;Vercel&lt;/a&gt; I host my web apps using Vercel. You push your commit to your GitHub repo, and they deploy it. It’s that simple.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://next-auth.js.org/"&gt;NextAuth&lt;/a&gt; authentication made finally easy, for Next.js&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.postgresql.org/"&gt;PostgreSQL&lt;/a&gt; is my favorite open-source SQL database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope you find this information useful, and if you have any questions, please write to me on &lt;a href="https://twitter.com/ikoichi"&gt;Twitter/X&lt;/a&gt; or &lt;a href="//mailto:hey@shipped.club"&gt;via email&lt;/a&gt; 🙌&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Luca&lt;/em&gt;&lt;/p&gt;

</description>
      <category>saas</category>
      <category>startup</category>
      <category>development</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>How to track errors with Sentry and Next.js</title>
      <dc:creator>Luca Restagno</dc:creator>
      <pubDate>Mon, 29 Jan 2024 11:43:14 +0000</pubDate>
      <link>https://dev.to/ikoichi/how-to-track-errors-with-sentry-and-nextjs-1fc4</link>
      <guid>https://dev.to/ikoichi/how-to-track-errors-with-sentry-and-nextjs-1fc4</guid>
      <description>&lt;p&gt;Sentry is one of the most popular error-tracking platforms for software products.&lt;/p&gt;

&lt;p&gt;It tracks the errors that occur in your software, showing you the error message and relevant information about the execution context (like browser, language, screen size, and so on).&lt;/p&gt;

&lt;p&gt;In this tutorial, will see in detail how to install Sentry into your Next.js app and start collecting remote errors in a few minutes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install Sentry
&lt;/h3&gt;

&lt;p&gt;Create an account on &lt;a href="https://sentry.io/signup" rel="noopener noreferrer"&gt;Sentry&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once done, you’ll be guided to install it in your project.&lt;/p&gt;

&lt;p&gt;Click on Start for the Install Sentry suggestion.&lt;/p&gt;

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

&lt;p&gt;Depending on your language and framework, you’ll get different instructions.&lt;/p&gt;

&lt;p&gt;Filter the platforms with &lt;code&gt;Next.js&lt;/code&gt; select it from the list, and click on &lt;code&gt;Configure SDK&lt;/code&gt;&lt;/p&gt;

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

&lt;p&gt;Once done, you’ll get the instructions to install Sentry in your Next.js project.&lt;/p&gt;

&lt;p&gt;Open the terminal and go to the folder of your Next.js project and simply run the command provided by Sentry:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npx @sentry/wizard@latest &lt;span class="nt"&gt;-i&lt;/span&gt; nextjs


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

&lt;/div&gt;

&lt;p&gt;At this point, follow the instructions in the terminal.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;Sentry Next.js Wizard&lt;/em&gt; will guide you through the installation.&lt;/p&gt;

&lt;p&gt;If you have uncommitted changes in your repository, it will ask you if you want to continue, I selected Yes.&lt;/p&gt;

&lt;p&gt;Then it asks you to use the &lt;em&gt;Sentry SaaS&lt;/em&gt; or a &lt;em&gt;self-hosted Sentry&lt;/em&gt;. Since I want to use their cloud solution, I selected Sentry SaaS.&lt;/p&gt;

&lt;p&gt;It asks if you already have an account or not chose your case.&lt;/p&gt;

&lt;p&gt;I had an account, so it redirected me to the browser, where it retrieved my Sentry account (I was already logged in). You can close this browser window when it’s done.&lt;/p&gt;

&lt;p&gt;At this point, the &lt;em&gt;Sentry Next.js Wizard&lt;/em&gt; installs the files needed by Next.js to correctly collect the errors, both on the client and on the server.&lt;/p&gt;

&lt;p&gt;It creates some files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sentry.server.config.ts&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sentry.client.config.ts&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sentry.edge.config.ts&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/pages/_error.jsx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.sentryclirc&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also updates the file &lt;code&gt;next.config.js&lt;/code&gt; with the Sentry configuration.&lt;/p&gt;

&lt;p&gt;It also asks to create two sample pages (recommended), one for client side error testing and one for server side error testing.&lt;/p&gt;

&lt;p&gt;These two files simply throws exceptions, so that you can test if the Sentry integration is correctly installed.&lt;/p&gt;

&lt;p&gt;Finally, you need to add the environment variable &lt;code&gt;SENTRY_AUTH_TOKEN&lt;/code&gt; to your CI setup (Vercel, GitHub Actions, Jenkins, and others). The wizard will provide you with the value to set.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test the Sentry installation
&lt;/h3&gt;

&lt;p&gt;If you accepted the creation of the sample pages (which I recommend) it’s time to test the installation.&lt;/p&gt;

&lt;p&gt;Run your local web server:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm run dev


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

&lt;/div&gt;

&lt;p&gt;And point your browser to these URLs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://localhost:3000/sentry-example-page" rel="noopener noreferrer"&gt;http://localhost:3000/sentry-example-page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://localhost:3000/api/sentry-example-api" rel="noopener noreferrer"&gt;http://localhost:3000/api/sentry-example-api&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;a href="http://localhost:3000/sentry-example-page" rel="noopener noreferrer"&gt;http://localhost:3000/sentry-example-page&lt;/a&gt; click “Throw error!”&lt;/p&gt;

&lt;p&gt;In both cases you will see and error in the browser, and that’s expected.&lt;/p&gt;

&lt;p&gt;Now open the Sentry dashboard, if the installation is correct, you’ll see two new errors.&lt;/p&gt;

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

&lt;p&gt;Congratulations, you’re now able to intercept the remote errors of your Next.js website.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>saas</category>
      <category>nextjs</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
