<?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: Remi W.</title>
    <description>The latest articles on DEV Community by Remi W. (@ixartz).</description>
    <link>https://dev.to/ixartz</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%2F98444%2Fcda642ef-7f1e-4218-99ec-3bf400943945.png</url>
      <title>DEV Community: Remi W.</title>
      <link>https://dev.to/ixartz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ixartz"/>
    <language>en</language>
    <item>
      <title>The Ultimate 2024 Tech Stack for Solo SaaS Developers: Build Smarter, Not Harder</title>
      <dc:creator>Remi W.</dc:creator>
      <pubDate>Tue, 18 Jun 2024 14:45:55 +0000</pubDate>
      <link>https://dev.to/ixartz/the-ultimate-2024-tech-stack-for-solo-saas-developers-build-smarter-not-harder-14kb</link>
      <guid>https://dev.to/ixartz/the-ultimate-2024-tech-stack-for-solo-saas-developers-build-smarter-not-harder-14kb</guid>
      <description>&lt;p&gt;Building a SaaS as a solo developer is a challenging task. You have to wear multiple hats and be proficient in various technologies, requiring strategic decisions about your tech stack. This means you need to be a full-stack developer familiar with both frontend and backend.&lt;/p&gt;

&lt;p&gt;Choosing the right tech stack is crucial for the best developer experience. In this post, I'll share my &lt;strong&gt;Next.js stack for building a SaaS&lt;/strong&gt; and break down the different parts of the stack. I'll also share the favorite tools I rely on. If you want to see the final result, you can check out a &lt;a href="https://pro-demo.nextjs-boilerplate.com" rel="noopener noreferrer"&gt;live demo of the stack&lt;/a&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnextjs-boilerplate-saas-dashboard.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnextjs-boilerplate-saas-dashboard.png" alt="Next.js Boilerplate SaaS Dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hope this post will inspire you and help you on your own SaaS journey.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next.js, the Backbone of the Stack
&lt;/h2&gt;

&lt;p&gt;As a solo developer, you need a framework that allows you to build full-stack applications with ease. Next.js is an excellent choice for building a SaaS, as it's a &lt;strong&gt;React framework&lt;/strong&gt; that enables you to build modern applications efficiently.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnextjs-logo.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnextjs-logo.png" alt="Next.js React Meta framework"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I use Next.js to create both the user dashboard and the marketing site. The frontend is written in React, while the backend uses Next.js Route Handlers. The Route Handlers create a RESTful API, which can be used by React components and other clients, such as mobile applications.&lt;/p&gt;

&lt;p&gt;Using the same framework for both the &lt;strong&gt;marketing site and the dashboard&lt;/strong&gt; allows me to reuse components and styles across all parts of the SaaS. This makes the design more consistent and development more efficient. Similarly, having both the frontend and backend rely on Next.js makes it extremely easy to share code between the two.&lt;/p&gt;

&lt;h2&gt;
  
  
  Only One Language, TypeScript
&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Ftypescript-logo.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Ftypescript-logo.png" alt="TypeScript programming language logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To maximize productivity, I use only a single programming language: TypeScript. Combined with Next.js, TypeScript allows me to write both frontend and backend code within one framework and one language, simplifying the development process and reducing context switching.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shadcn UI with Tailwind CSS
&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fshadcn-ui-logo.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fshadcn-ui-logo.png" title="Shadcn UI logo"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Ftailwind-css-logo.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Ftailwind-css-logo.png" title="Tailwind CSS logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the UI, I choose Shadcn UI, a collection of components built on top of Radix UI, which provides unstyled React components. &lt;strong&gt;Shadcn UI styles Radix UI&lt;/strong&gt; components using Tailwind CSS to deliver a beautiful UI for the SaaS. The good news is that I can share these components between the marketing site and the user dashboard seamlessly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authentication
&lt;/h2&gt;

&lt;p&gt;Authentication is a crucial part of any SaaS. I use &lt;a href="https://clerk.com?utm_source=github&amp;amp;utm_medium=sponsorship&amp;amp;utm_campaign=nextjs-boilerplate" rel="noopener noreferrer"&gt;Clerk&lt;/a&gt; for authentication, which offers comprehensive features like email/password and social login. These basic features are available in many open-source libraries.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://clerk.com?utm_source=github&amp;amp;utm_medium=sponsorship&amp;amp;utm_campaign=nextjs-boilerplate" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fclerk-auth-logo.png" alt="Clerk auth logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, if your application requires more &lt;strong&gt;advanced features&lt;/strong&gt;, Clerk is an excellent choice. It can handle multi-factor authentication, user impersonation, multi-session support (one user can connect to multiple accounts), blocking disposable emails, brute-force protection, bot protection, and more.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://clerk.com?utm_source=github&amp;amp;utm_medium=sponsorship&amp;amp;utm_campaign=nextjs-boilerplate" rel="noopener noreferrer"&gt;Clerk&lt;/a&gt; also offers a complete UI in React for authentication, which can be customized to match your brand. It saves you the time and effort of developing authentication from scratch. Some of the &lt;strong&gt;built-in UIs&lt;/strong&gt; provided by Clerk include Sign Up, Sign In, Forgot Password, Reset Password, and User Profile.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fclerk-sign-up-page.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fclerk-sign-up-page.png" alt="Clerk Sign up page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-tenancy and Team Management
&lt;/h2&gt;

&lt;p&gt;A robust SaaS should support collaboration within teams or organizations. &lt;a href="https://clerk.com?utm_source=github&amp;amp;utm_medium=sponsorship&amp;amp;utm_campaign=nextjs-boilerplate" rel="noopener noreferrer"&gt;Clerk&lt;/a&gt; provides a comprehensive multi-tenancy and team management system, including a full &lt;strong&gt;UI for managing teams and inviting users&lt;/strong&gt;. This means I don't need to implement backend logic or UI for team management, as Clerk handles everything, including sending invitation emails and allowing users to switch between teams seamlessly.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fclerk-multi-tenancy-user-management.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fclerk-multi-tenancy-user-management.png" alt="Clerk Multi-tenancy"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Role and Permission
&lt;/h2&gt;

&lt;p&gt;With multi-tenancy, it's important to manage roles and permissions. &lt;a href="https://clerk.com?utm_source=github&amp;amp;utm_medium=sponsorship&amp;amp;utm_campaign=nextjs-boilerplate" rel="noopener noreferrer"&gt;Clerk&lt;/a&gt; allows creating custom roles and permissions, enabling users to assign roles. For example, an Admin has all the privileges within the team, while a Read-Only role can only view the resources. This ensures appropriate access and security.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fclerk-custom-roles-permissions.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fclerk-custom-roles-permissions.png" alt="Clerk Roles and Permissions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Database
&lt;/h2&gt;

&lt;p&gt;I use Drizzle ORM for database management because it's type-safe and integrates seamlessly with TypeScript. With Drizzle, I can define models and relationships directly in TypeScript, eliminating the need for an external schema file. This means you don't have to learn another syntax.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fdrizzle-orm-logo.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fdrizzle-orm-logo.png" alt="Drizzle ORM"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Drizzle also provides &lt;strong&gt;Drizzle Kit&lt;/strong&gt;, a CLI tool that simplifies the migration process. With Drizzle Kit, you can generate a migration folder to seamlessly update your database schema.&lt;/p&gt;

&lt;p&gt;Additionally, you have &lt;strong&gt;Drizzle Studio&lt;/strong&gt; for a visual interface to manage your database. Drizzle Studio allows you to view your database schema, run queries, and browse your data.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fdrizzle-studio.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fdrizzle-studio.png" alt="Drizzle Studio"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Stripe
&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fstripe-logo.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fstripe-logo.png" alt="Stripe logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stripe handles payments and subscriptions seamlessly. With the Stripe SDK, I can easily integrate payment processing into my Next.js application. &lt;strong&gt;Stripe offers a checkout page&lt;/strong&gt;, to which users can be redirected. This page not only reminds users of the plan they are about to subscribe to, but also the monthly or yearly price. Finally, the users can enter their credit card details and subscribe to the selected plan.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fstripe-checkout-saas.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fstripe-checkout-saas.png" alt="Stripe Checkout SaaS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once a subscription is made, Stripe will send a webhook event to my REST API endpoint, indicating that the user has subscribed. This allows me to update the user's subscription status in my database.&lt;/p&gt;

&lt;p&gt;Stripe offers a &lt;strong&gt;self-service portal&lt;/strong&gt; for your users to manage their subscription. In this portal, users can change their plan, update their payment method, cancel their subscription, and view their invoices.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fstripe-customer-portal-saas.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fstripe-customer-portal-saas.png" alt="Stripe Customer Portal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Internationalization (i18n)
&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnext-intl-logo.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnext-intl-logo.png" alt="Next-Intl logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To reach a global audience, I use the Next-Intl library to support multiple languages in Next.js. Next-Intl ensures type-safe translations, verifying that the correct translation key is in use. This prevents runtime errors caused by missing or incorrect translations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://l.crowdin.com/next-js" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fcrowdin-logo.png" alt="Crowdin Logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To make the translation experience more efficient, I use &lt;a href="https://l.crowdin.com/next-js" rel="noopener noreferrer"&gt;Crowdin&lt;/a&gt;, a &lt;strong&gt;localization platform&lt;/strong&gt; that integrates seamlessly with GitHub. Crowdin allows me to manage translations collaboratively, ensuring that the application is available in the desired languages.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fcrowdin-editor.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fcrowdin-editor.png" alt="Crowdin editor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Form Management
&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Freact-hook-form-logo.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Freact-hook-form-logo.png" title="React Hook Form logo"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fzod-library.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fzod-library.png" title="Zod logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I use &lt;strong&gt;React-Hook-Form combined with Zod&lt;/strong&gt; for form management and validation. React-Hook-Form simplifies form handling in React, while Zod ensures data validation. The Zod schema can be easily shared between the frontend and the backend to ensure data validity on both sides.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;As a SaaS builder, it's essential to ensure that the application works as expected. Without a team to test my application, I must rely on automated tests. This way, I'm confident that my application won't experience any regression when new features are added.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fvitest-logo.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fvitest-logo.png" title="Vitest logo"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Freact-testing-library-logo.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Freact-testing-library-logo.png" title="React Testing Library logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I use &lt;strong&gt;Vitest and React Testing Library for unit testing&lt;/strong&gt;. Vitest is a test runner that supports TypeScript and ESM out of the box, offering a modern alternative to Jest. Another advantage of Vitest is its official VSCode extension and Vitest UI, which make Vitest even better. And, React Testing Library provides utilities for interacting with React components.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fplaywright-logo.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fplaywright-logo.png" alt="Playwright logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For end-to-end (E2E) and integration testing, I rely on Playwright. Playwright is a powerful tool that allows you to automate browser interactions, making it ideal for testing the full functionality of your application. With Playwright, I can simulate user interactions across different browsers, ensuring that my app performs consistently. Additionally, Playwright is excellent for testing Next.js Route Handlers, as it can easily send HTTP requests and validate responses.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub Actions
&lt;/h2&gt;

&lt;p&gt;GitHub Actions is a powerful tool that I use for Continuous Integration (CI). It allows me to automate the process of running tests and checks on my code before merging changes to the main branch.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fgithub-actions-logo.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fgithub-actions-logo.png" alt="GitHub Actions logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Whenever I push a new commit or create a pull request, &lt;strong&gt;GitHub Actions automatically triggers workflows&lt;/strong&gt; that I have defined in my repository. These workflows run unit tests with Vitest, executing end-to-end tests with Playwright, and performing linting and code formatting checks. If there is any issue, GitHub Actions will notify me, preventing me from merging faulty code.&lt;/p&gt;

&lt;p&gt;Because my code is continuously being tested and validated, it provides a safety net that allows me to focus on building new features. Especially as a solo developer, we need to wear multiple hats and have limited time to manually test every aspect of an application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logging
&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fpino-logging-logo.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fpino-logging-logo.png" title="Pino.js logging logo"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fbetter-stack-logo.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fbetter-stack-logo.png" title="Better Stack logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I use Pino, a &lt;strong&gt;fast and lightweight logging&lt;/strong&gt; library for Node.js. Pino provides a simple API to log messages and supports structured logging, making it easy to search and analyze logs. In production, I take logging a step further by sending the logs to &lt;a href="https://betterstack.com/?utm_source=github&amp;amp;utm_medium=sponsorship&amp;amp;utm_campaign=next-js-boilerplate" rel="noopener noreferrer"&gt;Better Stack&lt;/a&gt;. Better Stack offers a robust logging platform that allows for real-time log monitoring, alerting, and visualization. By integrating Pino with Better Stack, I ensure that all log data is efficiently captured, stored, and accessible, enabling quick identification and resolution of issues in a live environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error Monitoring
&lt;/h2&gt;

&lt;p&gt;For error monitoring, I use &lt;a href="https://sentry.io/for/nextjs/?utm_source=github&amp;amp;utm_medium=paid-community&amp;amp;utm_campaign=general-fy25q1-nextjs&amp;amp;utm_content=github-banner-nextjsboilerplate-logo" rel="noopener noreferrer"&gt;Sentry&lt;/a&gt;, which captures errors and exceptions. It provides detailed reports that include stack traces, user context, and other relevant information, making it easier to identify issues.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://sentry.io/for/nextjs/?utm_source=github&amp;amp;utm_medium=paid-community&amp;amp;utm_campaign=general-fy25q1-nextjs&amp;amp;utm_content=github-banner-nextjsboilerplate-logo" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fsentry-logo.png" alt="Sentry error monitoring logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In local development, I use &lt;strong&gt;Spotlight to capture Sentry events&lt;/strong&gt;, taking advantage of Sentry's telemetry without overwhelming the production instance.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fsentry-spotlight.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fsentry-spotlight.png" alt="Sentry spotlight local"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Environment Variables
&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Ft3-env-zod-logo.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Ft3-env-zod-logo.png" alt="T3 Env Zod logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;T3 Env&lt;/strong&gt; is a library that uses Zod to validate and transform environment variables. This ensures that all environment variables are correctly defined and validated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Linter and Code Formatter
&lt;/h2&gt;

&lt;p&gt;Maintaining a clean codebase is essential. I use &lt;strong&gt;ESLint and Prettier for linting and code formatting&lt;/strong&gt;. ESLint ensures code quality by enforcing best practices and catching potential errors, while Prettier enforces a consistent coding style. This makes the codebase more readable and maintainable.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Feslint-logo.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Feslint-logo.png" title="ESLint linter logo"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fprettier-logo.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fprettier-logo.png" title="Prettier Code formatter logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I recommend using the Airbnb style guide as the base configuration for ESLint, as it's one of the most popular JavaScript style guides. Additionally, I use &lt;code&gt;eslint-plugin-playwright&lt;/code&gt; to ensure my Playwright tests follow best practices and &lt;code&gt;eslint-plugin-tailwind&lt;/code&gt; to enforce best practices for Tailwind CSS.&lt;/p&gt;

&lt;h2&gt;
  
  
  VSCode
&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fvscode-logo.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fvscode-logo.png" alt="VSCode logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Visual Studio Code (VSCode) is my code editor of choice and has a rich ecosystem of extensions. Here are some of the extensions that I recommend that work well with my tech stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;vscode-eslint&lt;/code&gt;, integrates ESLint into VS Code&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;vscode-tailwindcss&lt;/code&gt;, provides IntelliSense and syntax highlighting for Tailwind CSS&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;vscode-github-actions&lt;/code&gt;, manages GitHub Actions workflows directly in VSCode&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;i18n-ally&lt;/code&gt;, supports internationalization, offering translation key management, making it easier to work with multiple languages&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;In conclusion, building a SaaS as a solo developer can be quite challenging. However, choosing the right tech stack can make the process much easier, allowing you to focus on delivering value to your users. The combination of Next.js, TypeScript, Shadcn UI with Tailwind CSS, Clerk, Drizzle ORM, Stripe, and other tools shared in this article provides a scalable environment for &lt;strong&gt;building a SaaS product&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;These tools not only simplify the development process but also ensure that your application is secure, performant, and user-friendly. They handle everything from authentication, multi-tenancy, and payment processing to database management, testing, and continuous integration, &lt;strong&gt;helping you focus on your business logic and user experience&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you want to check out the final result, you can find a &lt;a href="https://pro-demo.nextjs-boilerplate.com" rel="noopener noreferrer"&gt;live demo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I've created a &lt;a href="https://nextjs-boilerplate.com/pro-saas-starter-kit" rel="noopener noreferrer"&gt;Next.js SaaS boilerplate&lt;/a&gt;, which is a comprehensive starting point for building your own SaaS product using the same tech stack shared in this article.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nextjs-boilerplate.com/pro-saas-starter-kit" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnextjs-saas-boilerplate.png" alt="Next.js SaaS Starter kit"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The key to success as a solo developer is to leverage the right tools and technologies. This tech stack is my personal choice based on my experience and requirements. Depending on your project's needs, you might choose different tools. However, the principles remain the same: &lt;strong&gt;choose tools that make you productive&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I hope this post has given you some insights and inspiration for your own SaaS journey. Happy coding!&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>🚀 Next.js Boilerplate just hit 6000+ ⭐ stars on GitHub! 🔥 6️⃣0️⃣0️⃣0️⃣ 🔥</title>
      <dc:creator>Remi W.</dc:creator>
      <pubDate>Fri, 08 Mar 2024 11:46:42 +0000</pubDate>
      <link>https://dev.to/ixartz/nextjs-boilerplate-just-hit-6000-stars-on-github-6000-1bb</link>
      <guid>https://dev.to/ixartz/nextjs-boilerplate-just-hit-6000-stars-on-github-6000-1bb</guid>
      <description>&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%2Ftl87b22nhotoxtavymvk.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%2Ftl87b22nhotoxtavymvk.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I want to share an awesome news for my Next.js Boilerplate which has reached 6000+ ⭐ stars on GitHub. I started the project in July 2020 but I have continuously updating the project from Next.js 9 to Next.js 14.1 with the app router support, from Tailwind CSS 1 to the version 3.4, upgrade ESLint to version 8, replace Cypress by Playwright for better DX, etc.&lt;/p&gt;

&lt;p&gt;I also added new feature into the boilerplate. Lately, I add the internationalization (i18n) to support multi-language app out of the box. To also improve the Developer experience, the boilerplate comes up with a Logging system using Pino.js.&lt;/p&gt;

&lt;p&gt;You can check out the GitHub repo at: &lt;a href="https://github.com/ixartz/Next-js-Boilerplate" rel="noopener noreferrer"&gt;Next.js Boilerplate&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also learn more about the project on the &lt;a href="https://nextjs-boilerplate.com" rel="noopener noreferrer"&gt;official Next.js Boilerplate website&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is only the beginning, I'm currently working to add more built-in feature into the boilerplate and I'll keep updating the project. I'm also open to suggestion and feedback.&lt;/p&gt;

&lt;p&gt;Hope you'll find interesting and you'll use for your current and next projects.&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%2Fsevqsaav7b4r4x9y0lh6.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%2Fsevqsaav7b4r4x9y0lh6.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>nextjs</category>
      <category>opensource</category>
    </item>
    <item>
      <title>How to Build a SaaS on AWS: a deep dive into the architecture of a SaaS product</title>
      <dc:creator>Remi W.</dc:creator>
      <pubDate>Tue, 21 Feb 2023 15:03:38 +0000</pubDate>
      <link>https://dev.to/ixartz/how-to-build-a-saas-on-aws-a-deep-dive-into-the-architecture-of-a-saas-product-169f</link>
      <guid>https://dev.to/ixartz/how-to-build-a-saas-on-aws-a-deep-dive-into-the-architecture-of-a-saas-product-169f</guid>
      <description>&lt;p&gt;Building a SaaS product is a complex task. There are many things to consider, from the business model to the technology stack. In this article, we will focus on the technology stack I use and learn how I build my SaaS product on AWS. I'll describe the various services and how they fit together to provide a scalable, secure, and reliable SaaS product.&lt;/p&gt;

&lt;p&gt;It took me 5 months to build my first SaaS product. During this time, I had to learn a lot about AWS and gain a ton of experience. This article is an opportunity for me to share my knowledge, and I also hope it will inspire you to build your own SaaS product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture Diagram
&lt;/h2&gt;

&lt;p&gt;A picture is worth a thousand words, so let's start with the architecture diagram of a SaaS product.&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%2Fwyrns3uezy0j8w9nisdw.jpg" 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%2Fwyrns3uezy0j8w9nisdw.jpg" alt="AWS SaaS Boilerpalte architecture for a multi tenancy app" width="795" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It gives you a high-level overview of the various components of the architecture. We will now dive into each component and see how it works.&lt;/p&gt;

&lt;p&gt;You can see a live demo of a SaaS product build with my &lt;a href="https://nextlessjs.com" rel="noopener noreferrer"&gt;React SaaS Boilerplate&lt;/a&gt;, fully hosted on AWS. It includes everything you need in a SaaS including authentication, multi-tenancy &amp;amp; team support, user dashboard, billing with Stripe and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frontend
&lt;/h2&gt;

&lt;p&gt;Let's start with the frontend, the part of the application that users will interact with. It is the entry point to the application.&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%2Fji7iq1wynw5rj2sq9g49.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%2Fji7iq1wynw5rj2sq9g49.png" alt="Nextjs React framework logo" width="295" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The frontend is written in React with Next.js. For performance reasons, all the pages are statically generated. The good news, they can easily host on any static hosting service. For example, you can host the frontend on S3 with Cloudfont as a CDN. But with modern tools, I recommend using AWS Amplify Hosting. It's Vercel and Netlify alternatives in the AWS ecosystem.&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%2F2p5uhif5cw4b78gyiy9j.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%2F2p5uhif5cw4b78gyiy9j.png" alt="AWS Amplify Hosting logo" width="800" height="113"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AWS Amplify Hosting can automatically deploy your frontend application from your GitHub repository. It also provides features like a custom domain, SSL certificate, and more.&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%2F0rmd65mqjvn5hgloxpxx.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%2F0rmd65mqjvn5hgloxpxx.png" alt="Tailwind CSS logo" width="300" height="70"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The UI is styled with Tailwind CSS. So, I can easily style React components directly in JSX without using a library like styled-components or emotion.&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%2Fithgxwrrc7upup2yi6w5.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%2Fithgxwrrc7upup2yi6w5.png" alt="SWR React Hook logo" width="104" height="24"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, I use &lt;code&gt;SWR&lt;/code&gt; to fetch data from the backend. It's a React Hooks library for data fetching, a lightweight alternative to &lt;code&gt;React Query&lt;/code&gt;, easy to use, and offers features like caching, revalidation, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backend
&lt;/h2&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%2Frsdgzrnl30bcy0uep10f.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%2Frsdgzrnl30bcy0uep10f.png" alt="AWS Lambda" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The backend code is hosted on AWS Lambda, a serverless computing service that allows you to run code without managing servers. It's ideal for a SaaS product because I can dedicate all my time on the product without worrying about Ops. On top of that, it's highly scalable and cheap.&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%2F8g3cbb1lup5fqzpbq8jn.jpg" 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%2F8g3cbb1lup5fqzpbq8jn.jpg" alt="AWS API Gateway" width="79" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To make AWS Lambda publicly accessible, I need to use AWS API Gateway. It's a fully managed service that makes it easy to create, publish, maintain, monitor, and secure APIs at any scale. It provides features like authentication, rate limiting, and more.&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%2Fc0zrmr11rkgix4ln9xav.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%2Fc0zrmr11rkgix4ln9xav.png" alt="Serverless Framework" width="800" height="239"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I use the Serverless Framework to manage my API Gateway and AWS Lambda functions. It's a framework for creating and deploying serverless apps. It's super user-friendly and all configurations are handled in a single YAML file.&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%2Fxa2hi4hbdzqbvwtvgy0m.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%2Fxa2hi4hbdzqbvwtvgy0m.png" alt="TypeScript Zod library" width="200" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also use Zod for validating incoming data, it ensure its validity before processing by the backend. It's a TypeScript library that allows you to define a schema for your data and validate it. It's a lightweight alternative to Joi and Yup. Additionally, it can prevent bugs and security issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Infrastructure
&lt;/h2&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%2Flimm8maf69lh8kjzyf9f.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%2Flimm8maf69lh8kjzyf9f.png" alt="AWS CDK IaaS" width="800" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The frontend and backend codes also need to work with other services. I use AWS CDK to configure and manage the other AWS services. With AWS CDK, I can use JavaScript and TypeScript to define cloud infrastructure. So, I don't need to manually set up in AWS Console by clicking around.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authentication
&lt;/h3&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%2Fg1yhpa5x2t65g7ckyt8f.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%2Fg1yhpa5x2t65g7ckyt8f.png" alt="AWS Cognito Authentication" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I use AWS Cognito to manage users. With Cognito, you can limit access to your application and provide a way for users to sign in. Only authenticated users can access the dashboard and use the SaaS.&lt;/p&gt;

&lt;p&gt;In the front end, I use AWS Amplify for the authentication flow. Amplify abstracts the communication with Cognito and makes it easy. With a few lines of code, I've set up the signup, sign-in, social sign-in, and more. I don't lose my time implementing an authentication from scratch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Database
&lt;/h3&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%2Fgl52onlhwhxbmjggt8rv.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%2Fgl52onlhwhxbmjggt8rv.png" alt="AWS DynamoDB NoSQL database" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For data storage, I use AWS DynamoDB, a fully managed NoSQL database service that seamlessly integrates into the AWS ecosystem and works extremely well with AWS Lambda.&lt;/p&gt;

&lt;p&gt;One disadvantage of serverless architecture is its difficulty in working with SQL databases. For instance, you need to set up a connection pool to connect to the database. Otherwise, it will exhaust your server resources. The good news with DynamoDB, I don't need to worry about it because there isn't any connection limit you need to manage.&lt;/p&gt;

&lt;h3&gt;
  
  
  Logging
&lt;/h3&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%2Fg9tw148dj2bufb49kksx.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%2Fg9tw148dj2bufb49kksx.png" alt="Pino.js logging node.js" width="800" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The application uses Pino.js as a logging library. It's a very fast JSON logger for Node.js. With the &lt;code&gt;pino-lambda&lt;/code&gt; plugin, Pino is fully compatible with AWS Lambda.&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%2F2d2qff9o3g893spt2ix8.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%2F2d2qff9o3g893spt2ix8.png" alt="Lambda Cloudwatch dashboard" width="800" height="159"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Logs are directly sent to CloudWatch, a monitoring and log management service. It's a fully managed service that allows you to store, monitor, and access your log files from AWS services.&lt;/p&gt;

&lt;p&gt;You can set up an alert when the application goes wrong with CloudWatch. You can also create a custom dashboard to gain insight into the performance of your application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Email service
&lt;/h3&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%2F7l6zxep4vtdpua38v8zj.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%2F7l6zxep4vtdpua38v8zj.png" alt="AWS SES Email provider" width="189" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In SaaS applications, you have several reasons to send emails to your users. When they sign up for the first time, you need to send them a welcome email so they can confirm their email address. When they forget their password, you need to send them a reset password email.&lt;/p&gt;

&lt;p&gt;To remain in the AWS ecosystem, I use AWS SES, a fully managed email-sending service. I choose not to rely on a third-party email service like SendGrid, Mailgun, or Postmark.&lt;/p&gt;

&lt;h2&gt;
  
  
  Subscription payment
&lt;/h2&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%2Fd1dyyiejl0667byanl0x.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%2Fd1dyyiejl0667byanl0x.png" alt="Stripe checkout page" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To monetize your SaaS product, you need to charge your users. I use Stripe to handle the payment. It's a payment processing platform that allows you to accept payments online. In the application, the users can choose their subscription plan and it'll redirect them to the Stripe checkout page. On the checkout page, they can enter their credit card information and pay for the subscription.&lt;/p&gt;

&lt;p&gt;When the payment is successful, Stripe will trigger a webhook to the backend. The backend needs to listen to the Stripe events and update the user's subscription status in the database.&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%2Frf57cnsnjtmfdowg4xgb.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%2Frf57cnsnjtmfdowg4xgb.png" alt="Stripe customer portal" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Additionally, we need to provide users with the capability to update or cancel their subscriptions. To do this, I use Stripe's customer portal. It's a hosted page where the users can self-manage their subscriptions.&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%2Far9tcce5es4aofvy8sb1.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%2Far9tcce5es4aofvy8sb1.png" alt="Stripe logo" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;In this article, we learn how to build a SaaS product on AWS. A deep dive into all the components of the architecture and how they work together to provide a scalable, secure, and reliable SaaS product.&lt;/p&gt;

&lt;p&gt;If you are currently building or planning to build your own SaaS product, you should be interested in my &lt;a href="https://nextlessjs.com" rel="noopener noreferrer"&gt;AWS SaaS Boilerplate&lt;/a&gt;. It's a React SaaS boilerplate that includes everything you need in a SaaS product. Fully hosted on AWS, you can deploy it in a few minutes with the same stack described in this post. So, you can use it as a starting point to build your own SaaS product and earn your 1st MRR.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nextlessjs.com" rel="noopener noreferrer"&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%2F1pxd78i3fsvsb9fnisn0.jpg" alt="React SaaS Boilerplate" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>assemblyaichallenge</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Build a Free Twitter Scheduler with Next.js</title>
      <dc:creator>Remi W.</dc:creator>
      <pubDate>Thu, 08 Dec 2022 17:24:52 +0000</pubDate>
      <link>https://dev.to/ixartz/build-a-free-twitter-scheduler-with-nextjs-41jf</link>
      <guid>https://dev.to/ixartz/build-a-free-twitter-scheduler-with-nextjs-41jf</guid>
      <description>&lt;p&gt;Twitter is a popular social media platform for developers to share their thoughts, ideas, and opinions with a global audience. It's a great way to connect with other developers, stay up-to-date on the latest trends and technologies, and showcase their work to the world.&lt;/p&gt;

&lt;p&gt;To get the most out of Twitter, you need to post regularly. By planning and scheduling your tweets in advance, you can save time and increase your engagement. There are many paid SaaS (Software as a Service) solutions that allow users to schedule posts on social media platforms. However, these services can be expensive and require a subscription.&lt;/p&gt;

&lt;p&gt;In this article, we'll build our own solution using Next.js, a React framework for building full-stack applications. First, we need to save our tweets to a &lt;a href="https://upstash.com/?utm_source=remi1" rel="noopener noreferrer"&gt;Redis database, Upstash&lt;/a&gt;. Then, we'll create a Next.js API route to fetch the tweets from the database. Finally, we'll use the Twitter API to post the tweets to our account.&lt;/p&gt;

&lt;h2&gt;
  
  
  UI and Forms
&lt;/h2&gt;

&lt;p&gt;We start by creating a simple UI to schedule our tweets. As the creator of Next.js Boilerplate, I use my own boilerplate to get started. Next.js Boilerplate is a Next.js starter template that includes a fully configured project with all the tools you need to build a production-ready application. The source code for this project is available on GitHub at &lt;a href="https://github.com/ixartz/Next-js-Boilerplate" rel="noopener noreferrer"&gt;Next.js Boilerplate&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To get started, we need to add the following dependencies to our 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;react-hook-form @upstash/redis @upstash/qstash axios
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use the &lt;code&gt;react-hook-form&lt;/code&gt; library to handle the form state. In &lt;code&gt;src/pages&lt;/code&gt; folder, we create a new page &lt;code&gt;add-tweet.tsx&lt;/code&gt; and add a simple 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;axios&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;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;useForm&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-hook-form&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;AddTweet&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;register&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reset&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useForm&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;onSubmit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&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="s1"&gt;/api/add-tweet/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nf"&gt;reset&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;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;onSubmit&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;
        Message:
        &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="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&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="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;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Scheduled date:
        &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;"datetime-local"&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scheduledDate&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;valueAsDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="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;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;"submit"&lt;/span&gt; &lt;span class="na"&gt;value&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;
    &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;);&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;AddTweet&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Global Redis Database
&lt;/h2&gt;

&lt;p&gt;For the database part, we use &lt;a href="https://upstash.com/?utm_source=remi1" rel="noopener noreferrer"&gt;Upstash&lt;/a&gt;, a fully managed Redis database. Upstash is a solution for developers who want to build applications without worrying and managing the database. Another advantage of Upstash is that it can be run on the edge, which results in a faster response time. It works extremely well with Edge API Routes.&lt;/p&gt;

&lt;p&gt;To get started, we need to create a new account on Upstash. Once you've created an account, you'll be able to create a new database. We use the free plan for this project, which includes 10,000 requests per month (2,000 for the global database).&lt;/p&gt;

&lt;p&gt;Once you've created an Upstash account, you need to create a new database:&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fcreate-global-redis-database-upstash.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fcreate-global-redis-database-upstash.png" alt="Redis global database on Upstash"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect to the Redis database
&lt;/h3&gt;

&lt;p&gt;To connect to the Upstash Redis database, we use the &lt;code&gt;@upstash/redis&lt;/code&gt; package. We also need to create a new file called &lt;code&gt;src/utils/Redis.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Redis&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;@upstash/redis&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Redis&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="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;UPSTASH_REDIS_REST_URL&lt;/span&gt; &lt;span class="o"&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;token&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;UPSTASH_REDIS_REST_TOKEN&lt;/span&gt; &lt;span class="o"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To access the &lt;code&gt;UPSTASH_REDIS_REST_URL&lt;/code&gt; value, go to your Upstash dashboard. Once you've copied the Redis REST URL, you can paste it into the &lt;code&gt;.env&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;UPSTASH_REDIS_REST_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://XXXXXXXX.upstash.io
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition to the &lt;code&gt;UPSTASH_REDIS_REST_URL&lt;/code&gt; value, you also need to copy the &lt;code&gt;UPSTASH_REDIS_REST_TOKEN&lt;/code&gt; variable from your Upstash dashboard. But, this time, please past the value into the &lt;code&gt;.env.local&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;UPSTASH_REDIS_REST_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;XXXXXXXX
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to keep our secret variables safe, it is a good practice to store them in the &lt;code&gt;.env.local&lt;/code&gt; file. Since this file is not committed to the Git repository, our secrets will not be exposed to anyone who has access to the repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Edge API Routes to store in the database
&lt;/h2&gt;

&lt;p&gt;We need to define a schema by creating a new file &lt;code&gt;src/types/Tweet.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;IAddTweet&lt;/span&gt; &lt;span class="o"&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;scheduledDate&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we create a new file &lt;code&gt;src/pages/api/add-tweet.ts&lt;/code&gt; to handle the form submission. We use the &lt;code&gt;@upstash/redis&lt;/code&gt; library to connect to our Redis database and save the tweet.&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="kd"&gt;type&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;IAddTweet&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;@/types/Tweet&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;redis&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;@/utils/Redis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handler&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reqJson&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IAddTweet&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zadd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tweet&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;score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reqJson&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scheduledDate&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// convert to seconds&lt;/span&gt;
    &lt;span class="na"&gt;member&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;reqJson&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="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="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="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="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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;experimental-edge&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;To make our API route accessible extremely fast, we use the Edge API Routes feature of Next.js. Edge API Routes are serverless functions that run on the edge. This means that our API route will be executed close to the user, which results in a faster response time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Post on Twitter using code
&lt;/h2&gt;

&lt;p&gt;We also need to create another API route to post automatically to Twitter.&lt;/p&gt;

&lt;p&gt;To get started, we need to create a new Twitter app. Once you've created a new app, you'll be able to generate the necessary tokens. We use these tokens to connect to the Twitter API and create our first tweet using code.&lt;/p&gt;

&lt;p&gt;We define a new variable &lt;code&gt;TWITTER_BEARER_TOKEN&lt;/code&gt; in the &lt;code&gt;.env.local&lt;/code&gt; file so that the application has the necessary permissions to post on Twitter.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;src/pages/api/schedule-tweet.ts&lt;/code&gt;, we add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&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;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="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&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&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handler&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;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&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="s1"&gt;https://api.twitter.com/2/tweets&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;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test message&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="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="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &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;TWITTER_BEARER_TOKEN&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="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;To test our API route, we can open &lt;code&gt;localhost:3000/api/schedule-tweet&lt;/code&gt; in the browser. If everything is correctly set up, we should see a new tweet on your Twitter account.&lt;/p&gt;

&lt;h2&gt;
  
  
  Schedule your tweets
&lt;/h2&gt;

&lt;p&gt;We've successfully created our first tweet programmatically, but to take things to the next level, we need to schedule our tweets for a specific time in the future. This way, we can ensure that our tweets are sent out at the most effective time for maximum engagement and reach.&lt;/p&gt;

&lt;p&gt;Unfortunately, it only works if we run the API route manually. To automate the process, we need to use a cron job. A cron job is a task that runs periodically at a specified time. And, with Serverless Functions, we don't have access to a cron job. To solve this problem, we can use an external service like Upstash QStash. QStash is a scheduling solution for serverless applications.&lt;/p&gt;

&lt;p&gt;Now, we need to update the API endpoint and we can retrieve the tweets from the database and check if any of them are scheduled to be posted. In &lt;code&gt;src/pages/api/schedule-tweet.ts&lt;/code&gt;, we add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;verifySignature&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;@upstash/qstash/nextjs&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;axios&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;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="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&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&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;redis&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;@/utils/Redis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&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;handler&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;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&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;currentTimestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&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;list&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;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tweet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currentTimestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;byScore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Run sequentially the requests to prevent overloading Twitter API&lt;/span&gt;
    &lt;span class="k"&gt;await&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="s1"&gt;https://api.twitter.com/2/tweets&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;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&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="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="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &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;TWITTER_BEARER_TOKEN&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="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;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zremrangebyscore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tweet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currentTimestamp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="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="nf"&gt;verifySignature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="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;The &lt;code&gt;verifySignature&lt;/code&gt; requires two environment variables: &lt;code&gt;QSTASH_CURRENT_SIGNING_KEY&lt;/code&gt; and &lt;code&gt;QSTASH_NEXT_SIGNING_KEY&lt;/code&gt;. These variables are used to verify the signature of the requests. So, we can make sure that the requests are coming from QStash and not from a bad actor. You can get these variable values from your Upstash dashboard.&lt;/p&gt;

&lt;p&gt;You also need to deploy the Next.js application to a publically accessible URL. For example, you can deploy on Vercel. So, QStash can send a request to the API endpoint &lt;code&gt;api/schedule-tweet&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After deploying your Next.js app, in your Upstash dashboard, you can go to the QStash section and create a new &lt;code&gt;Request Builder&lt;/code&gt;. You also need to add the endpoint URL and the frequency of the cron job. In this example, it'll run the cron job every day.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fqstash-next-js-cron-scheduled-job.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fqstash-next-js-cron-scheduled-job.png" alt="QStash Next.js Cron job"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And, you can change the frequency of the cron job based on your needs. For example, you can change it to every minute or every hour.&lt;/p&gt;

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

&lt;p&gt;In this article, we've built a Twitter scheduler using Next.js and &lt;a href="https://upstash.com/?utm_source=remi1" rel="noopener noreferrer"&gt;Upstash&lt;/a&gt;. We've used Next.js API routes to store the tweets in a Redis database and schedule them for a specific time in the future. We've also used the Twitter API to post the tweets to our account.&lt;/p&gt;

&lt;p&gt;By building your own Twitter scheduler, you can avoid using expensive SaaS solutions and save money. You can also use this project as a starting point and improve based on your needs.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>nextjs</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Currying Layout Component Patterns in Next.js</title>
      <dc:creator>Remi W.</dc:creator>
      <pubDate>Fri, 21 Oct 2022 11:18:22 +0000</pubDate>
      <link>https://dev.to/ixartz/currying-layout-component-patterns-in-nextjs-4l1l</link>
      <guid>https://dev.to/ixartz/currying-layout-component-patterns-in-nextjs-4l1l</guid>
      <description>&lt;p&gt;In Next.js, you can use the &lt;strong&gt;Layout component pattern&lt;/strong&gt; by adding the &lt;code&gt;getLayout&lt;/code&gt; property to the pages. This property is a function that returns a React component. The Layout component can be used to add &lt;em&gt;common UI elements&lt;/em&gt; to all pages, such as navigation or footer.&lt;/p&gt;

&lt;p&gt;Not only this pattern avoids duplicate code, but it can also persist state between page navigations. It's a great way to add a &lt;strong&gt;Single-Page Application&lt;/strong&gt; (SPA) experience to your Next.js application.&lt;/p&gt;

&lt;p&gt;You can find more details about this pattern in &lt;a href="https://nextjs.org/docs/basic-features/layouts"&gt;the Next.js documentation&lt;/a&gt;. But, the first time I saw this pattern was from Adam Wathan's blog post about &lt;a href="https://adamwathan.me/2019/10/17/persistent-layout-patterns-in-nextjs/"&gt;Persistent Layout Patterns in Next.js&lt;/a&gt;. He really gives a great explanation of this pattern and how to use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The limitation of the Layout component pattern
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Layout component pattern&lt;/strong&gt; is extremely useful when some parts of the UI elements are &lt;em&gt;exactly the same&lt;/em&gt;. For example, the footer of the website: between each page, the footer doesn't change at all.&lt;/p&gt;

&lt;p&gt;So, you can easily create a &lt;em&gt;function that returns the footer&lt;/em&gt;. Then, you can use it as the Layout component in all Next.js pages. Here is a simple example of a Layout component that returns a footer:&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;getFooter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ReactElement&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Footer&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;page&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Footer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Next.js pages, you can use this function as the Layout component:&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="c1"&gt;// pages/index.js&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="nx"&gt;Page&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="cm"&gt;/** Your content */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getFooter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But for more complex applications, like the user/admin dashboard, the common UI elements can be &lt;em&gt;slightly different&lt;/em&gt; between pages. I would love to &lt;em&gt;add a title to the header&lt;/em&gt;, and for each page the title is different. Here is an example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X3plR7NA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://creativedesignsguru.com/assets/images/themes/next-js-layout-pattern.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X3plR7NA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://creativedesignsguru.com/assets/images/themes/next-js-layout-pattern.png" alt="Nextjs layout pattern" width="880" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--odyPaIsG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://creativedesignsguru.com/assets/images/themes/nextjs-layout-component.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--odyPaIsG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://creativedesignsguru.com/assets/images/themes/nextjs-layout-component.png" alt="Next.js layout component" width="880" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And, the only difference between the pages is the title. The rest of the UI elements are the same. So, how can I reuse the &lt;strong&gt;Layout component&lt;/strong&gt; and still be able to change the title? You can create a new function for each different title, but it's not a good solution. Here is a potential example:&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;getDashboardChangeEmail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ReactElement&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AuthProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;StateProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Dashboard&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Change Email"&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;page&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Dashboard&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;StateProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;AuthProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;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;getDashboardChangePassword&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ReactElement&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AuthProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;StateProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Dashboard&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Change password"&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;page&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Dashboard&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;StateProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;AuthProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have to create a new function for each different title. You have a lot of &lt;em&gt;duplicate code&lt;/em&gt; and it's &lt;em&gt;hard to maintain&lt;/em&gt;. And, if you want to add a new component, you need to update all of them.&lt;/p&gt;

&lt;p&gt;::: newsletter&lt;/p&gt;

&lt;h2&gt;
  
  
  Currying Layout component is the solution
&lt;/h2&gt;

&lt;p&gt;Instead of duplicating code for each title, you can &lt;strong&gt;curry the function&lt;/strong&gt;. Now, you can create a function that takes the &lt;code&gt;title&lt;/code&gt; as a &lt;em&gt;parameter&lt;/em&gt; and &lt;em&gt;return a function&lt;/em&gt;. And the second function will return the React component:&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;getDashboard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;title&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;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ReactElement&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AuthProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;StateProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Dashboard&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&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;page&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Dashboard&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;StateProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;AuthProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And, here is how you can use it on Next.js pages:&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="c1"&gt;// pages/change-email.js&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="nx"&gt;Page&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="cm"&gt;/** Your content */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getDashboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Change Email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// pages/change-password.js&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="nx"&gt;Page&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="cm"&gt;/** Your content */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getDashboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Change Password&lt;/span&gt;&lt;span class="dl"&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, we can reuse the same &lt;strong&gt;Layout component&lt;/strong&gt; for all pages. And, we can still &lt;em&gt;change the title&lt;/em&gt; for each page. The code isn't duplicated anymore. It also doesn't require a lot of changes to the existing code.&lt;/p&gt;

&lt;p&gt;I'm totally open to &lt;em&gt;any feedback or suggestions&lt;/em&gt;, please feel free to contact me on Twitter at &lt;a href="https://twitter.com/ixartz"&gt;@ixartz&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>nextjs</category>
      <category>react</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Build the future of web development with Next.js Edge Rendering and globally distributed database</title>
      <dc:creator>Remi W.</dc:creator>
      <pubDate>Wed, 05 Oct 2022 17:14:17 +0000</pubDate>
      <link>https://dev.to/ixartz/build-the-future-of-web-development-with-nextjs-edge-rendering-and-globally-distributed-database-8o6</link>
      <guid>https://dev.to/ixartz/build-the-future-of-web-development-with-nextjs-edge-rendering-and-globally-distributed-database-8o6</guid>
      <description>&lt;p&gt;Next.js allows you to build React applications. Recently, it gained a lot of popularity because of the great developer experience and many other features that make it a joy to use.&lt;/p&gt;

&lt;p&gt;In this article, we will build a state-of-the-art web application with Next.js Edge and &lt;a href="https://upstash.com/?utm_source=remi1" rel="noopener noreferrer"&gt;Upstash Redis&lt;/a&gt;. With the recent developments in Edge computing, we will use the newest features from Next.js (Edge SSR and Edge API Routes) to build an application that is blazing fast, fully distributed and scalable. And, the good news is that it's 100% serverless with no server management.&lt;/p&gt;

&lt;p&gt;To illustrate the power of edge computing, we will create a simple URL shortener application. A URL shortener is a service that takes a URL and converts it into a shorter URL. This is useful when you want to share a URL on Twitter or other social media platforms. It's also useful when you want to hide the actual URL from the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  Edge Computing
&lt;/h2&gt;

&lt;p&gt;In the past, Static Site Generation (SSG) in Next.js was served from the edge with the help of CDN. The static HTML content is deployed around the world and the user gets the content from the nearest edge location. It is a great way to reduce the latency and improve the performance of the application.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fcdn-nextjs-edge-global-database.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fcdn-nextjs-edge-global-database.png" alt="Next.js SSG CDN"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For dynamic content, Next.js provides Server Side Rendering (SSR). The content is generated on the server and sent to the client. In the past, compared to SSG, SSR was only deployed in a single location for an easy setup.&lt;/p&gt;

&lt;p&gt;With the latest version of Next.js (Next.js 12.2), we have access to the Edge Rendering. The feature is still in experimental mode, but you can already try it out. This allows to deploy SSR and API routes at the edge. So, the dynamic content can now be served from multiple locations in one configuration.&lt;/p&gt;

&lt;p&gt;After moving to the edge, there is a bottleneck with the database. Due to the complexity and operational cost, it was hard to deploy the database in multiple locations. But, with recent and modern database providers like Upstash, we can now deploy a global Redis database in one click. The perfect match for the Edge Rendering/Computing. On top of that, Upstash is a serverless database, so you don't have to worry about the infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Edge Server-Rendering
&lt;/h2&gt;

&lt;p&gt;We'll use Next.js Boilerplate as a starting point. It's a great way to start with Next.js with TypeScript and Tailwind CSS. It's also configured with ESLint, Prettier, Husky, Jest and Cypress. You can find the source code on GitHub at &lt;a href="https://github.com/ixartz/Next-js-Boilerplate" rel="noopener noreferrer"&gt;Next.js Boilerplate&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, let's create a new &lt;code&gt;admin&lt;/code&gt; folder with a new Page named &lt;code&gt;src/pages/admin/index.tsx&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="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;InferGetServerSidePropsType&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&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;Index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;InferGetServerSidePropsType&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;getServerSideProps&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;&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="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&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;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getServerSideProps&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;runtime&lt;/span&gt; &lt;span class="o"&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_RUNTIME&lt;/span&gt; &lt;span class="o"&gt;||&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="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;runtime&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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;experimental-edge&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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;runtime&lt;/code&gt; configuration can be set on all pages when you want to deploy at the edge. By default, the &lt;code&gt;runtime&lt;/code&gt; is set to &lt;code&gt;nodejs&lt;/code&gt;. But, for Edge Rendering, we need to set it to &lt;code&gt;experimental-edge&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After deploying the application, you can see that the page is rendered at the edge. You can check it out by opening the page in the browser and the server should return &lt;code&gt;edge&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/@ixartz/build-the-future-of-web-development-with-next-js-3f6414f93b25" rel="noopener noreferrer"&gt;&lt;strong&gt;Read the rest on Medium&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>nextjs</category>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How I host my Full-stack Application SaaS for Free on AWS</title>
      <dc:creator>Remi W.</dc:creator>
      <pubDate>Wed, 27 Jul 2022 14:04:45 +0000</pubDate>
      <link>https://dev.to/ixartz/how-i-host-my-full-stack-application-saas-for-free-on-aws-41ij</link>
      <guid>https://dev.to/ixartz/how-i-host-my-full-stack-application-saas-for-free-on-aws-41ij</guid>
      <description>&lt;p&gt;Deploying your application to production can become quite expensive on AWS if you don't take the time to think about your infrastructure. In this article, I will show you how I manage to host my full-stack application for free on AWS: Frontend, Backend, Database, Monitoring and Email service, all hosted for free on AWS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;I'm an indie maker with limited financial resources, I need to optimize the hosting costs. If you are working for a larger company, this article can still give you some idea on how to reduce your cost on AWS.&lt;/p&gt;

&lt;p&gt;My whole application is hosted on AWS. Because everything is centralized on AWS, it makes easier to manage the infrastructure. Also, as a solo developer with limited time, the infrastructure is 100% serverless. So, you don't need to worry about server management, AWS handles it for you. They configure and update the server for you. Thanks to the centralization and serverless, I can focus on my business and product.&lt;/p&gt;

&lt;p&gt;You can check out the live demo of my application at the &lt;a href="https://demo.nextlessjs.com" rel="noopener noreferrer"&gt;full-stack React Boilerplate demo&lt;/a&gt;. Or, if you need to see a real SaaS product, you can check out &lt;a href="https://postmage.com" rel="noopener noreferrer"&gt;PostMage&lt;/a&gt; app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authentication
&lt;/h2&gt;

&lt;p&gt;Let's start by looking at the authentication where I use AWS Cognito to secure my full-stack application. All the authentication system is managed and secured by AWS, so I don't need to worry about it. With Cognito, it's extremely easy to implement email and social authentication with Google, Facebook, Amazon and Apple.&lt;/p&gt;

&lt;p&gt;The good news is that AWS Cognito has a very generous free tier policy. Below 50,000 monthly active users, you can stay at the free tier without any time limitation (always free). I think it's one of the most generous free-tier policies in the market. For example, Auth0 only offers 7,000 monthly active users.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Faws-cognito-logo.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Faws-cognito-logo.png" alt="AWS Cognito email auth"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Frontend
&lt;/h2&gt;

&lt;p&gt;The developer experience has recently improved with Netlify and Vercel. With these two tools, I can build and deploy your frontend directly from your GitHub repository. Did you know you can have the same experience with AWS without any external services? Yes, with AWS Amplify Hosting, you can host your frontend on AWS without compromising on your developer experience.&lt;/p&gt;

&lt;p&gt;AWS Amplify Hosting also offers a free tier, but it's limited to one year. The free plan includes 1,000 build minutes and 15 GB of bandwidth per month. Compared to Vercel and Netlify, you don't need to pay a subscription for each developer seat. With Amplify Hosting, you only need to pay based on your usage.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Faws-amplify-logo.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Faws-amplify-logo.png" alt="AWS Amplify Hosting logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Backend
&lt;/h2&gt;

&lt;p&gt;For the REST API, I host it on AWS Lambda, the serverless computer service from AWS. No need to set up an EC2 instance to host a backend. So, no need to update your server and no need to manage the scaling. With AWS Lambda, you only need to deploy your code and AWS will take care of the rest.&lt;/p&gt;

&lt;p&gt;You can invoke your AWS Lambda 1 million requests per month for free. And, it isn't limited in time. When you go above the free tier, you only need to pay based on the number of requests. Basically, you don't need to pay anything if you don't have any requests.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Faws-lambda-serverless.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Faws-lambda-serverless.png" alt="AWS Lambda"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the past, you usually need an API gateway. It's needed to route requests to the correct Lambda function. It also comes at a small cost. But, again, there is also a free tier ;) Like AWS Lambda, the API gateway can handle 1 million requests per month for free. More recently, AWS has released AWS Lambda Function URLs. So, you can directly invoke your Lambda function without an API gateway. And, the good news with AWS Lambda Function URLs is free with Lambda.&lt;/p&gt;

&lt;h2&gt;
  
  
  Database
&lt;/h2&gt;

&lt;p&gt;You might already notice that there aren't a lot of providers for serverless databases. Fortunately for us, DynamoDB checks all the requirements you expected for a serverless database: scale to zero, pay per request, automatically manage the scaling, and so on. So, I choose DynamoDB as my database for my SaaS application.&lt;/p&gt;

&lt;p&gt;Again I won't disappoint you ;) DynamoDB has a very generous always free tier policy: 25 GB of storage, 25 provisioned Write and Read Capacity. Based on the official description, this enough to handle 200 million requests per month. I don't know this is true or not, but I think it's definitely enough to handle a middle-sized application for free.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Faws-dynamodb-logo.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Faws-dynamodb-logo.png" alt="AWS DynamoDB serverless database"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring, Logging and Observability
&lt;/h2&gt;

&lt;p&gt;The infrastructure is 100% serverless and managed by AWS. But, I still need to keep an eye on the application to see if there are any errors. So, I use CloudWatch to monitor the application and the infrastructure. I also set up some alerts to be notified when something goes wrong.&lt;/p&gt;

&lt;p&gt;For CloudWatch, AWS offers an always-free tier: 10 custom metrics, 10 alarms, 5GB of log ingestion, etc. Using only what the free tier offering, you can still have a better idea of how your application is behaving in production.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Faws-cloudwatch-logo.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Faws-cloudwatch-logo.png" alt="AWS Cloudwatch monitoring"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Email
&lt;/h2&gt;

&lt;p&gt;By using AWS Cognito for the authentication, there are several steps in the authentication process where Cognito will send an email with AWS SES. For example, if you have a registration form, you can send a confirmation email to the user after he registers.&lt;/p&gt;

&lt;p&gt;Not only for the authentication, but the application itself also needs to send an email. My SaaS application has team support where users can invite their friends or coworker to work together in the same workspace. So, the application needs to send an email when the user start inviting his friends.&lt;/p&gt;

&lt;p&gt;You won't get any surprise ;) But, AWS SES has an extremely generous always-free tier: you can send 62,000 emails per month for free. I think it's one of the most generous free tiers in the market for email service.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Faws-ses-logo.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Faws-ses-logo.png" alt="AWS Email service SES"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;All the AWS services I used for my SaaS application have a free tier. Currently, I'm paying nothing for hosting my full-stack application on AWS. In this article, I hope I give you some inspiration on how you can also reduce your AWS bill.&lt;/p&gt;

&lt;p&gt;If you like my article and my stack, you should be definitively interested in my &lt;a href="https://nextlessjs.com" rel="noopener noreferrer"&gt;Full-stack React Boilerplate&lt;/a&gt;, a pre-configured template for you to start a new project quickly. It's exactly the same stack mentioned in the article: 100% serverless hosted on AWS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nextlessjs.com" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnext-js-saas-starter-kit.jpg" alt="React SaaS Template Starter"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll find inside the boilerplate everything configures for you. It includes TypeScript, Tailwind CSS, Serverless framework, Linter, Code formatter, Jest, Cypress and VSCode configuration. So, you don't need to lose your time fighting with configuration files.&lt;/p&gt;

&lt;p&gt;Not only you'll find configuration files in the boilerplate, but you'll also find code for your application. For example, it includes pre-built code for authentication, landing page, user dashboard, multi-tenancy support (team support), subscription payment, and more. Instead of wasting time reinventing the wheel and developing from scratch, you can focus on the core of your project. It'll save you months of development time.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>react</category>
      <category>aws</category>
    </item>
    <item>
      <title>How to get 2000+ stars on GitHub with 11 places to promote your project</title>
      <dc:creator>Remi W.</dc:creator>
      <pubDate>Thu, 21 Jul 2022 15:51:14 +0000</pubDate>
      <link>https://dev.to/ixartz/how-to-get-2000-stars-on-github-with-11-places-to-promote-your-project-2o3h</link>
      <guid>https://dev.to/ixartz/how-to-get-2000-stars-on-github-with-11-places-to-promote-your-project-2o3h</guid>
      <description>&lt;p&gt;My &lt;a href="https://github.com/ixartz/Next-js-Boilerplate" rel="noopener noreferrer"&gt;React Boilerplate with Next.js&lt;/a&gt; has recently reached 2000+ stars on GitHub. In the last months, I've continuously been working on improving the project and adding new features. Unfortunately, this isn't enough to get the project noticed by the community. I've also spent my time promoting the project on many platforms and in this article, I'll share with you my 11 places to promote an open source project.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnextjs-boilerplate-github-stars.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnextjs-boilerplate-github-stars.png" alt="Next.js Boilerplate Github Stars"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparation for a successful promotion
&lt;/h2&gt;

&lt;p&gt;Before promoting your project, you need to make sure other developers will be interested in it. In my case, as an indie maker, I constantly build new products. So, I was losing my time installing and configuring new React projects again and again. For example, I was spending my time configuring TypeScript, ESLint, Prettier, Jest, Cypress and other JavaScript-related tools.&lt;/p&gt;

&lt;p&gt;With this frustration, I've decided to create a React boilerplate that you can use to start quickly a new project. I thought other people would have the same pain. So, I made the project open source and accessible to everyone.&lt;/p&gt;

&lt;p&gt;You also need to make sure your project is easy to use. Any documentation, tutorials or README you provide will help other developers to get started. Especially if you have a good-looking README file, it'll definitively increase your chances of getting a good first impression and a star on your GitHub project.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnext-js-boilerplate-readme.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnext-js-boilerplate-readme.png" alt="Next.js Boilerplate README example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After making sure that everything is in place, we can start promoting in these 11 places.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Google with SEO
&lt;/h3&gt;

&lt;p&gt;For my React Boilerplate, the project is currently ranked number 1 on Google for the keyword &lt;code&gt;Next.js Boilerplate&lt;/code&gt;. It brings a lot of traffic to the repository and increases the number of stars on GitHub. Actually, the project got the most traffic from Google: Google brings more traffic than GitHub itself. That's why it's extremely important to write the README file for Google to index.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnext-js-boilerplate-google.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnext-js-boilerplate-google.png" alt="Next.js Boilerplate Google ranking"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The good thing about SEO is that you only need to set it up once. Then, your project automatically gets some traffic from Google. It's fully passive. But, SEO is hard and complex, especially if you target a highly competitive keyword. There are a lot of factors that can influence your Google ranking. It requires you to invest your time to learn about the SEO strategy and how to implement it.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Twitter
&lt;/h3&gt;

&lt;p&gt;As you already know, Twitter has a large number of developers that can be interested in your project. If you have a large based of followers, you shouldn't have any issues getting noticed when you start promoting your project.&lt;/p&gt;

&lt;p&gt;But, when you don't have a lot of followers like me, you need to make sure you have a good chance to get noticed. You should add some hashtags to your tweet, it'll help you to increase your reach. For example, you can add some hashtags like the technology stack you use to build your open source project like #react, #reactjs, #javaScript, #webdev, #nextjs, etc.&lt;/p&gt;

&lt;p&gt;Here is one example of my tweet where I got 40 likes and 21 retweets (by having only 100 followers):&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnextjs-boilerplate-twitter.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnextjs-boilerplate-twitter.png" alt="Next.js Boilerplate twitter"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Reddit
&lt;/h3&gt;

&lt;p&gt;Reddit has also a large community of programmers who can support you by giving you a star on your project. There are communities for almost every technology stack. For example, there is a subreddit for React named &lt;code&gt;/r/reactjs&lt;/code&gt;. And, there is also a subreddit for Node.js, JavaScript, TypeScript, AWS, etc. You won't have difficulty finding a community where it makes sense to promote your project.&lt;/p&gt;

&lt;p&gt;For your information, each subreddits has different rules and guidelines. Some subreddits are more strict than others. I suggest you take some time to read them and make sure you follow them.&lt;/p&gt;

&lt;p&gt;For one of my posts on Reddit, I got XXX upvotes which translates to a lot of stars on GitHub (I don't remember the exact number):&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnext-js-boilerplate-reddit.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnext-js-boilerplate-reddit.png" alt="Next.js Boilerplate Reddit"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Awesome lists
&lt;/h3&gt;

&lt;p&gt;You can find a similar list directly on GitHub with &lt;a href="https://github.com/sindresorhus/awesome" rel="noopener noreferrer"&gt;Awesome Lists&lt;/a&gt;. There is almost an Awesome list for each technology stack and each field in software engineering. It shouldn't be hard to find a list that fits your project. For Next.js Boilerplate, I've posted into these lists:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/aniftyco/awesome-tailwindcss" rel="noopener noreferrer"&gt;Awesome Tailwind CSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dabit3/awesome-aws-amplify" rel="noopener noreferrer"&gt;Awesome AWS Amplify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/automata/awesome-jamstack" rel="noopener noreferrer"&gt;Awesome JAMStack&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Publish aggregator websites
&lt;/h3&gt;

&lt;p&gt;There are several websites that list projects using a specific technology stack. For example, BestOfJs is a website that aggregates open source projects built with JavaScript. You can find a similar website for React, Vue, Tailwind CSS, and more.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnextjs-boilerplate-bestofjs.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnextjs-boilerplate-bestofjs.png" alt="Next.js best of js"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Indie Hacker
&lt;/h3&gt;

&lt;p&gt;Not everybody on Indie Hacker is a developer. So, not everybody will be interested in your open-source project. But, one of the largest groups on Indie Hacker are developers. People on indie hackers are building a startup or bootstrap company. So if your project can help them in their business, you should promote it on Indie Hacker.&lt;/p&gt;

&lt;p&gt;My React Boilerplate Template helps developers to start a new project. So, indie makers can use it to start their new productl, whether for a landing page, a SaaS, a blog, etc. That's why I've done some promotions on Indie Hacker.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Write a blog post
&lt;/h3&gt;

&lt;p&gt;You can write a blog post about your project on your blog if you have one. So, you can share your vision and your idea. It's the perfect solution to promote your project. Or, you can also write a tutorial on how to use your project.&lt;/p&gt;

&lt;p&gt;You can also post on Dev.to, Hashnode, Medium, or any other platform as an alternative. Or, you can republish your blog post from your personal blog into these platforms.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Discord
&lt;/h3&gt;

&lt;p&gt;Today, most open source project has a discord channel where they can discuss with other developers. A great way to get help from other developers and you can connect with others who use the same technology. For example, there is a discord channel for React developers named &lt;code&gt;Reactiflux&lt;/code&gt;. If your project uses React, it makes sense to join the server and promote your project.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fdiscord-react-reactiflux.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fdiscord-react-reactiflux.png" alt="Discord react reactiflux"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Newsletter
&lt;/h3&gt;

&lt;p&gt;You can find a lot of newsletters for developers. For example, you can find a newsletter for JavaScript developers called &lt;code&gt;JavaScript Weekly&lt;/code&gt;. You can definitively try to contact them to see if they are interested in featuring your project in their newsletter. Like on Reddit, you can definitely find a newsletter where your project can be promoted. There is almost a newsletter for each technology stack and each field in software engineering.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. GitHub Trends
&lt;/h3&gt;

&lt;p&gt;Your project can be featured on GitHub Trends if it has received a large number of stars in a short period. After appearing in GitHub Trends, my React Boilerplate has received more than 150 stars in one day. So, this is super effective to get stars on your project.&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fgithub-trends.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fgithub-trends.png" alt="GitHub Trends React"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  11. Github Explore
&lt;/h3&gt;

&lt;p&gt;GitHub Explore is a great way to find open source projects. It automatically suggests open-source projects hosted on GitHub to users based on their interests. So, it's important to fill your project details by adding description and tags.&lt;/p&gt;

&lt;p&gt;Your project will show up on the right side of their dashboard:&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnextjs-github-explore-dashboard.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnextjs-github-explore-dashboard.png" alt="Nextjs-github-explore"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It will also show up in their explore page:&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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnextjs-github-explore-page.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%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnextjs-github-explore-page.png" alt="Next-js-github-explore-page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I myself love this feature and use it to discover projects that I can use.&lt;/p&gt;

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

&lt;p&gt;These are the 11 places I've posted about my Next.js Boilerplate Template. The project on GitHub has now 2000+ stars on GitHub. It was a long journey, it took me almost 2 years to reach this number. Hope this article can help you and shorten your journey to get stars on your project.&lt;/p&gt;

&lt;p&gt;After working on this boilerplate for almost two years, I noticed it's possible to go further by creating a SaaS boilerplate. It's exactly the same idea but applies to a SaaS product. So, I build a &lt;a href="https://nextlessjs.com" rel="noopener noreferrer"&gt;React SaaS Boilerplate&lt;/a&gt;, a boilerplate you can get everything you need to create your SaaS and earn your 1st MRR.&lt;/p&gt;

&lt;p&gt;It'll take care of all the features needed to make SaaS products: authentication, payment, team support, dashboard, landing page, etc. So, you focus on what makes your project unique and quickly launch your SaaS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nextlessjs.com" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnext-js-saas-starter-kit.jpg" alt="React SaaS Template Starter"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>showdev</category>
      <category>react</category>
    </item>
    <item>
      <title>My Next.js Boilerplate now has 2000+ GitHub stars</title>
      <dc:creator>Remi W.</dc:creator>
      <pubDate>Wed, 08 Jun 2022 17:03:25 +0000</pubDate>
      <link>https://dev.to/ixartz/my-nextjs-boilerplate-now-has-2000-github-stars-dne</link>
      <guid>https://dev.to/ixartz/my-nextjs-boilerplate-now-has-2000-github-stars-dne</guid>
      <description>&lt;p&gt;My Next.js boilerplate has just crossed 2000+ stars on GitHub. Thanks to all GitHub stargazers for the support!&lt;/p&gt;

&lt;p&gt;A project I have started 2 years ago for my own personal use and I thought it would be a great idea to share it. Now, I use it for all my project in React and Next.js.&lt;/p&gt;

&lt;p&gt;Now, I also get help from the community. Other developers makes suggestion to the boilerplate code. There are also some external contributors.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ixartz" rel="noopener noreferrer"&gt;
        ixartz
      &lt;/a&gt; / &lt;a href="https://github.com/ixartz/Next-js-Boilerplate" rel="noopener noreferrer"&gt;
        Next-js-Boilerplate
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      🚀🎉📚 Boilerplate and Starter for Next.js 14+ with App Router and Page Router support, Tailwind CSS 3.4 and TypeScript ⚡️ Made with developer experience first: Next.js + TypeScript + ESLint + Prettier + Drizzle ORM + Husky + Lint-Staged + Vitest + Testing Library + Playwright + Storybook + Commitlint + VSCode + Netlify + PostCSS + Tailwind CSS ✨
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Boilerplate and Starter for Next.js 14+, Tailwind CSS 3.4, and TypeScript.&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;
  &lt;a href="https://demo.nextjs-boilerplate.com" rel="nofollow noopener noreferrer"&gt;&lt;img height="300" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fixartz%2FNext-js-Boilerplatepublic%2Fassets%2Fimages%2Fnextjs-starter-banner.png%3Fraw%3Dtrue" alt="Next js starter banner"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;🚀 Boilerplate and Starter for Next.js with App Router, Tailwind CSS, and TypeScript ⚡️ Prioritizing developer experience first: Next.js, TypeScript, ESLint, Prettier, Husky, Lint-Staged, Vitest (replacing Jest), Testing Library, Playwright, Commitlint, VSCode, Tailwind CSS, Authentication with &lt;a href="https://clerk.com?utm_source=github&amp;amp;utm_medium=sponsorship&amp;amp;utm_campaign=nextjs-boilerplate" rel="nofollow noopener noreferrer"&gt;Clerk&lt;/a&gt;, Database with DrizzleORM (PostgreSQL, SQLite, and MySQL), Error Monitoring with &lt;a href="https://sentry.io/for/nextjs/?utm_source=github&amp;amp;utm_medium=paid-community&amp;amp;utm_campaign=general-fy25q1-nextjs&amp;amp;utm_content=github-banner-nextjsboilerplate-logo" rel="nofollow noopener noreferrer"&gt;Sentry&lt;/a&gt;, Logging with Pino.js and Log Management, Monitoring as Code, Storybook, Multi-language (i18n), and more. Ready for Next.js 15.&lt;/p&gt;

&lt;p&gt;Clone this project and use it to create your own Next.js project. You can check out the live demo at &lt;a href="https://demo.nextjs-boilerplate.com" rel="nofollow noopener noreferrer"&gt;Next.js Boilerplate&lt;/a&gt;, which includes a working authentication system.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Sponsors&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;&lt;div class="table-wrapper-paragraph"&gt;&lt;table width="100%"&gt;
&lt;br&gt;
  &lt;tbody&gt;
&lt;br&gt;
&lt;tr height="187px"&gt;
&lt;br&gt;
    &lt;td width="33%"&gt;
&lt;br&gt;
      &lt;a href="https://clerk.com?utm_source=github&amp;amp;utm_medium=sponsorship&amp;amp;utm_campaign=nextjs-boilerplate" rel="nofollow noopener noreferrer"&gt;&lt;br&gt;
        &lt;br&gt;
          &lt;br&gt;
          &lt;br&gt;
          &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fixartz%2FSaaS-Boilerplate%2Fassets%2F1328388%2Ff80a8bb5-66da-4772-ad36-5fabc5b02c60" class="article-body-image-wrapper"&gt;&lt;img alt="Clerk – Authentication &amp;amp; User Management for Next.js" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fixartz%2FSaaS-Boilerplate%2Fassets%2F1328388%2Ff80a8bb5-66da-4772-ad36-5fabc5b02c60"&gt;&lt;/a&gt;&lt;br&gt;
        &lt;br&gt;
      &lt;/a&gt;&lt;br&gt;
    &lt;/td&gt;
&lt;br&gt;
    &lt;td width="33%"&gt;
&lt;br&gt;
      &lt;a href="https://l.crowdin.com/next-js" rel="nofollow noopener noreferrer"&gt;&lt;br&gt;
        &lt;br&gt;
          &lt;br&gt;
          &lt;br&gt;
          &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fixartz%2FNext-js-Boilerplatepublic%2Fassets%2Fimages%2Fcrowdin-dark.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img alt="Crowdin" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fixartz%2FNext-js-Boilerplatepublic%2Fassets%2Fimages%2Fcrowdin-dark.png%3Fraw%3Dtrue"&gt;&lt;/a&gt;&lt;br&gt;
        &lt;br&gt;
      &lt;/a&gt;&lt;br&gt;
    &lt;/td&gt;
&lt;br&gt;
    &lt;td width="33%"&gt;
&lt;br&gt;
      &lt;a href="https://sentry.io/for/nextjs/?utm_source=github&amp;amp;utm_medium=paid-community&amp;amp;utm_campaign=general-fy25q1-nextjs&amp;amp;utm_content=github-banner-nextjsboilerplate-logo" rel="nofollow noopener noreferrer"&gt;&lt;br&gt;
        &lt;br&gt;
          &lt;br&gt;
          &lt;br&gt;
          &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fixartz%2FNext-js-Boilerplatepublic%2Fassets%2Fimages%2Fsentry-dark.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img alt="Sentry" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fixartz%2FNext-js-Boilerplatepublic%2Fassets%2Fimages%2Fsentry-dark.png%3Fraw%3Dtrue"&gt;&lt;/a&gt;&lt;br&gt;
        &lt;br&gt;
      &lt;/a&gt;&lt;br&gt;
      &lt;a href="https://about.codecov.io/codecov-free-trial/?utm_source=github&amp;amp;utm_medium=paid-community&amp;amp;utm_campaign=general-fy25q1-nextjs&amp;amp;utm_content=github-banner-nextjsboilerplate-logo" rel="nofollow noopener noreferrer"&gt;&lt;br&gt;
        &lt;br&gt;
          &lt;br&gt;
          &lt;br&gt;
          &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fixartz%2FNext-js-Boilerplatepublic%2Fassets%2Fimages%2Fcodecov-dark.svg%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img alt="Codecov" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fixartz%2FNext-js-Boilerplatepublic%2Fassets%2Fimages%2Fcodecov-dark.svg%3Fraw%3Dtrue"&gt;&lt;/a&gt;&lt;br&gt;
        &lt;br&gt;
      &lt;/a&gt;&lt;br&gt;
    &lt;/td&gt;
&lt;br&gt;
  &lt;/tr&gt;
&lt;br&gt;
  &lt;tr height="187px"&gt;
&lt;br&gt;
    &lt;td width="33%"&gt;
&lt;br&gt;
      &lt;a href="https://posthog.com/?utm_source=github&amp;amp;utm_medium=sponsorship&amp;amp;utm_campaign=next-js-boilerplate" rel="nofollow noopener noreferrer"&gt;&lt;br&gt;
        &lt;br&gt;
          &lt;br&gt;
          &lt;br&gt;
          &lt;a href="https://camo.githubusercontent.com/81759ea55b20c551aa0488e10efd868efc859238f7ad1c42efc4c8bb04e94e03/68747470733a2f2f706f7374686f672e636f6d2f6272616e642f706f7374686f672d6c6f676f2e737667" class="article-body-image-wrapper"&gt;&lt;img alt="PostHog" src="https://camo.githubusercontent.com/81759ea55b20c551aa0488e10efd868efc859238f7ad1c42efc4c8bb04e94e03/68747470733a2f2f706f7374686f672e636f6d2f6272616e642f706f7374686f672d6c6f676f2e737667"&gt;&lt;/a&gt;&lt;br&gt;
        &lt;br&gt;
      &lt;/a&gt;&lt;br&gt;
    &lt;/td&gt;
&lt;br&gt;
    &lt;td width="33%"&gt;
&lt;br&gt;
      &lt;a href="https://betterstack.com/?utm_source=github&amp;amp;utm_medium=sponsorship&amp;amp;utm_campaign=next-js-boilerplate" rel="nofollow noopener noreferrer"&gt;&lt;br&gt;
        &lt;br&gt;
          &lt;br&gt;
          &lt;br&gt;
          &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fixartz%2FNext-js-Boilerplatepublic%2Fassets%2Fimages%2Fbetter-stack-dark.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img alt="Better Stack" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fixartz%2FNext-js-Boilerplatepublic%2Fassets%2Fimages%2Fbetter-stack-dark.png%3Fraw%3Dtrue"&gt;&lt;/a&gt;&lt;br&gt;
        &lt;br&gt;
      &lt;/a&gt;&lt;br&gt;
    &lt;/td&gt;
&lt;br&gt;
    &lt;td width="33%"&gt;
&lt;br&gt;
      &lt;a href="https://www.checklyhq.com/?utm_source=github&amp;amp;utm_medium=sponsorship&amp;amp;utm_campaign=next-js-boilerplate" rel="nofollow noopener noreferrer"&gt;&lt;br&gt;
        &lt;br&gt;
          &lt;br&gt;
          &lt;br&gt;
          &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fixartz%2FNext-js-Boilerplatepublic%2Fassets%2Fimages%2Fcheckly-logo-light.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img alt="Checkly" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fixartz%2FNext-js-Boilerplatepublic%2Fassets%2Fimages%2Fcheckly-logo-light.png%3Fraw%3Dtrue"&gt;&lt;/a&gt;&lt;br&gt;
        &lt;br&gt;
      &lt;/a&gt;&lt;br&gt;
    &lt;/td&gt;
&lt;br&gt;
  &lt;/tr&gt;
&lt;br&gt;
  &lt;tr height="187px"&gt;
&lt;br&gt;
    &lt;td&gt;
&lt;br&gt;
      &lt;a href="https://nextjs-boilerplate.com/pro-saas-starter-kit" rel="nofollow noopener noreferrer"&gt;&lt;br&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fixartz%2FNext-js-Boilerplatepublic%2Fassets%2Fimages%2Fnextjs-boilerplate-saas.png%3Fraw%3Dtrue" alt="Next.js SaaS Boilerplate with React"&gt;&lt;br&gt;
      &lt;/a&gt;&lt;br&gt;
    &lt;/td&gt;
&lt;br&gt;
  &lt;/tr&gt;
&lt;br&gt;
  &lt;tr height="187px"&gt;
&lt;br&gt;
    &lt;td width="33%"&gt;
&lt;br&gt;
      &lt;a href="https://github.com/ixartz/Next-js-Boilerplatemailto:contact@creativedesignsguru.com" rel="noopener noreferrer"&gt;&lt;br&gt;
        Add your logo here&lt;br&gt;
      &lt;/a&gt;&lt;br&gt;
    &lt;/td&gt;
&lt;br&gt;
  &lt;/tr&gt;
&lt;br&gt;
&lt;/tbody&gt;
&lt;br&gt;
&lt;/table&gt;&lt;/div&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Demo&lt;/h3&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Live demo: &lt;a href="https://demo.nextjs-boilerplate.com" rel="nofollow noopener noreferrer"&gt;Next.js Boilerplate&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;br&gt;
&lt;thead&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;th&gt;Sign Up&lt;/th&gt;
&lt;br&gt;
&lt;th&gt;Sign In&lt;/th&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;/thead&gt;
&lt;br&gt;
&lt;tbody&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a href="https://demo.nextjs-boilerplate.com/sign-up" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fixartz%2FNext-js-Boilerplatepublic%2Fassets%2Fimages%2Fnextjs-boilerplate-sign-in.png" alt="Next.js Boilerplate SaaS Sign Up"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;a href="https://demo.nextjs-boilerplate.com/sign-in" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fixartz%2FNext-js-Boilerplatepublic%2Fassets%2Fimages%2Fnextjs-boilerplate-sign-in.png" alt="Next.js Boilerplate SaaS Sign In"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;/tbody&gt;
&lt;br&gt;
&lt;/table&gt;&lt;/div&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Features&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;Developer experience first, extremely flexible code structure and only keep what you need:&lt;/p&gt;


&lt;ul&gt;

&lt;li&gt;⚡ &lt;a href="https://nextjs.org" rel="nofollow noopener noreferrer"&gt;Next.js&lt;/a&gt; with App Router support&lt;/li&gt;

&lt;li&gt;🔥 Type checking &lt;a href="https://www.typescriptlang.org" rel="nofollow noopener noreferrer"&gt;TypeScript&lt;/a&gt;
&lt;/li&gt;

&lt;li&gt;💎 Integrate with &lt;a href="https://tailwindcss.com" rel="nofollow noopener noreferrer"&gt;Tailwind&lt;/a&gt;…&lt;/li&gt;

&lt;/ul&gt;
&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ixartz/Next-js-Boilerplate" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;I'm currently writing a blog post on how the project reached 2000 stars on GitHub, you can be notified when the article is published by &lt;a href="https://twitter.com/ixartz" rel="noopener noreferrer"&gt;following me&lt;/a&gt; on Twitter.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>javascript</category>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Building a Full Stack Application on AWS: 100% Serverless</title>
      <dc:creator>Remi W.</dc:creator>
      <pubDate>Thu, 02 Jun 2022 16:19:47 +0000</pubDate>
      <link>https://dev.to/ixartz/building-a-full-stack-application-on-aws-100-serverless-3idm</link>
      <guid>https://dev.to/ixartz/building-a-full-stack-application-on-aws-100-serverless-3idm</guid>
      <description>&lt;p&gt;Serverless computing is such a big topic! And it's no news that it's the next step in building applications. It's extremely true for a small team with limited resources.&lt;/p&gt;

&lt;p&gt;It's such a fast-growing market. Amazon Web Services (AWS) is not the only the biggest provider, but also my favorite.&lt;/p&gt;

&lt;p&gt;As a developer myself, I appreciate things that can be automated. If there's a function or method for everything, all I want to do is "automate the boring stuff" and be more productive. Fortunately, AWS can give access to this kind of power.&lt;/p&gt;

&lt;p&gt;I love AWS not because it consists of a famous suit of lovely nicknamed services but its complete package. AWS gives total control of your project all in one place.&lt;/p&gt;

&lt;p&gt;In this article, I'll share what AWS services I use to build full-stack applications with React and Node.js. And, how I use them to make my SaaS application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Be Comfortable With a Programming Language
&lt;/h2&gt;

&lt;p&gt;A good understanding of Python or JavaScript concepts will set you on the right foot to build a full-stack application with AWS.&lt;/p&gt;

&lt;p&gt;I'm a huge fan of JavaScript because it's a versatile programming language. JavaScript works well both on the server side and also on the front.&lt;/p&gt;

&lt;p&gt;The possibilities are unlimited after you've some basic knowledge: you can code on the client-side (frontend) with React and the server-side (backend) with Express.js and Node.js.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Facts About JavaScript
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;JavaScript is native to the web browser&lt;/li&gt;
&lt;li&gt;JavaScript is a widely used programming language&lt;/li&gt;
&lt;li&gt;The threshold to get started with JavaScript is low compared to C/C++ for example&lt;/li&gt;
&lt;li&gt;JavaScript is an interesting language to learn&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I can go on with 101 reasons why you should pick up JavaScript. But, that would make this article longer than it should. So, once I'm comfortable writing a programming language (whether it's JavaScript or not), the next thing is...&lt;/p&gt;

&lt;h2&gt;
  
  
  Jump on a Framework for Infrastructure as Code
&lt;/h2&gt;

&lt;p&gt;As mentioned earlier, JavaScript has endless possibilities. You don't have to be an expert in JavaScript, but it can definitively help to have some knowledge in Express.js. Then, I also need to learn how to deploy your application.&lt;/p&gt;

&lt;p&gt;Learning programming languages is great, but my project isn't available to the world. It only works on my local machine and I couldn't share it with my friends. Today, one of the biggest cloud providers is AWS.&lt;/p&gt;

&lt;p&gt;To make the AWS experience more enjoyable, I also use Serverless Framework and AWS Cloud Development Kit (CDK). I can declare my AWS resources in JavaScript and configuration files instead of using the AWS console. So, you can easily replicate it for several environments like development, staging and production.&lt;/p&gt;

&lt;p&gt;After sharing all the basic requirements to start a full-stack application on AWS, I'll show you the services I use to build my SaaS application.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Amplify Hosting
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QlovMWEh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://creativedesignsguru.com/assets/images/themes/aws-amplify-logo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QlovMWEh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://creativedesignsguru.com/assets/images/themes/aws-amplify-logo.png" alt="AWS Amplify Hosting logo" width="880" height="125"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With Amplify Hosting, it's extremely simple to launch and host your frontend code on AWS. In my case, the frontend is written in React. More precisely, I use Next.js with TypeScript and Tailwind CSS. Amplify Hosting also handles custom domain and SSL certificates for me.&lt;/p&gt;

&lt;p&gt;It's definitively an good alternative to Vercel and Netlify. But, the good thing about Amplify Hosting is that it can host on my own AWS account.&lt;/p&gt;

&lt;p&gt;Like its counterpart, I can connect my GitHub repository to Amplify Hosting. It'll also set up for a simple CI/CD pipeline connected to my GitHub account. This way I can easily deploy your code by simply pushing your changes. No more manual deployment and improve the developer experience by speeding the application deployment.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. AWS Lambda
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iuJqldSv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://creativedesignsguru.com/assets/images/themes/aws-lambda-serverless.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iuJqldSv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://creativedesignsguru.com/assets/images/themes/aws-lambda-serverless.png" alt="AWS Lambda" width="880" height="880"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the backend of my application, I use AWS Lambda. It's a serverless computing platform that runs on AWS. Lambda is one of AWS most fastest-growing products.&lt;/p&gt;

&lt;p&gt;Basically, after implementing the business logic for my SaaS or web application, I need to run my code and AWS Lambda can help me to achieve this.&lt;/p&gt;

&lt;p&gt;With AWS Lambda, I only need to deploy my code on AWS and AWS Lambda will take care of the rest. I don't need to worry about the server, auto-scaling, upgrading, maintenance, etc. I can 100% focus on my code.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. AWS API Gateway
&lt;/h3&gt;

&lt;p&gt;To connect my AWS Lambda to the world, I need to use AWS API Gateway. It's a service that allows me to connect the front of your application to AWS Lambda. With API Gateway, my frontend can send requests to my AWS Lambda and receive the response.&lt;/p&gt;

&lt;p&gt;Like the previous services, AWS API Gateway is also a managed service that I can use for handling, securing, monitoring and versioning my REST API.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. AWS Cognito
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pqf7D1oH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://creativedesignsguru.com/assets/images/themes/aws-cognito-logo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pqf7D1oH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://creativedesignsguru.com/assets/images/themes/aws-cognito-logo.png" alt="AWS Cognito email auth" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When building an application, security should always be a top priority. For this, I use Amazon Cognito. AWS Cognito allows me to add authentication easily without implementing it from scratch.&lt;/p&gt;

&lt;p&gt;You can easily add an email authentication to your application as well as social authentication like Google, Facebook, Apple and Amazon. It'll save you a lot of time and effort.&lt;/p&gt;

&lt;p&gt;In combination with the AWS API gateway, I can secure my backend and restrict my AWS Lambda to only authenticated users.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. DynamoDB
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--o3RDv2HD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://creativedesignsguru.com/assets/images/themes/aws-dynamodb-logo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--o3RDv2HD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://creativedesignsguru.com/assets/images/themes/aws-dynamodb-logo.png" alt="AWS DynamoDB serverless database" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In a full-stack application, I also need to store the data. And, we all know managing a database can sometimes be a daunting task! That's why I choose DynamoDB.&lt;/p&gt;

&lt;p&gt;DynamoDB is a serverless database that runs on AWS. As a serverless database, I don't have to worry about maintaining it and AWS handles that for me. It can automatically scale based on my traffic and scale to zero when needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. CloudWatch
&lt;/h3&gt;

&lt;p&gt;After deploying my application, I need to keep track of how the application will behave in production. And, I use CloudWatch to do that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qmZ5fhtc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://creativedesignsguru.com/assets/images/themes/lambda-metrics.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qmZ5fhtc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://creativedesignsguru.com/assets/images/themes/lambda-metrics.png" alt="Lambda dashboard with metrics" width="880" height="175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once CloudWatch is set up, it gathers logs, metrics, and events for monitoring and operational data. I can also visualize it using Dashboards and have a complete overview of my AWS resources, applications, and services.&lt;/p&gt;

&lt;p&gt;With this information, I can analyze the health and performance of my application. Then, I also set up alarms to automatically monitor the application and take appropriate actions.&lt;/p&gt;

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

&lt;p&gt;Learning to utilize the power of Amazon Web Services (AWS) has helped me build fast, secure, and reliable applications. I'd recommend these services to anyone who wishes to make a full-stack application. You can have everything in the same place with a unified interface.&lt;/p&gt;

&lt;p&gt;By utilizing the power of serverless, you don't have to worry about the underlying infrastructure. AWS is taking care of the servers to execute your applications, databases, and storage systems at any scale. You'd be surprised how much time you'd save building more efficient applications.&lt;/p&gt;

&lt;p&gt;It took me 5 months to understand and build my first full-stack application with AWS. It wasn't an easy journey but I'm extremely happy with the result. So, I've built an &lt;a href="https://nextlessjs.com"&gt;AWS Boilerplate&lt;/a&gt; to make the process easier for all developers. With only a few commands, without any configuration, you can get a full-stack application on AWS and here is the &lt;a href="https://demo.nextlessjs.com"&gt;demo of the full-stack application&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Not only it's hosted on AWS, but it also includes UI components built with React and Next.js styled with Tailwind CSS. So, making a simple full-stack application with Nextless.js is a breeze with 100% Serverless (Frontend, Backend and Database).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nextlessjs.com"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lJu2BxvL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://creativedesignsguru.com/assets/images/themes/aws-saas-boilerplate.jpg" alt="AWS SaaS Boilerplate" width="880" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>react</category>
      <category>aws</category>
    </item>
    <item>
      <title>A Free and Open-Source Responsive Portfolio Template built with Astro.js and React</title>
      <dc:creator>Remi W.</dc:creator>
      <pubDate>Wed, 25 May 2022 14:37:41 +0000</pubDate>
      <link>https://dev.to/ixartz/a-free-and-open-source-responsive-portfolio-template-built-with-astrojs-and-react-5fnc</link>
      <guid>https://dev.to/ixartz/a-free-and-open-source-responsive-portfolio-template-built-with-astrojs-and-react-5fnc</guid>
      <description>&lt;p&gt;A Free and Open Source Responsive Template for Portfolio and Blog built with Astro.js and React styled with Tailwind CSS. Here is a screenshot:&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%2F3o96iadeieqqljwuo81j.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%2F3o96iadeieqqljwuo81j.png" alt="Astro boilerplate template"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the screenvideo:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/XW0s5acCxYw"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Or, you play around a live demo at: &lt;a href="https://creativedesignsguru.com/demo/astro-boilerplate/" rel="noopener noreferrer"&gt;Astro boilerplate Live demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The source code is hosted on GitHub at &lt;a href="https://github.com/ixartz/Astro-boilerplate" rel="noopener noreferrer"&gt;Astro Boilerplate GitHub&lt;/a&gt;. The project is built from scratch and recently released. So, every GitHub ⭐ counts!&lt;/p&gt;

&lt;p&gt;The project includes everything you need for your blog with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sitemap.xml&lt;/li&gt;
&lt;li&gt;Feed RSS&lt;/li&gt;
&lt;li&gt;Robots.txt&lt;/li&gt;
&lt;li&gt;Pagination&lt;/li&gt;
&lt;li&gt;Typography&lt;/li&gt;
&lt;li&gt;Syntax highlighting for code&lt;/li&gt;
&lt;li&gt;Markdown&lt;/li&gt;
&lt;li&gt;Image lazy load&lt;/li&gt;
&lt;li&gt;Newsletter component&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ixartz" rel="noopener noreferrer"&gt;
        ixartz
      &lt;/a&gt; / &lt;a href="https://github.com/ixartz/Astro-boilerplate" rel="noopener noreferrer"&gt;
        Astro-boilerplate
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      🚀 Astro boilerplate with responsive blog and portfolio template using TypeScript and React styled with Tailwind CSS ⚡️ Made with developer experience first: TypeScript + ESLint + Prettier + Husky + Lint-Staged + Commitlint + VSCode
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Astro Boilerplate with TypeScript and Tailwind CSS &lt;a href="https://twitter.com/ixartz" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6fde8675a785bf6f354166820fb0e27be3cc9f4b1160e32bb38e55b9f24ab2f7/68747470733a2f2f696d672e736869656c64732e696f2f747769747465722f75726c2f68747470732f747769747465722e636f6d2f636c6f7564706f7373652e7376673f7374796c653d736f6369616c266c6162656c3d466f6c6c6f7725323025343049786172747a" alt="Twitter"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;🚀 Astro Boilerplate is starter code for your blog or portfolio based on Astro
with Tailwind CSS 3.0. ⚡️ Made with Astro, TypeScript, ESLint, Prettier
Tailwind CSS.&lt;/p&gt;
&lt;p&gt;Clone this project and use it to create your own Astro blog. You can check the
&lt;a href="https://creativedesignsguru.com/demo/astro-boilerplate/" rel="nofollow noopener noreferrer"&gt;Astro templates demo&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Sponsors&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table width="100%"&gt;
  &lt;tbody&gt;
&lt;tr height="187px"&gt;
    &lt;td width="33%"&gt;
      &lt;a href="https://sentry.io/for/nextjs/?utm_source=github&amp;amp;utm_medium=paid-community&amp;amp;utm_campaign=general-fy25q1-nextjs&amp;amp;utm_content=github-banner-nextjsboilerplate-logo" rel="nofollow noopener noreferrer"&gt;
        
          
          
          &lt;img alt="Sentry" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fixartz%2FAstro-boilerplatepublic%2Fassets%2Fimages%2Fsentry-dark.png%3Fraw%3Dtrue"&gt;
        
      &lt;/a&gt;
      &lt;a href="https://about.codecov.io/codecov-free-trial/?utm_source=github&amp;amp;utm_medium=paid-community&amp;amp;utm_campaign=general-fy25q1-nextjs&amp;amp;utm_content=github-banner-nextjsboilerplate-logo" rel="nofollow noopener noreferrer"&gt;
        
          
          
          &lt;img alt="Codecov" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fixartz%2FAstro-boilerplatepublic%2Fassets%2Fimages%2Fcodecov-dark.svg%3Fraw%3Dtrue"&gt;
        
      &lt;/a&gt;
    &lt;/td&gt;
    &lt;td width="33%"&gt;
      &lt;a href="https://betterstack.com/?utm_source=github&amp;amp;utm_medium=sponsorship&amp;amp;utm_campaign=next-js-boilerplate" rel="nofollow noopener noreferrer"&gt;
        
          
          
          &lt;img alt="Better Stack" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fixartz%2FAstro-boilerplatepublic%2Fassets%2Fimages%2Fbetter-stack-dark.png%3Fraw%3Dtrue"&gt;
        
      &lt;/a&gt;
    &lt;/td&gt;
    &lt;td&gt;
      &lt;a href="https://nextlessjs.com" rel="nofollow noopener noreferrer"&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fixartz%2FAstro-boilerplatepublic%2Fassets%2Fimages%2Fnextlessjs.png%3Fraw%3Dtrue" alt="React SaaS Boilerplate Next.js"&gt;
      &lt;/a&gt;
    &lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr height="187px"&gt;
    &lt;td width="33%"&gt;
      &lt;a href="https://clerk.com?utm_source=github&amp;amp;utm_medium=sponsorship&amp;amp;utm_campaign=nextjs-boilerplate" rel="nofollow noopener noreferrer"&gt;
        
          
          
          &lt;img alt="Clerk – Authentication &amp;amp; User Management for Next.js" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fixartz%2FNext-js-Boilerplate%2Fassets%2F1328388%2F3459074d-c3e2-46c5-8be4-b836cb7989ea"&gt;
        
      &lt;/a&gt;
    &lt;/td&gt;
    &lt;td width="33%"&gt;
      &lt;a href="https://turso.tech/?utm_source=nextjsstarterbp" rel="nofollow noopener noreferrer"&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fixartz%2FAstro-boilerplatepublic%2Fassets%2Fimages%2Fturso.png%3Fraw%3Dtrue" alt="SQLite Developer Experience"&gt;
      &lt;/a&gt;
    &lt;/td&gt;
    &lt;td width="33%"&gt;
      &lt;a href="https://l.crowdin.com/next-js" rel="nofollow noopener noreferrer"&gt;
        
          
          
          &lt;img alt="Crowdin" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fixartz%2FAstro-boilerplatepublic%2Fassets%2Fimages%2Fcrowdin-dark.png%3Fraw%3Dtrue"&gt;
        
      &lt;/a&gt;
    &lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr height="187px"&gt;
    &lt;td width="33%"&gt;
      &lt;a href="https://github.com/ixartz/Astro-boilerplatemailto:contact@creativedesignsguru.com" rel="noopener noreferrer"&gt;
        Add your logo here
      &lt;/a&gt;
    &lt;/td&gt;
  &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;A complete Blog feature:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;🎈 Syntax Highlighting&lt;/li&gt;
&lt;li&gt;🤖 SEO friendly with sitemap.xml and robots.txt&lt;/li&gt;
&lt;li&gt;⚙️ RSS feed&lt;/li&gt;
&lt;li&gt;📖 Pagination&lt;/li&gt;
&lt;li&gt;🌈 Include a dark blog theme&lt;/li&gt;
&lt;li&gt;⬇️ Markdown&lt;/li&gt;
&lt;li&gt;📦 Image lazy loading&lt;/li&gt;
&lt;li&gt;💎 Responsive design&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Developer experience first:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;🔥 Astro&lt;/li&gt;
&lt;li&gt;🎨 Tailwind CSS with aspect ratio and typography plugin&lt;/li&gt;
&lt;li&gt;🎉 TypeScript&lt;/li&gt;
&lt;li&gt;✏️ ESLint compatible with .astro files&lt;/li&gt;
&lt;li&gt;🛠 Prettier compatible with .astro files&lt;/li&gt;
&lt;li&gt;🦊 Husky&lt;/li&gt;
&lt;li&gt;🚫 lint-staged&lt;/li&gt;
&lt;li&gt;🚨 Commitlint&lt;/li&gt;
&lt;li&gt;🔧 One-click deploy on Netlify (or, manual if you prefer)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ESLint with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Airbnb styled guide&lt;/li&gt;
&lt;li&gt;TypeScript compatible&lt;/li&gt;
&lt;li&gt;Astro compatible&lt;/li&gt;
&lt;li&gt;Automatically remove unused…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ixartz/Astro-boilerplate" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>react</category>
      <category>webdev</category>
      <category>showdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to configure ESLint, Prettier, Husky, Lint-staged into a React project with TypeScript and Tailwind CSS</title>
      <dc:creator>Remi W.</dc:creator>
      <pubDate>Thu, 28 Apr 2022 12:52:24 +0000</pubDate>
      <link>https://dev.to/ixartz/how-to-configure-eslint-prettier-husky-lint-staged-into-a-react-project-with-typescript-and-tailwind-css-4jp8</link>
      <guid>https://dev.to/ixartz/how-to-configure-eslint-prettier-husky-lint-staged-into-a-react-project-with-typescript-and-tailwind-css-4jp8</guid>
      <description>&lt;p&gt;As a software developer, you have preferences and habits that you want to follow when writing your code. You want to be able to write code that is readable, maintainable, and scalable.&lt;/p&gt;

&lt;p&gt;When you are working in a team with other developers, everybody has their own coding standards and they can be different. It makes the code difficult to read and maintain. How do you settle the differences? You will have to reach a compromise and pick a preferred style for that project.&lt;/p&gt;

&lt;p&gt;Tools such as ESLint, Prettier, Husky, and Lint-staged can help enforce a coding and formatting style. It also spots errors rapidly in your JS application. These tools keep developers focused on solving problems rather than debating which formatting style is best. They also help you to write code unified code across all your projects.&lt;/p&gt;

&lt;p&gt;ESLint is a code analysis tool, or linter, for identifying and reporting on patterns in JS. It's a pluggable and configurable tool that finds and fixes problems in your JavaScript or Node.js code.&lt;/p&gt;

&lt;p&gt;Prettier is an opinionated code formatter that formats your code according to a set of rules. It ensures that your programs follow a consistent coding style.&lt;/p&gt;

&lt;p&gt;Adding ESLint, Prettier, and Husky to your React project will avoid mistakes in your code by making sure that your code follows best practices. It also helps developers write a consistent code style.&lt;/p&gt;

&lt;p&gt;For your information, I'm the author of a boilerplate with ESLint, Prettier, Husky, and Lint-staged already configured and ready to use. If you don't want to lose your time, you can check out my &lt;a href="https://github.com/ixartz/Next-js-Boilerplate" rel="noopener noreferrer"&gt;React Boilerplate&lt;/a&gt; on GitHub.&lt;/p&gt;

&lt;p&gt;In this article, I will guide you through how to configure these tools stated above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Empty Project Setup
&lt;/h2&gt;

&lt;p&gt;You will need to create a TypeScript React project using &lt;code&gt;create-next-app&lt;/code&gt;. Then, you also need to install and configure all the necessary NPM packages.&lt;/p&gt;

&lt;h3&gt;
  
  
  React &amp;amp; TypeScript Configuration
&lt;/h3&gt;

&lt;p&gt;TypeScript is an open-source typed programming language developed by Microsoft. It builds on top of JavaScript with a strict syntax and type checking.&lt;/p&gt;

&lt;p&gt;🚀 Open your favorite terminal&lt;/p&gt;

&lt;p&gt;🚀 Run &lt;code&gt;npx create-next-app@latest --ts&lt;/code&gt; to create a TypeScript Next.js project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-next-app@latest &lt;span class="nt"&gt;--ts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ESLint Configuration
&lt;/h3&gt;

&lt;p&gt;ESLint is highly configurable and can be configured to enforce a specific coding style. You can set up ESLint rules one by one or you can use a preset.&lt;/p&gt;

&lt;p&gt;In this tutorial, we will use the Airbnb style guide for TypeScript: &lt;code&gt;eslint-config-airbnb-typescript&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;🚀 Add ESLint to the project dependency list&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i eslint &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🚀 Install Airbnb ESLint style guide dependencies and its peer dependencies.&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;eslint-config-airbnb-typescript @typescript-eslint/eslint-plugin @typescript-eslint/parser &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🚀 Create and configure the &lt;code&gt;.eslintrc&lt;/code&gt; file by adding Airbnb and ESLint configuration. We also need to indicate to ESLint that we are using TypeScript. We'll also add &lt;code&gt;next/core-web-vitals&lt;/code&gt; to use a stricter ESLint configuration for Next.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extends"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"next/core-web-vitals"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"airbnb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"airbnb-typescript"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"parserOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"project"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./tsconfig.json"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🚀 Add &lt;code&gt;Prettier&lt;/code&gt;, &lt;code&gt;eslint-plugin-prettier&lt;/code&gt;, &lt;code&gt;eslint-plugin-prettier&lt;/code&gt; to the project's dependency.&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;prettier eslint-plugin-prettier eslint-config-prettier &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These three packages load Prettier into ESLint. ESLint will automatically highlight formatting issues in your code based on Prettier rules.&lt;/p&gt;

&lt;p&gt;🚀 Install the &lt;code&gt;eslint-plugin-unused-imports&lt;/code&gt; plugin, it helps you to find unused imports.&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;eslint-plugin-unused-imports &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🚀 Add &lt;code&gt;unused-imports&lt;/code&gt; to the plugins section of your &lt;code&gt;.eslintrc&lt;/code&gt; configuration file. You can omit the &lt;code&gt;eslint-plugin-&lt;/code&gt; prefix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"plugins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"unused-imports"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🚀 Install &lt;code&gt;eslint-plugin-tailwindcss&lt;/code&gt; to lint Tailwind CSS class. It contains rules enforcing best practices and consistency when working with Tailwind CSS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i eslint-plugin-tailwindcss &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🚀 Add &lt;code&gt;tailwindcss&lt;/code&gt; to the plugins section of your &lt;code&gt;.eslintrc&lt;/code&gt; configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"plugins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"unused-imports"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tailwindcss"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🚀 Then, you need to add all the recommended rules from the Tailwind CSS plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extends"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"plugin:tailwindcss/recommended"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🚀 Lint all the .js, .jsx, .ts, and .tsx files within the project folder. After running the command below, it'll display all the errors you need to address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx eslint &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--ext&lt;/span&gt; .js,.jsx,.ts,.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🚀 &lt;code&gt;node_modules&lt;/code&gt; is ignored by ESLint in the default configuration. You can also add more files to ignore by creating a &lt;code&gt;.eslintignore&lt;/code&gt; file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Husky and Lint-staged Setup
&lt;/h3&gt;

&lt;p&gt;Husky is a JavaScript package that allows you to run some code during different stages of the git workflow. On the other hand, Lint-staged is a JavaScript package that helps you to run linter on files that will be committed on Git.&lt;/p&gt;

&lt;p&gt;🚀 Initialize Git in the project directory.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;🚀 Install Husky and Lint Staged.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx mrm@2 lint-staged
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above command will install and configure Husky and Lint-staged. Add &lt;code&gt;lint-staged&lt;/code&gt; and &lt;code&gt;husky&lt;/code&gt; in the &lt;code&gt;package.json&lt;/code&gt; file. It also creates a &lt;code&gt;.husky&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;🚀 Optional: You can create a &lt;code&gt;lint-staged.config.js&lt;/code&gt; file that holds all the Lint-staged configuration. Check out &lt;a href="https://github.com/okonet/lint-staged#configuration" rel="noopener noreferrer"&gt;all the different ways to configure lint-staged&lt;/a&gt; if you don't want Lint-stage configuration in your &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  VSCode ESLint &amp;amp; Prettier Configuration
&lt;/h3&gt;

&lt;p&gt;Visual Studio Code provides ESLint and Prettier extensions that you can install. These extensions give you access to all functionalities discussed in this tutorial.&lt;/p&gt;

&lt;p&gt;To install these extensions:&lt;/p&gt;

&lt;p&gt;🚀 Open your VS Code&lt;/p&gt;

&lt;p&gt;🚀 Click on the Extensions icon on the sidebar or run the command Ctrl + Shift + x.&lt;/p&gt;

&lt;p&gt;🚀 Search for "dbaeumer.vscode-eslint" to install ESLint and "esbenp.prettier-vscode" for Prettier.&lt;/p&gt;

&lt;p&gt;🚀 Close and re-open VSCode to use the newly installed extensions.&lt;/p&gt;

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

&lt;p&gt;Integrating ESLint, Prettier, Husky, and Lint-staged in a TypeScript React project reduce conflicts based on coding and formatting styles. It helps developers to focus on writing high-quality code.&lt;/p&gt;

&lt;p&gt;If you are working on a project, it's highly recommended to have these tools set up first. You can avoid making mistakes in your code: it makes your code more readable with a consistent coding style.&lt;/p&gt;

&lt;p&gt;If you're building your own SaaS application and want to have the same Developer experience, I've made a &lt;a href="https://nextlessjs.com" rel="noopener noreferrer"&gt;React SaaS Starter kit&lt;/a&gt;. It includes by default ESLint, Prettier, Husky, and Lint-staged already configured with TypeScript for you. So, you can start working on your SaaS project right away instead of losing your time with boring configurations.&lt;/p&gt;

&lt;p&gt;In Nextless.js, you'll also find everything you need to build faster your SaaS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Email &amp;amp; Social auth&lt;/li&gt;
&lt;li&gt;Subscription payment&lt;/li&gt;
&lt;li&gt;Team support&lt;/li&gt;
&lt;li&gt;Landing page &amp;amp; Dashboard&lt;/li&gt;
&lt;li&gt;Form &amp;amp; Error management&lt;/li&gt;
&lt;li&gt;Deployed on AWS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://nextlessjs.com" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcreativedesignsguru.com%2Fassets%2Fimages%2Fthemes%2Fnext-js-saas-starter-kit.jpg" alt="React SaaS Template Starter"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>react</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
