<?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: Sabin Adams</title>
    <description>The latest articles on DEV Community by Sabin Adams (@sabinthedev).</description>
    <link>https://dev.to/sabinthedev</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%2F454544%2F0a75c08c-c602-4be7-96b4-0a7e8882d088.jpeg</url>
      <title>DEV Community: Sabin Adams</title>
      <link>https://dev.to/sabinthedev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sabinthedev"/>
    <language>en</language>
    <item>
      <title>What is an API? A Beginner's Guide</title>
      <dc:creator>Sabin Adams</dc:creator>
      <pubDate>Wed, 02 Aug 2023 18:36:43 +0000</pubDate>
      <link>https://dev.to/sabinthedev/what-is-an-api-a-beginners-guide-4b8m</link>
      <guid>https://dev.to/sabinthedev/what-is-an-api-a-beginners-guide-4b8m</guid>
      <description>&lt;p&gt;The world of software relies on the ability of different applications and software to interact with each other by sharing data and communicating. This communication is typically done through APIs &lt;em&gt;(Application Programming Interfaces)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In this article, we will take a close look at what an API is and how they enable developers to effectively and efficiently build software.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding APIs
&lt;/h2&gt;

&lt;p&gt;Most applications in this day and age are data-driven, relying heavily on data from multiple services. These services are typically separate and manage isolated data sets specific to the context of that service. What happens, however, when a service needs to retrieve data or perform an action that is outside its own context?&lt;/p&gt;

&lt;p&gt;As a basic example, consider a multi-tier application with a:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Frontend application&lt;/li&gt;
&lt;li&gt;  Backend application&lt;/li&gt;
&lt;li&gt;  Database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What happens when the frontend application's interface allows you to add data to your database? For security reasons, the frontend application should not have direct access to the database, so how would you go about creating that data?&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%2Ff1sx9z287ptmh7c9rm9v.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%2Ff1sx9z287ptmh7c9rm9v.png" alt="What is an API? A Beginner's Guide" width="800" height="256"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this example, the backend application may provide an API that exposes operations that allow you to perform CRUD &lt;em&gt;(create, read, update, delete)&lt;/em&gt; operations on your database.&lt;/p&gt;

&lt;h3&gt;
  
  
  The API's role
&lt;/h3&gt;

&lt;p&gt;The way these operations are exposed may vary depending on the type of API the backend application provides, however in general an API will expose some set functions or endpoints that allow you to perform pre-defined sets of operations.&lt;/p&gt;

&lt;p&gt;These pre-defined operations act as &lt;em&gt;"contracts"&lt;/em&gt; between the two services. For any given operation, you should be able to request its invocation and expect some sort of response back. Often, you will provide data via a request body or URL variable and expect a &lt;a href="https://www.json.org/json-en.html?ref=devchronicles.io" rel="noopener noreferrer"&gt;JSON&lt;/a&gt; response back, however, this varies based on the flavor of API you are working with.&lt;/p&gt;

&lt;p&gt;We won't cover the various types of APIs in this article, however, to name a few there are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  REST&lt;/li&gt;
&lt;li&gt;  GraphQL&lt;/li&gt;
&lt;li&gt;  gRPC&lt;/li&gt;
&lt;li&gt;  SOAP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The common factor between all of these and the important takeaway of this section is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;APIs are software intermediaries that allow two services to communicate with each other by passing data to and from each other.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Benefits of using APIs
&lt;/h2&gt;

&lt;p&gt;Without APIs, there would be no such thing as third-party services such as &lt;a href="https://stripe.com/?ref=devchronicles.io" rel="noopener noreferrer"&gt;Stripe&lt;/a&gt; and &lt;a href="https://mailchimp.com/?ref=devchronicles.io" rel="noopener noreferrer"&gt;Mailchimp&lt;/a&gt;, and front-end applications would have no way to communicate with a server.&lt;/p&gt;

&lt;p&gt;Every application or website you use is likely communicating with some sort of API. This is why APIs are such a powerful concept. Rather than re-inventing the wheel when adding things like payments, email services, mapping data, etc... APIs allow you to re-use existing functionality simply and consistently.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;APIs allow you to consistently re-use functionality without re-inventing the wheel.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;To recap, APIs allow applications and software to communicate with each other using pre-defined, repeatable actions exposed by the API.&lt;/p&gt;

&lt;p&gt;APIs are commonly provided by service providers to give you access to easily implement payments, email services, and much more. Along with this, essentially any multi-tier application will need to make use of some sort of custom API to allow client-side applications to interact with data from a database.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>api</category>
      <category>programming</category>
    </item>
    <item>
      <title>The Most Valuable Trait of a Developer: Curiosity</title>
      <dc:creator>Sabin Adams</dc:creator>
      <pubDate>Fri, 28 Jul 2023 17:32:34 +0000</pubDate>
      <link>https://dev.to/sabinthedev/the-most-valuable-trait-of-a-developer-curiosity-4842</link>
      <guid>https://dev.to/sabinthedev/the-most-valuable-trait-of-a-developer-curiosity-4842</guid>
      <description>&lt;p&gt;Diving into the world of a software developer can be daunting. There are a million things to learn, and the more you learn the more you find you still need to learn!&lt;/p&gt;

&lt;p&gt;This can be a challenging reality when working in the field alongside other professionals. The goal of this article is to ease your mind about this a help you focus on what matters as a developer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why curiosity is so important
&lt;/h2&gt;

&lt;p&gt;There are many essential qualities that characterize a successful developer. A successful developer should be a good communicator, a team player, organized, etc... but there is something I see as a precursor to all of these.&lt;/p&gt;

&lt;p&gt;These characteristics describe behaviors you exhibit while working in a job you love. They come from a genuine interest in your work and show themselves through effective professionalism.&lt;/p&gt;

&lt;p&gt;This genuine interest, or curiosity, is a necessary prerequisite to the others in my opinion. Without a true curiosity about how things work, how to progress in your career, and how to grow as a developer, the other traits become infinitely more difficult.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to stay curious
&lt;/h2&gt;

&lt;p&gt;All developers go through the ups and downs of curiosity throughout their careers. Varying levels of burnout affect your mindset and interest in growing as a developer, however, there are tricks to keep that fire alive:&lt;/p&gt;

&lt;h3&gt;
  
  
  Pace yourself
&lt;/h3&gt;

&lt;p&gt;This one may seem counterintuitive, however, I believe a major factor in maintaining a healthy curiosity about your work is to set healthy limits to the amount of time you spend honing your skills.&lt;/p&gt;

&lt;p&gt;You may think pouring yourself day and night into learning and building knowledge is the secret to becoming a great developer. This behavior is actually detrimental but points to a positive trait. The mindset behind that &lt;em&gt;(unhealthy)&lt;/em&gt; behavior is &lt;em&gt;curiosity&lt;/em&gt;!&lt;/p&gt;

&lt;p&gt;Rather than focusing on pouring excess amounts of time into learning and practicing, focus on maintaining that curiosity and desire to learn by giving yourself time each day to dedicate to learning.&lt;/p&gt;

&lt;h3&gt;
  
  
  Be open to trying new things
&lt;/h3&gt;

&lt;p&gt;Another way to remember that you are not in school. You aren't being forced to learn any one thing. If one thing starts to feel like work, expand your expertise and try something new!&lt;/p&gt;

&lt;p&gt;Have you been playing with databases for too long and feel like you don't ever want to write a SQL query again? Try learning some new CSS tricks!&lt;/p&gt;

&lt;p&gt;Being open to trying new things not only expands your technical toolbelt but also gives you time away from whatever topic you were becoming burned out on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set goals for yourself
&lt;/h3&gt;

&lt;p&gt;The last trick to help you maintain a healthy curiosity in your development journey is to set goals for yourself.&lt;/p&gt;

&lt;p&gt;Look at what other developers out there are doing. Become active on Twitter, Discord, and other communities where people share their accomplishments. Doing this will help you formulate ideas about accomplishments you would like to achieve.&lt;/p&gt;

&lt;p&gt;As you find things that spark your interests, take note! Set a goal to get your hands on that technology and understand it. You don't need to become an expert in something to justify spending time with it. Set small goals to incrementally build your knowledge across many different tools and paradigms.&lt;/p&gt;

&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;

&lt;p&gt;We've talked about why curiosity is so important and how to maintain your curiosity, but what will this do for you?&lt;/p&gt;

&lt;p&gt;As mentioned before, curiosity is the precursor for other traits of a successful developer. Being curious will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Be apparent to your team and show you care about your job&lt;/li&gt;
&lt;li&gt;  Help you to be constantly building your technical knowledge&lt;/li&gt;
&lt;li&gt;  Give you genuine interest in understanding how to communicate your knowledge effectively&lt;/li&gt;
&lt;li&gt;  Help you be constantly aware of your interests and goals in your career&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these are incredibly important during your career and will be the defining factors of how you grow as a developer.&lt;/p&gt;

&lt;p&gt;I hope this helped ease your mind by giving you one primary goal: build, maintain and enjoy your curiosity in the wide field of software development!&lt;/p&gt;

</description>
      <category>career</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Add Sign In and Sign Up to Your React App With Clerk</title>
      <dc:creator>Sabin Adams</dc:creator>
      <pubDate>Wed, 26 Jul 2023 23:08:32 +0000</pubDate>
      <link>https://dev.to/sabinthedev/add-sign-in-and-sign-up-to-your-react-app-with-clerk-3d26</link>
      <guid>https://dev.to/sabinthedev/add-sign-in-and-sign-up-to-your-react-app-with-clerk-3d26</guid>
      <description>&lt;p&gt;It can look like a daunting task if you haven't had to add authentication to your application before. This is because there are so many things to consider:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Where do I store my user data?&lt;/li&gt;
&lt;li&gt; How do I make sure it is secure?&lt;/li&gt;
&lt;li&gt; What should the sign-up and sign-in flows look like?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Fortunately, many tools out there take away these concerns and give you a clean and simple way to set up secure authentication in your applications.&lt;/p&gt;

&lt;p&gt;My personal favorite of these tools is &lt;a href="https://clerk.com/?ref=devchronicles.io" rel="noopener noreferrer"&gt;Clerk&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://clerk.com/?ref=devchronicles.io" 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%2F58v626upe1nw2wj8o5ky.png" alt="Add Sign In and Sign Up to Your React App With Clerk" width="322" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, you will learn how to use Clerk to add sign-in and sign-up functionality to a React application.&lt;/p&gt;

&lt;h2&gt;
  
  
  The starting point
&lt;/h2&gt;

&lt;p&gt;To start a React application, you will use &lt;a href="https://nextjs.org/?ref=devchronicles.io" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt;. Next.js provides a framework that allows you to easily build React applications of varying complexity and provides built-in niceties such as routing, bundling, and local development tools.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In the past, we may have opted for a simple React application without a framework, however, the React team now suggests using a framework such as Next.js or &lt;a href="http://remix.run/?ref=devchronicles.io" rel="noopener noreferrer"&gt;Remix&lt;/a&gt; to scaffold your React applications.  &lt;/p&gt;

&lt;p&gt;See the &lt;a href="https://react.dev/learn/start-a-new-react-project?ref=devchronicles.io" rel="noopener noreferrer"&gt;React docs&lt;/a&gt; for more information.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To start a Next.js application, navigate via the terminal into a folder where you would like to save your project and run the following command:&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;$ &lt;/span&gt;npx create-next-app@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will be asked for a few bits of information. For this tutorial, you should use all of the default values &lt;strong&gt;except&lt;/strong&gt; opt out of TypeScript by selecting &lt;code&gt;No&lt;/code&gt; when asked if you would like to use TypeScript.&lt;/p&gt;

&lt;h3&gt;
  
  
  Navigating the project
&lt;/h3&gt;

&lt;p&gt;Once your project is set up and you have installed your node modules, you should have a complete project ready to be run locally.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you did not opt to have your &lt;code&gt;node_modules&lt;/code&gt; installed, run &lt;code&gt;npm i&lt;/code&gt; in the terminal.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The bulk of your application is stored in &lt;code&gt;src/app&lt;/code&gt;. Here you will find a file named &lt;code&gt;page.js&lt;/code&gt; which contains the boilerplate page the project comes with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To start your development&lt;/strong&gt; server run the following command in your terminal:&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;$ &lt;/span&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running that command, head to &lt;a href="http://localhost:3000/?ref=devchronicles.io" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt; in your browser to see what the starter project looks like.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To stop the development server&lt;/strong&gt; hit &lt;code&gt;CTRL+C&lt;/code&gt; in the terminal that is running the process.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For more information about Next.js projects, check out their &lt;a href="https://nextjs.org/docs?ref=devchronicles.io" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Add Clerk
&lt;/h2&gt;

&lt;p&gt;With a project up and running, you are now ready to begin setting up authentication for that project using Clerk.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create an account
&lt;/h3&gt;

&lt;p&gt;Head over to Clerk and &lt;a href="https://dashboard.clerk.com/sign-up?ref=devchronicles.io" rel="noopener noreferrer"&gt;sign up&lt;/a&gt;. After signing up you should land in a personal workspace with the option to create an application.&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Add application&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvlp8siblqoky7xgvyhsx.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%2Fvlp8siblqoky7xgvyhsx.png" alt="Add Sign In and Sign Up to Your React App With Clerk" width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will open a view that allows you to customize the sign up and sign in elements and choose your authentication methods. Customize this however you like.&lt;/p&gt;

&lt;h3&gt;
  
  
  Store the application secrets
&lt;/h3&gt;

&lt;p&gt;The important piece comes after this. The page you are redirected to contains your project's secrets: &lt;code&gt;NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY&lt;/code&gt; and &lt;code&gt;CLERK_SECRET_KEY&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F37aktshipepwr3taed4r.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%2F37aktshipepwr3taed4r.png" alt="Add Sign In and Sign Up to Your React App With Clerk" width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy those values by clicking the clipboard icon.&lt;/p&gt;

&lt;p&gt;Those values will need to be stored securely for your application to access. At the root of your application create a new file named &lt;code&gt;.env&lt;/code&gt;:&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;$ &lt;/span&gt;&lt;span class="nb"&gt;touch&lt;/span&gt; .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste the contents you copied into this 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="c"&gt;# .env&lt;/span&gt;
&lt;span class="nv"&gt;NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pk_fake_cHJvYmFmbGUtY2hhbW9pcy0zNi5jbGVyay5hY2NvdW50cy5kZXYk
&lt;span class="nv"&gt;CLERK_SECRET_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sk_fake_gdcBCVQM0TEQaA5krQI154JbRWJDgWIKP5LHSwuYw3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Never store or post your keys anywhere they can be publicly accessed! These values are fake.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up the Clerk provider
&lt;/h2&gt;

&lt;p&gt;To begin using Clerk in your application, you first need to install it.&lt;/p&gt;

&lt;p&gt;Install Clerk's Next.js SDK with the following command:&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;$ &lt;/span&gt;npm i @clerk/nextjs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This package gives you access to various tools Clerk provides, including a React context provider which provides session and user data to Clerk's components.&lt;/p&gt;

&lt;p&gt;Within &lt;code&gt;src/app/layout.js&lt;/code&gt;, import &lt;code&gt;ClerkProvider&lt;/code&gt; and use it to wrap the application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/app/layout.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./globals.css&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;Inter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/font/google&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;ClerkProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@clerk/nextjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 👈🏻&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Inter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;subsets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;latin&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Create Next App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Generated by create next app&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RootLayout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ClerkProvider&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;html&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"en"&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;body&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;inter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&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;children&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;body&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;html&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;ClerkProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&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;blockquote&gt;
&lt;p&gt;The layout.js file is a special file in Next.js. Read more about it &lt;a href="https://nextjs.org/docs/app/api-reference/file-conventions/layout?ref=devchronicles.io" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Add the authentication middleware
&lt;/h2&gt;

&lt;p&gt;The next step is to add middleware to the application. This middleware will intercept every navigation and verify the current user and session have access to the destination page.&lt;/p&gt;

&lt;p&gt;Create a new file in &lt;code&gt;src/&lt;/code&gt; named &lt;code&gt;middleware.js&lt;/code&gt;:&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;$ &lt;/span&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;src/middleware.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside that file, add the following code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/middleware.js&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;authMiddleware&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@clerk/nextjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// This example protects all routes including api/trpc routes&lt;/span&gt;
&lt;span class="c1"&gt;// Please edit this to allow other routes to be public as needed.&lt;/span&gt;
&lt;span class="c1"&gt;// See https://clerk.com/docs/nextjs/middleware for more information about configuring your middleware&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;authMiddleware&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;matcher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/((?!.*&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;..*|_next).*)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/(api|trpc)(.*)&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;blockquote&gt;
&lt;p&gt;This &lt;code&gt;middleware.js&lt;/code&gt; file is another special file that Next.js handles and applies automatically. See more information &lt;a href="https://nextjs.org/docs/app/building-your-application/routing/middleware?ref=devchronicles.io" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Within this middleware, you can configure which pages in your application are protected and should only be viewed by signed-in users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add The Sign-In Page
&lt;/h2&gt;

&lt;p&gt;With the middleware and Clerk context in place, we are now ready to build a sign-in page.&lt;/p&gt;

&lt;p&gt;Create a new directory in &lt;code&gt;src/app&lt;/code&gt; named &lt;code&gt;sign-in/[[...sign-in]]&lt;/code&gt; and a new file inside of that new directory named &lt;code&gt;page.js&lt;/code&gt;&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;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"src/app/sign-in/[[...sign-in]]"&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;src/app/sign-in/&lt;span class="s1"&gt;'[[...sign-in]]'&lt;/span&gt;/page.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The file path for this looks strange because it uses Next.js's new App directory with file-based routing. This means Next.js looks at the files and folders in the &lt;code&gt;src/app&lt;/code&gt; directory and builds your application's routing automatically based on how they are named.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For information on this, refer to the docs &lt;a href="https://nextjs.org/docs/app/building-your-application/routing?ref=devchronicles.io" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This new file is where you will build your sign-in page. Add the following to &lt;code&gt;src/app/sign-in/[[...sign-in]]/page.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/app/sign-in/[[...sign-in]]/page.js&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;SignIn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@clerk/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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"h-screen w-full flex items-center justify-center"&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;SignIn&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This adds a sign-in page, but we also need to configure where to navigate the user after the sign-in action is completed.&lt;/p&gt;

&lt;p&gt;Add the following to &lt;code&gt;.env&lt;/code&gt;:&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="c"&gt;# .env&lt;/span&gt;
&lt;span class="c"&gt;# ... other variables&lt;/span&gt;
&lt;span class="nv"&gt;NEXT_PUBLIC_CLERK_SIGN_IN_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/sign-in
&lt;span class="nv"&gt;NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The variables shown here are used by Clerk to determine where the sign-in page is and where to navigate the user after a sign-in is complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add user details to the screen
&lt;/h2&gt;

&lt;p&gt;You now have a complete and functional sign-in page and measures in place to keep your application secure. In &lt;code&gt;src/app/page.js&lt;/code&gt;, replace all of the existing code with the following to show the logged in user after logging in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/app/layout.js&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;UserButton&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@clerk/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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;currentUser&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@clerk/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;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;Home&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"h-screen w-full flex flex-col"&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;header&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"bg-slate-800 w-full p-3 h-16 flex items-center"&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;UserButton&lt;/span&gt; &lt;span class="na"&gt;afterSignOutUrl&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&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;header&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;main&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex-1 flex items-center justify-center"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;firstName&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="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The snippet above displays the signed-in user's name as well as a component provided by Clerk, &lt;code&gt;UserButton&lt;/code&gt;, which allows a user to sign out and manage their account.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test it out
&lt;/h2&gt;

&lt;p&gt;At this point, your authenticated application is complete! Start up the application by running:&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;$ &lt;/span&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then head over to &lt;a href="http://localhost:3000/?ref=devchronicles.io" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt; in your browser. You should find yourself on the sign-in page:&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%2Fbv13jouhs6r5e1n796cd.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%2Fbv13jouhs6r5e1n796cd.png" alt="Add Sign In and Sign Up to Your React App With Clerk" width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Signing in will redirect you to the root page and show your user details:&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%2F6u1aal00l2e9ls34mwa6.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%2F6u1aal00l2e9ls34mwa6.png" alt="Add Sign In and Sign Up to Your React App With Clerk" width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All that is needed now is to add more pages and finish your secure application!&lt;/p&gt;

&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;p&gt;Over the course of this tutorial, you learned how to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Set up a Next.js application&lt;/li&gt;
&lt;li&gt; Install and configure Clerk&lt;/li&gt;
&lt;li&gt; Use Clerk to authenticate your application&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The resulting application is equipt with a secure sign-in that allows you to create an account or sign in with Google. With different configurations and customizations, you can allow users to sign in with other social accounts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Next steps
&lt;/h3&gt;

&lt;p&gt;With this foundation in place, you can now begin to extend the application by adding new pages, updating the middleware to allow public access to specific pages, and much more!&lt;/p&gt;




&lt;p&gt;Thanks for following along!&lt;/p&gt;

</description>
      <category>react</category>
      <category>nextjs</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Common React Interview Question: Tic Tac Toe</title>
      <dc:creator>Sabin Adams</dc:creator>
      <pubDate>Mon, 24 Jul 2023 17:31:41 +0000</pubDate>
      <link>https://dev.to/sabinthedev/common-react-interview-question-tic-tac-toe-jeg</link>
      <guid>https://dev.to/sabinthedev/common-react-interview-question-tic-tac-toe-jeg</guid>
      <description>&lt;p&gt;Are you preparing for a technical interview for a position where you'll be working with React? One of the more common tasks I've seen given to interviewees is: &lt;em&gt;"build a simple tic tac toe game"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Oftentimes, the individual you are coordinating interviews with will give you a vague overview of what to expect during your technical interview. If they mentioned implementing a simple game, you're in the right place!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you just want to check out the final result, head over to this &lt;a href="https://github.com/sabinadams/tic-tac-toe?ref=devchronicles.io" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Why is Tic-Tac-Toe used for technical interviews?
&lt;/h1&gt;

&lt;p&gt;As is the case with most technical interviews, the tic tac toe challenge gives the interviewer a chance to see a few things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; How you think about building a feature&lt;/li&gt;
&lt;li&gt; Your depth of knowledge in React&lt;/li&gt;
&lt;li&gt; Your communication&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;During an interview where you are asked to build anything, not just tic-tac-toe, it is essential to understand that the interviewers are on your side and expect a collaborative session.&lt;/p&gt;

&lt;p&gt;If you get stuck, &lt;em&gt;ask questions!&lt;/em&gt; Not sure about the prompt? &lt;em&gt;Ask about it!&lt;/em&gt; The more you show that you are a team player who isn't afraid to ask for help, the more of a full picture you give the interviewer about what it will be like to work with you.&lt;/p&gt;

&lt;p&gt;Aside from personality and collaboration skills though, this test is a great way to see if an individual understands things like:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; State management&lt;/li&gt;
&lt;li&gt; Controlled components&lt;/li&gt;
&lt;li&gt; Context API&lt;/li&gt;
&lt;li&gt; CSS and JSX skills&lt;/li&gt;
&lt;li&gt; Basic JavaScript skills&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  What a solution might look like
&lt;/h1&gt;

&lt;p&gt;There are many different ways you could build this game. Here I will walk you through a solution I believe is pretty straightforward and uses patterns that demonstrate a good understanding of React.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This tutorial will assume your technical assessment requires you to use TypeScript, however the concepts translate to JavaScript.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The starting point
&lt;/h2&gt;

&lt;p&gt;Typically during a technical interview with a React-based challenge, you will start with a basic React app. Likely in a platform such as &lt;a href="https://coderpad.io/?ref=devchronicles.io" rel="noopener noreferrer"&gt;CoderPad&lt;/a&gt; or &lt;a href="https://codesandbox.io/?ref=devchronicles.io" rel="noopener noreferrer"&gt;CodeSandbox&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The starting point will typically include things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The basic setup for running a React project&lt;/li&gt;
&lt;li&gt;  A &lt;code&gt;src/&lt;/code&gt; folder containing an &lt;code&gt;App.tsx&lt;/code&gt; and &lt;code&gt;main.tsx&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Likely some other files that can be deleted or ignored&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the most part, you will not have to worry much about the starting files as your focus will be in &lt;code&gt;App.tsx&lt;/code&gt; and new files you add yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build the game board
&lt;/h2&gt;

&lt;p&gt;To begin building the game, we will build a component that acts as the game board. This is where all of the squares from the tic tac toe grid will eventually be rendered.&lt;/p&gt;

&lt;p&gt;To do this, create a new folder within the &lt;code&gt;src/&lt;/code&gt; directory named &lt;code&gt;components&lt;/code&gt; and a new file in that folder named &lt;code&gt;GameBoard.tsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;src/components
&lt;span class="nb"&gt;touch &lt;/span&gt;src/components/GameBoard.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll likely be in an online editor where you will have to create these manually via the UI&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;GameBoard.tsx&lt;/code&gt; file will export a &lt;a href="https://legacy.reactjs.org/docs/components-and-props.html?ref=devchronicles.io#function-and-class-components" rel="noopener noreferrer"&gt;&lt;em&gt;function component&lt;/em&gt;&lt;/a&gt; as its default export:&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="c1"&gt;// src/components/GameBoard.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GameBoard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;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;GameBoard&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This component needs to render a 3 x 3 grid of squares. We will assume there is a root-level &lt;code&gt;App.css&lt;/code&gt; file where we can provide global styles for the purposes of this tutorial.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;App.css&lt;/code&gt;, add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* src/App.css */&lt;/span&gt;
&lt;span class="nc"&gt;.gameboard&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should give us a class that will style a &lt;code&gt;div&lt;/code&gt;'s contents as a 3 x 3 grid.&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="c1"&gt;// src/components/GameBoard.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GameBoard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gameboard&lt;/span&gt;&lt;span class="dl"&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="cm"&gt;/* Render grid here! */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;GameBoard&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, we have a &lt;code&gt;GameBoard&lt;/code&gt; component that is ready to render some grid items on the game board. Next, we will tackle that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build the square component
&lt;/h2&gt;

&lt;p&gt;To start the component that will be rendered for each grid item, create a new file in &lt;code&gt;src/components&lt;/code&gt; named &lt;code&gt;Square.tsx&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="c1"&gt;// src/components/Square.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Square&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;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;Square&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This component will render the square that will contain either an X or an O. Create another class to style these squares:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* src/App.css */&lt;/span&gt;
&lt;span class="nc"&gt;.square&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="no"&gt;gray&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#f1f1f1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&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;And then put that to use in the new component:&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="c1"&gt;// src/components/Square.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Square&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;square&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;Square&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Within that &lt;code&gt;div&lt;/code&gt; tag is where you will render an X or an O depending on which player clicked the square.&lt;/p&gt;

&lt;p&gt;To prepare this component for its future usage, define a few properties that you can pass it to specify the user who selected it and a click handler function:&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="c1"&gt;// src/components/Square.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
  &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&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;Square&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onClick&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;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;square&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onClick&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;user&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;Square&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have a game board and a way to render squares on that board now. What we need next is some structure to store the game's data and render the board based on that data.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;At this point we are not actually rendering either of the components we have built. That will come soon, hang tight!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Build the game state using the Context API
&lt;/h2&gt;

&lt;p&gt;To handle the state data in this application, you will use React's &lt;a href="https://legacy.reactjs.org/docs/context.html?ref=devchronicles.io" rel="noopener noreferrer"&gt;Context API&lt;/a&gt;. This API gives you a way to provide global state management to your application, allowing you to easily share data across components.&lt;/p&gt;

&lt;p&gt;To stay organized, contexts are typically stored in their own folder. Create a new folder in &lt;code&gt;src/&lt;/code&gt; named &lt;code&gt;contexts&lt;/code&gt; and a file in that new directory named &lt;code&gt;GameState.tsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;src/contexts
&lt;span class="nb"&gt;touch &lt;/span&gt;src/contexts/GameState.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This file is where we will create our context. Open it up and start by creating a new context and exporting it:&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="c1"&gt;// src/contexts/GameState.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GameState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;users&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="na"&gt;activeUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="na"&gt;selections&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GameStateContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GameState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;y&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;activeUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;selections&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;In the snippet above, we are importing the &lt;code&gt;createContext&lt;/code&gt; function which allows us to create a React context. We are also creating a type &lt;code&gt;GameState&lt;/code&gt; to define the properties this context exposes. For now, it contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;users&lt;/code&gt;: An array containing the two players' data&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;activeUser&lt;/code&gt;: The user whose turn it is&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;selections&lt;/code&gt;: The data for each individual grid item&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this point, we have a context, but we also need to export a component that provides that context using a &lt;a href="https://legacy.reactjs.org/docs/context.html?ref=devchronicles.io#contextprovider" rel="noopener noreferrer"&gt;&lt;em&gt;provider&lt;/em&gt;&lt;/a&gt;&lt;em&gt;:&lt;/em&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="c1"&gt;// src/contexts/GameState.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="c1"&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;GameStateProvider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&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;activeUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setActiveUser&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSelections&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GameStateContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
    &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;y&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="nx"&gt;activeUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;selections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/GameStateContext.Provider&lt;/span&gt;&lt;span class="err"&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;Notice &lt;code&gt;useState&lt;/code&gt; as added to the imports from the &lt;code&gt;react&lt;/code&gt; library&lt;/p&gt;

&lt;p&gt;This provider component will wrap the entire application, giving it global access to the data it provides. Important to note here are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The &lt;code&gt;children&lt;/code&gt; argument, which contains the child components the provider will eventually wrap.&lt;/li&gt;
&lt;li&gt;  The &lt;code&gt;useState&lt;/code&gt; invocations. We are initializing the provider's state with two pieces of data. the &lt;code&gt;activeUser&lt;/code&gt; which is &lt;code&gt;"x"&lt;/code&gt; by default and &lt;code&gt;selections&lt;/code&gt; which contains an empty array with a length of &lt;code&gt;9&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There will be a bit more to add to this file, however for now let's move on to putting the context to use so we can begin rendering the game board.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use the GameState context
&lt;/h2&gt;

&lt;p&gt;To use the context, we will first import the &lt;em&gt;provider&lt;/em&gt; component and wrap the entire application in it.&lt;/p&gt;

&lt;p&gt;Head into &lt;code&gt;src/App.tsx&lt;/code&gt; and put the provider to use by importing it and wrapping the JSX contents in the component:&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="c1"&gt;// src/App.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GameStateProvider&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;./contexts/GameState&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GameStateProvider&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* original contents */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/GameStateProvider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anything contained inside of that &lt;code&gt;GameStateProvider&lt;/code&gt; component will have access to the &lt;code&gt;GameState&lt;/code&gt; context.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;GameBoard&lt;/code&gt; component will be the entry point for this game. Next import that and replace the contents inside of the &lt;code&gt;GameStateProvider&lt;/code&gt; with that component:&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="c1"&gt;// src/App.tsx&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;GameStateProvider&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;./contexts/GameState&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;GameBoard&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;./components/GameBoard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GameStateProvider&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GameBoard&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/GameStateProvider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will cause the &lt;code&gt;GameBoard&lt;/code&gt; to be rendered on the screen, although that component does not currently render any of the squares.&lt;/p&gt;

&lt;h2&gt;
  
  
  Render the game grid
&lt;/h2&gt;

&lt;p&gt;If you think back to the &lt;code&gt;GameState&lt;/code&gt; context initialization, you will remember we initialized the state with an array of nine items, which represents the grid items on the board. To render the game's UI we will render a square for each of the grid items.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;src/components/GameBoard.tsx&lt;/code&gt;, use &lt;code&gt;useContext&lt;/code&gt; to gain access to the context's data and render a &lt;code&gt;Square&lt;/code&gt; component for each item in the &lt;code&gt;selections&lt;/code&gt; array:&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="c1"&gt;// src/components/GameBoard.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Square&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;./Square&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GameStateContext&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;../contexts/GameState&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GameBoard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;selections&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GameStateContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gameboard&lt;/span&gt;&lt;span class="dl"&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;selections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selection&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="o"&gt;=&amp;gt;&lt;/span&gt; 
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Square&lt;/span&gt; 
            &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&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="nx"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;selection&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
            &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Container&lt;/span&gt;&lt;span class="err"&gt;&amp;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;GameBoard&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For each item in the array, you are now rendering a &lt;code&gt;Square&lt;/code&gt; and passing along the selection data to that square. Eventually, this will hold the name of the user that clicked that square.&lt;/p&gt;

&lt;p&gt;If we take a look at the screen, however, we will see a very unorganized grid:&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%2F0ftznbvwuopgmeyzwa5j.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%2F0ftznbvwuopgmeyzwa5j.png" alt="Common React Interview Question: Tic Tac Toe" width="800" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's fix this by wrapping the game board in a new &lt;code&gt;div&lt;/code&gt; in &lt;code&gt;App.tsx&lt;/code&gt; and adding some styles in &lt;code&gt;App.css&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="c1"&gt;// src/App.tsx&lt;/span&gt;
&lt;span class="c1"&gt;// ... &lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GameStateProvider&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;container&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GameBoard&lt;/span&gt;&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/GameStateProvider&lt;/span&gt;&lt;span class="err"&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;App&lt;/span&gt;

&lt;span class="cm"&gt;/* src/App.css */&lt;/span&gt;
&lt;span class="cm"&gt;/* ... */&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="nx"&gt;vw&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="nx"&gt;vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;align&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;justify&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;font&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;roboto&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;And with those adjustments, you should now see a formatted tic tac toe grid!&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%2Fyfqb3dl9tf4euefsb6bb.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%2Fyfqb3dl9tf4euefsb6bb.png" alt="Common React Interview Question: Tic Tac Toe" width="800" height="591"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are now rendering a tic tac toe grid and have access to a global state. You have all the pieces you need to begin making this grid functional!&lt;/p&gt;

&lt;h2&gt;
  
  
  Give players the ability to select a square
&lt;/h2&gt;

&lt;p&gt;To begin, we need to add a method and make it accessible via the global state that mutates the &lt;code&gt;selections&lt;/code&gt; array when a user clicks a square. Clicking a square should also switch the turn to the next player.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;src/contexts/GameContext.tsx&lt;/code&gt; make the following changes to add a function that selects a square based on the current player and then passes the turn to the next player:&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="c1"&gt;// src/contexts/GameContext.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GameState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;users&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="na"&gt;activeUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="na"&gt;selections&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;makeSelection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;squareId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="c1"&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;GameStateContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GameState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;o&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;activeUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;selections&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="na"&gt;makeSelection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&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;GameStateProvider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&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;activeUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setActiveUser&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSelections&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Allows a user to make a selection 👇🏻&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;makeSelection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;squareId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Update selections&lt;/span&gt;
    &lt;span class="nf"&gt;setSelections&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selections&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;selections&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;squareId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;activeUser&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;selections&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;// Switch active user to the next user's turn&lt;/span&gt;
    &lt;span class="nf"&gt;setActiveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;activeUser&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x&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;o&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;x&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;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GameStateContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
    &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;o&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="nx"&gt;activeUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;selections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;makeSelection&lt;/span&gt; &lt;span class="c1"&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="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/GameStateContext.Provider&lt;/span&gt;&lt;span class="err"&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;Take note of where the hands are pointing! Those are the changes that were made.&lt;/p&gt;

&lt;p&gt;That's a big code snipped, so let's see what changed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; The &lt;code&gt;GameState&lt;/code&gt; type needed a new property called &lt;code&gt;makeSelection&lt;/code&gt; to define the function we are adding&lt;/li&gt;
&lt;li&gt; The &lt;code&gt;GameStateContext&lt;/code&gt; needed an initial value for &lt;code&gt;makeSelection&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; The provider defines the functionality for &lt;code&gt;makeSelection&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; The &lt;code&gt;makeSelection&lt;/code&gt; function is provided to the &lt;code&gt;value&lt;/code&gt; attribute of the provider, exposing it to any component that uses that context&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;makeSelection&lt;/code&gt; function itself does two things. It takes in the &lt;code&gt;squareId&lt;/code&gt;, which is its index in the &lt;code&gt;selections&lt;/code&gt; array and uses that to update the value of that index with the name of the current player. It then sets the &lt;code&gt;activeUser&lt;/code&gt; to whichever player did not just make a selection, passing the turn.&lt;/p&gt;

&lt;p&gt;As a result, this function allows a user to select a square and pass the turn. What's left is to put it to use. Head into &lt;code&gt;GameBoard&lt;/code&gt; component and pass this to the &lt;code&gt;onClick&lt;/code&gt; handler of the &lt;code&gt;Square&lt;/code&gt; components being rendered:&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="c1"&gt;// src/components/GameBoard.tsx&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GameBoard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="nx"&gt;selections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="nx"&gt;makeSelection&lt;/span&gt; &lt;span class="c1"&gt;// 👈🏻&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GameStateContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gameboard&lt;/span&gt;&lt;span class="dl"&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;selections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selection&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="o"&gt;=&amp;gt;&lt;/span&gt; 
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Square&lt;/span&gt; 
            &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&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="nx"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;selection&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
            &lt;span class="nx"&gt;onClick&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="nf"&gt;makeSelection&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="c1"&gt;// 👈🏻&lt;/span&gt;
          &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;GameBoard&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when a square on the grid is clicked, the current player's symbol will be displayed:&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%2Fnqxqtwbx1h2gafrzmahm.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%2Fnqxqtwbx1h2gafrzmahm.png" alt="Common React Interview Question: Tic Tac Toe" width="800" height="590"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What's left is to add the functionality to check for a winner and reset the game once a winner is found.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check for a winner
&lt;/h2&gt;

&lt;p&gt;When a player selects a square, a function should fire off that checks whether there is a winning combination.&lt;/p&gt;

&lt;p&gt;To accomplish this, we will use &lt;code&gt;useEffect&lt;/code&gt; within the &lt;code&gt;GameContextProvider&lt;/code&gt; component. Every time &lt;code&gt;selections&lt;/code&gt; changes, the effect will fire triggering the check for a winner.&lt;/p&gt;

&lt;p&gt;Make the changes below to accomplish this:&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="c1"&gt;// src/contexts/GameState.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="c1"&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;GameStateProvider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&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;selections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSelections&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="c1"&gt;// 👇🏻&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// checkForWinner()&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selections&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GameStateContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
    &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;o&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="nx"&gt;activeUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;selections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;makeSelection&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;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/GameStateContext.Provider&lt;/span&gt;&lt;span class="err"&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;Remember to import &lt;code&gt;useEffect&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;Every time a grid item is selected (or more specifically, whenever the &lt;code&gt;selections&lt;/code&gt; variable changes) the code inside of the &lt;code&gt;useEffect&lt;/code&gt; callback will be run.&lt;/p&gt;

&lt;p&gt;What we need to add to handle selecting a winner is add a new state variable and provide it via the provider named &lt;code&gt;winner&lt;/code&gt;. When we check for a winner and find one, the player will be stored in that state variable.&lt;/p&gt;

&lt;p&gt;Add the following to do this:&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="c1"&gt;// src/contexts/GameState.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GameState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;users&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="na"&gt;activeUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="na"&gt;selections&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;makeSelection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;squareId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;
  &lt;span class="na"&gt;winner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="c1"&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;GameStateProvider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&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;winner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setWinner&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// 👈🏻&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GameStateContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
    &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;o&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="nx"&gt;activeUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;selections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;makeSelection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;winner&lt;/span&gt; &lt;span class="c1"&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="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/GameStateContext.Provider&lt;/span&gt;&lt;span class="err"&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;Now there is a piece of state that can keep track of whether or not a winner has been selected and who it is. The last piece for handling a winner is the actual function that reads the game board and finds a line of three matching selections.&lt;/p&gt;

&lt;p&gt;Add the following function and uncomment the contents of the &lt;code&gt;useEffect&lt;/code&gt; callback:&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="c1"&gt;// src/contexts/GameState.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&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;GameStateProvider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checkForWinner&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="nx"&gt;winningCombos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&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="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&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="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="nx"&gt;winningCombos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;combo&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;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;combo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;curr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;selections&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;curr&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="dl"&gt;''&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;xxx&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;yyy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; 
        &lt;span class="nf"&gt;setWinner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&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="nf"&gt;checkForWinner&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;selections&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GameStateContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
    &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;o&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="nx"&gt;activeUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;selections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;makeSelection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;winner&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;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/GameStateContext.Provider&lt;/span&gt;&lt;span class="err"&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;When a player wins the game, the &lt;code&gt;winner&lt;/code&gt; state variable will be updated to contain the winning player's symbol. At the moment, there is no indication there was a winner though. Let's fix that and wrap up the game.&lt;/p&gt;

&lt;h2&gt;
  
  
  Display a winner and reset the board
&lt;/h2&gt;

&lt;p&gt;To display a winner, we can make use of the new &lt;code&gt;winner&lt;/code&gt; variable that is made accessible to the application via the context provider.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;GameBoard&lt;/code&gt; component, add a &lt;code&gt;useEffect&lt;/code&gt; that watches for changes to the &lt;code&gt;winner&lt;/code&gt; variable. When that variable is updated and a winner is contained in that variable, display an alert signifying which player won:&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="c1"&gt;// src/components/GameBoard.tsx&lt;/span&gt;
&lt;span class="c1"&gt;// 👇🏻&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GameBoard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&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;selections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;makeSelection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;winner&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GameStateContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// 👇🏻&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;winner&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Player &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;winner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt; won!`&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;winner&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gameboard&lt;/span&gt;&lt;span class="dl"&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="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;GameBoard&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't forget to import &lt;code&gt;useEffect&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;If a player selects three in a row, you should now see an alert signifying which user won!&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%2F1nedzz5hc1thcls0e39w.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%2F1nedzz5hc1thcls0e39w.png" alt="Common React Interview Question: Tic Tac Toe" width="800" height="738"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once that alert is dismissed, the game board does not change. There is currently no way to start over (other than refreshing the browser).&lt;/p&gt;

&lt;p&gt;Add and expose a new function in the &lt;code&gt;GameState&lt;/code&gt; context that resets the state variables to their original values:&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="c1"&gt;// src/contexts/GameState.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GameState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="na"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&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;GameStateContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GameState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="na"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GameStateProvider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reset&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="nf"&gt;setSelections&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;setWinner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;setActiveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x&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;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GameStateContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
    &lt;span class="c1"&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;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/GameStateContext.Provider&lt;/span&gt;&lt;span class="err"&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;This function will reset the game completely and should be run directly after the &lt;code&gt;alert&lt;/code&gt; in the &lt;code&gt;GameBoard&lt;/code&gt; component:&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="c1"&gt;// src/components/GameBoard.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GameBoard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&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;selections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;makeSelection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;winner&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;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GameStateContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;winner&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Player &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;winner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt; won!`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="c1"&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="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;winner&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gameboard&lt;/span&gt;&lt;span class="dl"&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="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;GameBoard&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when you dismiss the &lt;code&gt;alert&lt;/code&gt; you should see the game board is reset and ready for a new game!&lt;/p&gt;

&lt;h1&gt;
  
  
  Closing words
&lt;/h1&gt;

&lt;p&gt;I really enjoy this task because, while it seems simple at first glance, it allows interviewers to see you understand concepts such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Reusable components&lt;/li&gt;
&lt;li&gt;  Global state management&lt;/li&gt;
&lt;li&gt;  JSX&lt;/li&gt;
&lt;li&gt;  Basic logic&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;... and more!&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you had trouble following through the tutorial above at all, you can also refer to this &lt;a href="https://github.com/sabinadams/tic-tac-toe?ref=devchronicles.io" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; with the completed project.&lt;/p&gt;

&lt;p&gt;Thanks so much for reading, and good luck interviewing!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>typescript</category>
      <category>interview</category>
    </item>
    <item>
      <title>To NoSQL or Not to NoSQL</title>
      <dc:creator>Sabin Adams</dc:creator>
      <pubDate>Fri, 21 Jul 2023 19:56:58 +0000</pubDate>
      <link>https://dev.to/sabinthedev/to-nosql-or-not-to-nosql-2ncm</link>
      <guid>https://dev.to/sabinthedev/to-nosql-or-not-to-nosql-2ncm</guid>
      <description>&lt;p&gt;NoSQL was a revolutionary advance in technology when it first began to gain popularity. As time has passed and more teams have gained hands-on experience with it in long-living projects, the hype has died down and opinions have changed.&lt;/p&gt;

&lt;p&gt;In this article we will take a look at how NoSQL compares to SQL and the considerations to keep in mind when deciding whether or not to use a NoSQL database.&lt;/p&gt;

&lt;h1&gt;
  
  
  What is NoSQL?
&lt;/h1&gt;

&lt;p&gt;The first step to understanding when you should and shouldn't use NoSQL is having a firm grasp of NoSQL as a concept.&lt;/p&gt;

&lt;p&gt;"NoSQL" itself is not a great name as it doesn't really encompass all that a NoSQL database has to offer. There are many different &lt;em&gt;flavors&lt;/em&gt; of NoSQL. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Document databases: &lt;em&gt;e.g. MongoDB, DynamoDB&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;  Key-Value databases: &lt;em&gt;e.g. Redis, Memcached, Couchbase&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;  Wide-column stores: &lt;em&gt;e.g. Cassandra, BigTable, CosmosDB&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;  Graph databases: &lt;em&gt;e.g. Neo4j, ArangoDB, TigerGraph&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What all of these have in common is that they are &lt;em&gt;non-relational&lt;/em&gt; database, meaning they do not adhere to a defined schema of relational tables. Often when someone refers to a NoSQL database, they are referring to a document store such as &lt;a href="https://www.mongodb.com/?ref=devchronicles.io" rel="noopener noreferrer"&gt;MongoDB&lt;/a&gt;, however as you can see above there are many variations to keep in mind.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NoSQL refers to any databases that store data in non-relational constructs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Primary features
&lt;/h3&gt;

&lt;p&gt;Below are just a few of the notable features of NoSQL databases that make them such a useful technology:&lt;/p&gt;

&lt;h3&gt;
  
  
  Flexible data structures
&lt;/h3&gt;

&lt;p&gt;The most obvious feature of NoSQL is the fact that it does not have to follow a schema pre-defined at the database-level. This allows you as a developer to have the flexibility of storing data in a chosen shape per-record. One record in a collection may look completely different than the next!&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="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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sdf8s7d76sfds9d0fs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"firstName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sabin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"lastName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Adams"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"favoriteColor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#000000"&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;You may have another record in that same collection that looks more like this:&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sdf8s7d76sfds9d0fs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"firstName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Thomas"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"lastName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Newman"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"favoriteColor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#1f1f1f"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"hobby"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"music composition"&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;Notice the new &lt;code&gt;hobby&lt;/code&gt; property&lt;/p&gt;

&lt;p&gt;This is perfectly acceptable in a NoSQL database and allows you as a developer to not have to worry about having your long-term data structure defined right from the start.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick iterations
&lt;/h3&gt;

&lt;p&gt;A side-effect of having flexible schemas is that NoSQL allows developers and teams to iterate very quickly as their applications progress and evolve.&lt;/p&gt;

&lt;p&gt;When an application requires data structure changes within the database, making those changes is as simple as adding or removing columns from the data model. The database doesn't care what data you give it, so long as it is of a valid format.&lt;/p&gt;

&lt;h3&gt;
  
  
  Potentially faster queries
&lt;/h3&gt;

&lt;p&gt;NoSQL has the potential for faster queries compared to similar queries against a traditional relational database.&lt;/p&gt;

&lt;p&gt;In NoSQL, relations are not handled via an underlying schema. Instead they are manually maintained using nested data structures. For example, consider a model where a &lt;code&gt;user&lt;/code&gt; can have many &lt;code&gt;posts&lt;/code&gt;:&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"9879sdfs98df"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"fullName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sabin Adams"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"posts"&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="err"&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="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;As is shown above, the &lt;code&gt;posts&lt;/code&gt; data is nested within the &lt;code&gt;user&lt;/code&gt; record itself. This makes it very easy and efficient to search for a user's related posts. Rather than having to make use of a foreign key to point to a separate table and scan that table for linked data, it's all packaged nicely in one spot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Horizontally scalable
&lt;/h2&gt;

&lt;p&gt;The last point I will touch on is that NoSQL databases excel at being horizontally scalable.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Horizontal scaling&lt;/em&gt; refers to increasing the capacity of a system by adding additional machines (nodes), as opposed to increasing the capability of the existing machines. This is also called &lt;em&gt;scaling out&lt;/em&gt;. - &lt;a href="https://www.cockroachlabs.com/blog/vertical-scaling-vs-horizontal-scaling/?ref=devchronicles.io#:~:text=handle%20heavier%20workloads.-,What%20is%20horizontal%20scaling%3F,is%20also%20called%20scaling%20out." rel="noopener noreferrer"&gt;Cockroach Labs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The way data is structured in a NoSQL database makes it easier to shard and duplicate across multiple machines (or nodes). When using a NoSQL database, you give up a lot of the built-in features a traditional relational database gives you, such as &lt;em&gt;referential integrity&lt;/em&gt; and &lt;em&gt;transactions&lt;/em&gt; in return for an easily partition-able pool of data.&lt;/p&gt;

&lt;p&gt;When a NoSQL database runs up against performance walls, you can simply add more nodes to your pool of databases that split the processing power between each other.&lt;/p&gt;

&lt;h1&gt;
  
  
  How Is It Different From SQL?
&lt;/h1&gt;

&lt;p&gt;The sections above focused specifically on the features of NoSQL, but now let's take a look at how those features set NoSQL apart from traditional relational databases:&lt;/p&gt;

&lt;h2&gt;
  
  
  Rigid data structure
&lt;/h2&gt;

&lt;p&gt;A SQL database has a very rigid data structure. In fact, you cannot begin using and storing data in your database without first defining a data structure and the relationships within that data structure.&lt;/p&gt;

&lt;p&gt;This has positive and negative implications. In regards to how this causes SQL to differ from NoSQL, rigid data structures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Make iteration much slower.&lt;/strong&gt; Changing your SQL data model requires you to update your schema via a migration before you can store new data or remove data.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Cause a higher barrier of entry.&lt;/strong&gt; Migrations are difficult to manage and easy to get wrong. Because of this, it is best practice to think all the way through your data needs before applying your initial schema to minimize the number of major structure changes. This takes time and resources.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The above are presented as negatives, however the time spent defining and updating a rigid data model allow you to construct well-defined relations in your data which allow you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Enforce relation rules&lt;/li&gt;
&lt;li&gt;  Establish &lt;a href="https://en.wikipedia.org/wiki/ACID?ref=devchronicles.io" rel="noopener noreferrer"&gt;ACID&lt;/a&gt; properties, allowing safe transactional operations across many tables of data&lt;/li&gt;
&lt;li&gt;  Improve data compatibility&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Vertically scalable
&lt;/h2&gt;

&lt;p&gt;Unlike NoSQL, which is horizontally scalable, traditional SQL databases are scaled vertically.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Vertical scaling&lt;/em&gt; refers to increasing the capacity of a system by adding capability to the machines it is using (as opposed to increasing the overall number of machines). This is also called &lt;em&gt;scaling up&lt;/em&gt;. - &lt;a href="https://www.cockroachlabs.com/blog/vertical-scaling-vs-horizontal-scaling/?ref=devchronicles.io#:~:text=handle%20heavier%20workloads.-,What%20is%20horizontal%20scaling%3F,is%20also%20called%20scaling%20out." rel="noopener noreferrer"&gt;Cockroach Labs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Relational data, due to the nature of the underlying data structure that make up relations, does not support the concept of horizontal scaling. Writing a SQL query with joins across different tables assumes it has immediate access to the related data. If the database were stored horizontally, the related data from such a query might only exist in a particular node, requiring a network request to fetch that segment of the data.&lt;/p&gt;

&lt;p&gt;This poses problems as the database will have no way to determine whether it has access to all of the data when generating a query plan.&lt;/p&gt;

&lt;p&gt;Because of this, SQL database are typically scaled vertically. When a SQL database runs up against performance issues, the database server itself is upgraded to a more powerful machine that can handle the desired workload.&lt;/p&gt;

&lt;h1&gt;
  
  
  Considerations
&lt;/h1&gt;

&lt;p&gt;At this point, you should have a general overview of some of the primary differences between NoSQL and SQL databases. But, as we saw above, both have their own pros and cons.&lt;/p&gt;

&lt;p&gt;So we now come to the question this article is aiming to answer: &lt;em&gt;To NoSQL or Not to NoSQL.&lt;/em&gt; The answer to this question is the typical: &lt;em&gt;It depends.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Every application is different and has different functional and organizational needs. SQL and NoSQL each solve specific problems the other can't account for. The answer to the question will depend on what your specific applications' needs are.&lt;/p&gt;

&lt;p&gt;Below are a few considerations to keep in mind when deciding if NoSQL is a fit for your needs:&lt;/p&gt;

&lt;h2&gt;
  
  
  Structure of data
&lt;/h2&gt;

&lt;p&gt;One major consideration is the structure and nature of the data your application needs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If are expecting your data to primarily consist of non-relational data or large sets of unstructured data, NoSQL is a fantastic choice.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A few examples of when you might opt for a NoSQL database:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Social media-like applications where data and relationships are user-defined&lt;/li&gt;
&lt;li&gt;  Storage for unstructured variable data such as logs or IoT data&lt;/li&gt;
&lt;li&gt;  Applications such as content management systems where the data is primarily non-relational&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Evolution of data
&lt;/h2&gt;

&lt;p&gt;As discussed briefly above, the lack of a structured schema allows you to modify your data structure with little to no effort. This can be important for a team working to get an application out as soon as possible.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If your application is in its early phases and you are hoping to iterate and evolve it quickly, a NoSQL is definitely the best option.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Often teams will use a NoSQL database during experimentation phases. Once the product is complete, you can always take a look at the data needs of that application and determine whether a switch to a tradition SQL database would be beneficial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your team's capabilities
&lt;/h2&gt;

&lt;p&gt;Another thing to consider when choosing a database type is the knowledge your team members possess. Working with a traditional SQL database requires the developer to understand how to write efficient SQL queries, often complex ones.&lt;/p&gt;

&lt;p&gt;One of the reasons NoSQL was invented was due to the frustrating of the SQL language. With most NoSQL providers, your queries are run via an API built in your language of choice.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If your team consists primarily of developers who are not SQL-savvy, you may be best suited running a NoSQL database.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Cost
&lt;/h2&gt;

&lt;p&gt;Due to the flexible nature of hosting and deploying NoSQL databases, you also gain access to more granular control of the costs that go into your database.&lt;/p&gt;

&lt;p&gt;As your database scales up and down, the cost of hosting your data scales with it. This can often lead to much lower costs compared to a traditional SQL database which is run 24/7 on a machine with static allocations of resources.&lt;/p&gt;

&lt;h1&gt;
  
  
  Key Takeways
&lt;/h1&gt;

&lt;p&gt;The key takeway here is that the NoSQL vs. SQL debate does not have any one definitive answer. Each type of database has its own special attributes that make it more suitable for specific situations.&lt;/p&gt;

&lt;p&gt;When choosing your database, be sure to consider the strengths and weaknesses of each kind of database, the human resources available on your team and the future data needs of your application.&lt;/p&gt;

</description>
      <category>database</category>
      <category>datascience</category>
      <category>mongodb</category>
    </item>
    <item>
      <title>Stop Hating On Array.reduce()</title>
      <dc:creator>Sabin Adams</dc:creator>
      <pubDate>Thu, 20 Jul 2023 05:01:32 +0000</pubDate>
      <link>https://dev.to/sabinthedev/stop-hating-on-arrayreduce-36gj</link>
      <guid>https://dev.to/sabinthedev/stop-hating-on-arrayreduce-36gj</guid>
      <description>&lt;p&gt;There has been some controversy recently about whether or not JavaScript developers should use the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce?ref=devchronicles.io" rel="noopener noreferrer"&gt;&lt;code&gt;Array.reduce()&lt;/code&gt;&lt;/a&gt; method.&lt;/p&gt;

&lt;p&gt;Here's just a few posts that were part of the recent Tweet storm:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1681027968985104386-239" src="https://platform.twitter.com/embed/Tweet.html?id=1681027968985104386"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1681027968985104386-239');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1681027968985104386&amp;amp;theme=dark"
  }



 &lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1681285782475259905-188" src="https://platform.twitter.com/embed/Tweet.html?id=1681285782475259905"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1681285782475259905-188');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1681285782475259905&amp;amp;theme=dark"
  }



 &lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1681148216585392128-168" src="https://platform.twitter.com/embed/Tweet.html?id=1681148216585392128"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1681148216585392128-168');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1681148216585392128&amp;amp;theme=dark"
  }



 &lt;/p&gt;

&lt;p&gt;Of course, everyone is entitled to their own opinion! But this article is dedicated to why everyone with the opinion that &lt;code&gt;Array.reduce()&lt;/code&gt; is bad is wrong 😈&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Disclaimer: They aren't wrong 😅 I'm as opinionated as the rest of 'em!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;
  
  
  What does it do?
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce?ref=devchronicles.io" rel="noopener noreferrer"&gt;&lt;code&gt;Array.reduce()&lt;/code&gt;&lt;/a&gt; is an array function in JavaScript that is used to reduce the contents of an array down to a single value using a function called a &lt;em&gt;reducer.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A popular example usage of the function is a reducer that returns the sum of all numbers in an array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cur&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;return&lt;/span&gt; &lt;span class="nx"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;curr&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="c1"&gt;// value: 10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function takes in two arguments:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;callback&lt;/code&gt;: A callback function, the &lt;em&gt;reducer&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;initialValue&lt;/code&gt;: The initial value the accumulated value builds upon&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The callback function takes in 4 optional parameters:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;accumulator&lt;/code&gt;: The accumulated value&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;currentValue&lt;/code&gt;: The current item in the array you are iterating through&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;currentIndex&lt;/code&gt;: The current index of the array you are iterating through&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;array&lt;/code&gt;: The entire array you are iterating through&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A full signature looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reducer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;accumulator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currentValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currentIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&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;return&lt;/span&gt; &lt;span class="nx"&gt;accumulator&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;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...].&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reducer&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  What's the problem?
&lt;/h1&gt;

&lt;p&gt;After digging through the complaints, the recurring theme is that &lt;code&gt;Array.reduce()&lt;/code&gt; is too difficult to read and understand.&lt;/p&gt;

&lt;p&gt;While reviewing code, scanning through a new codebase or reading documentation, coming across an &lt;code&gt;Array.reduce()&lt;/code&gt; requires you to stop and think for a moment about what is actually happening with an array.&lt;/p&gt;

&lt;p&gt;These opinions are based around the fact that you can achieve the same result with another &lt;code&gt;Array&lt;/code&gt; method such as &lt;code&gt;Array.forEach()&lt;/code&gt; or even a simple &lt;code&gt;for&lt;/code&gt; loop in a way that is more readable.&lt;/p&gt;

&lt;p&gt;While the opinions hit on a good point... they're wrong!&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%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1689828197213%2F96fe8b4c-f75d-41f7-b363-58f665b0482c.gif%2520align%3D" 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%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1689828197213%2F96fe8b4c-f75d-41f7-b363-58f665b0482c.gif%2520align%3D" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  My reasoning
&lt;/h1&gt;

&lt;p&gt;There are a few things that come to mind when I read these comments. I think a lot of the reasoning behind these opinions are perfectly valid! But the frustration is directed at the wrong thing.&lt;/p&gt;

&lt;p&gt;My first thought about this matter is that the real frustration isn't about the method signature and complexity at all, but rather about a developer's worst enemy: &lt;em&gt;naming things.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In fact, this in my opinion is so deeply rooted in the controversy that it shows itself in two different ways!&lt;/p&gt;

&lt;h3&gt;
  
  
  Exhibit A: It shouldn't be named reduce
&lt;/h3&gt;

&lt;p&gt;First, the method itself is named &lt;code&gt;reduce&lt;/code&gt;. While this method name makes sense in many situations... the &lt;code&gt;Array.reduce()&lt;/code&gt; method is so powerful that it can do far more than reduce an array to a single value.&lt;/p&gt;

&lt;p&gt;Consider the following usage of the function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;smallNumbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&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;largeNumbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;smallNumbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;newArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;current&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;newArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;newArray&lt;/span&gt; 
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;

&lt;span class="c1"&gt;// largeNumbers: [1,4,9,16,25]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, we aren't reducing the initial array at all... we are &lt;em&gt;transforming&lt;/em&gt; it! So... is this reason enough to hate &lt;code&gt;Array.reduce()&lt;/code&gt;? I think not!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Boom, fixed.&lt;/p&gt;

&lt;p&gt;Obviously, that's a joke. A joke that would fix the problem completely, but still a joke.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exhibit B: People are lazy when naming parameters
&lt;/h3&gt;

&lt;p&gt;How many times have you seen a loop like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&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;crazyValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="k"&gt;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;array&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="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;j&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;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="nx"&gt;crazyValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;j&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;Really?? &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;j&lt;/code&gt;? Why are these single-character variable names so common that it almost seems normal to look at?&lt;/p&gt;

&lt;p&gt;The same &lt;em&gt;(disgusting)&lt;/em&gt; problem exists with &lt;code&gt;Array.reduce()&lt;/code&gt; usage. You will often see this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt; &lt;span class="o"&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;crazyvalue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;curr&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="nx"&gt;arr&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;return&lt;/span&gt; &lt;span class="nx"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;curr&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;acc&lt;/code&gt;, &lt;code&gt;curr&lt;/code&gt;, &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;arr&lt;/code&gt;....really guys?? We can do better. Let's fix this confusing problem by being a lot more descriptive with our variable names:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt; &lt;span class="o"&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;crazyvalue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currentValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;originalArray&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;return&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;currentValue&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or better yet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt; &lt;span class="o"&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;initalValue&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addValues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currentValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;originalArray&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;return&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;currentValue&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;crazyvalue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;addValues&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initialValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, this may not be the perfect solution but it certainly makes the code a lot easier to read and digest.&lt;/p&gt;

&lt;h1&gt;
  
  
  What do you think?
&lt;/h1&gt;

&lt;p&gt;So, is &lt;code&gt;Array.reduce()&lt;/code&gt; all that bad? Personally, I would say no. If you understand that &lt;code&gt;Array.reduce()&lt;/code&gt; is a powerful function that can do more than simply reduce an array to a single value, it is actually pretty easy to follow.&lt;/p&gt;

&lt;p&gt;A lot of the issues I see with it are user-errors related to naming conventions.&lt;/p&gt;

&lt;p&gt;What do you think? Am I completely off-base here? &lt;a href="https://twitter.com/sabinthedev" rel="noopener noreferrer"&gt;@ me on Twitter&lt;/a&gt; and we can fight about it 🤺&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Bonus question:&lt;/em&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reduce&lt;/span&gt; 
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt; 
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;intialValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; 
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sumOfNumbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initialValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Yay or nay?&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>datastructures</category>
    </item>
    <item>
      <title>Managing a Remix Site's Content With Sanity.io</title>
      <dc:creator>Sabin Adams</dc:creator>
      <pubDate>Tue, 23 Aug 2022 20:56:15 +0000</pubDate>
      <link>https://dev.to/sabinthedev/managing-a-remix-sites-content-with-sanityio-3602</link>
      <guid>https://dev.to/sabinthedev/managing-a-remix-sites-content-with-sanityio-3602</guid>
      <description>&lt;p&gt;In this day and age, the world runs on data. Your phone, your favorite game, the internet itself! Everything comes down to data. This has lead to a realization by developers over the years: &lt;em&gt;data is hard to manage&lt;/em&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;In this article, you will learn how to use &lt;a href="https://www.sanity.io/" rel="noopener noreferrer"&gt;Sanity.io&lt;/a&gt;, a content platform that includes the &lt;a href="https://www.sanity.io/docs/datastore" rel="noopener noreferrer"&gt;Content Lake&lt;/a&gt; where your content is stored, a content management studio and various APIs to access your content from. Sanity will be used to manage the content &lt;em&gt;(data)&lt;/em&gt; of a book catalog's website built with &lt;a href="//remix.run/"&gt;Remix&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;By the end, you will have Sanity set up to manage your content and a fully functional Remix application. This application will use Sanity's GraphQL API to retrieve your content.&lt;/p&gt;

&lt;p&gt;Finally, you will deploy your finished website using Vercel.&lt;/p&gt;

&lt;h1&gt;
  
  
  Prerequisites
&lt;/h1&gt;

&lt;p&gt;While not completely necessary, I believe you will get the most out of this article if you come with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A basic understanding of JavaScript and its tooling&lt;/li&gt;
&lt;li&gt;Experience working with React&lt;/li&gt;
&lt;li&gt;A basic understanding of GraphQL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Make sure you have &lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;node.js&lt;/a&gt; installed on your machine.&lt;/p&gt;

&lt;h1&gt;
  
  
  Tools you will use
&lt;/h1&gt;

&lt;p&gt;Below are the various tools and technologies you will get to touch in this tutorial:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://remix.run/" rel="noopener noreferrer"&gt;Remix&lt;/a&gt;, your application framework&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sanity.io/" rel="noopener noreferrer"&gt;Sanity&lt;/a&gt;, a headless CMS to manage your data&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/prisma-labs/graphql-request" rel="noopener noreferrer"&gt;graphql-request&lt;/a&gt;, a minimal GraphQL client&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.graphql-code-generator.com/" rel="noopener noreferrer"&gt;GraphQL Codegen&lt;/a&gt;, generates TypeScript types from a GraphQL schema&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;TailwindCSS&lt;/a&gt;, as your CSS framework&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vercel.com/" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt;, as your website hosting provider&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Set up a Sanity.io project
&lt;/h1&gt;

&lt;p&gt;Sanity gives you the ability to set up Sanity Studio, an application that allows you to configure different content types and inputs. The studio interacts with Sanity's APIs, allowing you to manage your data from a self-hosted application.&lt;/p&gt;

&lt;p&gt;In order to set up a Sanity project, you first need to install the Sanity CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i -g @sanity/cli

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

&lt;/div&gt;



&lt;p&gt;Next, initialize a Sanity project in a directory where you would like the project to live. For the purposes of this tutorial I will work in &lt;code&gt;/Documents/projects&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /Documents/projects
sanity init

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : If you did not already have a Sanity account set up, &lt;code&gt;sanity init&lt;/code&gt; will walk you through setting up a new account.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This will walk you through setting up your project and will download a starter template of Sanity Studio. You will be prompted for a few bits of data and asked a few questions about your project. I chose the name &lt;code&gt;catalog-sanity&lt;/code&gt; for my project and will use that for the remainder of this tutorial.&lt;/p&gt;

&lt;p&gt;At some point in the process, you will be asked to &lt;strong&gt;Select project template&lt;/strong&gt;. Select the &lt;strong&gt;Clean project with no predefined schemas&lt;/strong&gt; option, as you will configure this project yourself.&lt;/p&gt;

&lt;p&gt;Once your project has been set up, follow the instructions outputted to start up Sanity Studio:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /Documents/projects
cd catalog-sanity
sanity start

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

&lt;/div&gt;



&lt;p&gt;Sanity Studio should start up at &lt;a href="http://localhost:3333" rel="noopener noreferrer"&gt;localhost:3333&lt;/a&gt;. Pop that open to see what the starter template looks like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : You will be asked to sign in to the studio. Use the credentials you used when creating an account on Sanity.io.&lt;/p&gt;
&lt;/blockquote&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%2Fwvv5uc178oemvj4w6b42.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%2Fwvv5uc178oemvj4w6b42.png" alt="Sanity Studio Starter" width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should see a page similar to the one above. As the message on the page indicates, you have not yet configured a schema.&lt;/p&gt;

&lt;p&gt;In the next section, you will set up a schema to define a &lt;code&gt;Book&lt;/code&gt; document and its &lt;code&gt;field&lt;/code&gt;s.&lt;/p&gt;

&lt;h2&gt;
  
  
  Define a &lt;code&gt;Book&lt;/code&gt; document type
&lt;/h2&gt;

&lt;p&gt;In Sanity, JavaScript objects are used to build schemas that define your content model. This model consists of "documents", or the types of content you are creating. In this catalog scenario, the only type of content you will create is &lt;code&gt;Book&lt;/code&gt;s.&lt;/p&gt;

&lt;p&gt;Open up your Sanity project in a code editor. You will find a folder within named &lt;code&gt;schemas&lt;/code&gt;. This is the folder that will contain all of your project's schemas.&lt;/p&gt;

&lt;p&gt;Create a new file within the &lt;code&gt;schemas&lt;/code&gt; folder named &lt;code&gt;book.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /Documents/projects/catalog-sanity
touch schemas/book.js

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

&lt;/div&gt;



&lt;p&gt;Add the following code to the new &lt;code&gt;book.js&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// /Documents/projects/catalog-sanity/schemas/book.js

export const book = {
  name: 'book',
  type: 'document',
  title: 'Book',
  fields: []
}

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

&lt;/div&gt;



&lt;p&gt;This object defines a &lt;code&gt;document&lt;/code&gt; named &lt;code&gt;book&lt;/code&gt;. Within Sanity Studio, this document will be referred to as &lt;code&gt;Book&lt;/code&gt; because of the &lt;code&gt;title&lt;/code&gt; field. The &lt;code&gt;fields&lt;/code&gt; array is empty at the moment.&lt;/p&gt;

&lt;p&gt;In your application, a book will have three pieces of data associated with it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Title&lt;/code&gt;: The title of the book&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Author&lt;/code&gt;: The author of the book&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Description&lt;/code&gt;: A quick description of the book&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Update the &lt;code&gt;fields&lt;/code&gt; array to define these data points:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// /Documents/projects/catalog-sanity/schemas/book.js

// ...
fields: [
    {
        name: "title",
        type: "string",
        title: "Title",
    }, {
        name: "author",
        type: "string",
        title: "Author",
    }, {
        name: "description",
        type: "text",
        title: "Description",
    },
],
// ...

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Apply &lt;code&gt;Book&lt;/code&gt; to your schema
&lt;/h2&gt;

&lt;p&gt;At this point, you have completely defined the &lt;code&gt;Book&lt;/code&gt; document type, however that type has not yet been applied to the project's schema.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;schemas/schema.js&lt;/code&gt;, import the new &lt;code&gt;Book&lt;/code&gt; type and add it to the &lt;code&gt;types&lt;/code&gt; array within the &lt;code&gt;createSchema&lt;/code&gt; configuration object argument:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// /Documents/projects/catalog-sanity/schemas/schema.js

import createSchema from "part:@sanity/base/schema-creator";

import schemaTypes from "all:part:@sanity/base/schema-type";
import { book } from "./book"; // &amp;lt;- Import the type

export default createSchema({
  name: "default",
  types: schemaTypes.concat([
    book // &amp;lt;- Add it to the array
  ]),
});

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

&lt;/div&gt;



&lt;p&gt;Once you save all of your changes and head back to the browser, you should now see the UI updated with your new content type.&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%2Fb8ldadka51r3wmg9aqlj.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%2Fb8ldadka51r3wmg9aqlj.png" alt="Sanity Studio With Book" width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking the &lt;strong&gt;Book&lt;/strong&gt; option under the &lt;strong&gt;Content&lt;/strong&gt; header will reveal a list of your existing books &lt;em&gt;(it will be empty for now)&lt;/em&gt;. Here, you are provided all of the tools you need to create, update, and delete books.&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%2Fqkoyen61v1vpsgu3crsz.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%2Fqkoyen61v1vpsgu3crsz.png" alt="Sanity Studio Book View" width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a couple of books by clicking the pencil icon on the top right of that section:&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%2Ftse7fecx2oto2693wufd.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%2Ftse7fecx2oto2693wufd.png" alt="Sanity New Book Icon" width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you've added a few books, you are almost ready to move on to the last section!&lt;/p&gt;

&lt;p&gt;The last thing you need to do, however, is install the &lt;code&gt;@sanity/cli&lt;/code&gt; as a development dependency in the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i -D @sanity/cli

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

&lt;/div&gt;



&lt;p&gt;This will allow you to deploy to Vercel later on in this tutorial.&lt;/p&gt;

&lt;h1&gt;
  
  
  Build the Remix application
&lt;/h1&gt;

&lt;p&gt;Now that Sanity is set up to manage your content, you need a way to display that content. You will use &lt;a href="https://remix.run/" rel="noopener noreferrer"&gt;Remix&lt;/a&gt;, a full stack JavaScript framework, to create a book catalog website where your data will be displayed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initialize a Remix application
&lt;/h2&gt;

&lt;p&gt;This application will be separate from the Sanity project. Navigate out of the Sanity project's directory and into a directory where you would like your Remix project to live. Then run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /Documents/projects
npx create-remix@latest

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

&lt;/div&gt;



&lt;p&gt;This command will ask you a series of questions and scaffold the beginnings of a Remix application for you. Answer the questions with the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Where would you like to create your app?&lt;/strong&gt; : &lt;code&gt;catalog-remix&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What type of app do you want to create?&lt;/strong&gt; : &lt;code&gt;Just the basics&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Where do you want to deploy?&lt;/strong&gt; : &lt;code&gt;Vercel&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TypeScript or JavaScript?&lt;/strong&gt; : &lt;code&gt;TypeScript&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do you want me to run &lt;code&gt;npm install&lt;/code&gt;?&lt;/strong&gt; : &lt;code&gt;Yes&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The options above will set up a Remix starter template in a folder named &lt;code&gt;catalog-remix&lt;/code&gt;. This application will be a bare bones template configured to use TypeScript and deploy to Vercel.&lt;/p&gt;

&lt;p&gt;Enter the new directory and run the &lt;code&gt;dev&lt;/code&gt; script to start up the development server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /Documents/projects
cd catalog-remix &amp;amp;&amp;amp; npm run dev

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

&lt;/div&gt;



&lt;p&gt;Now, if you open up a web browser and navigate to &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;localhost:3000&lt;/a&gt;, you should see the starter page Remix provided!&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%2Fbyuxusu053tpg0w2bdcw.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%2Fbyuxusu053tpg0w2bdcw.png" alt="CleanShot 2022-08-19 at 14.44.10.png" width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up TailwindCSS
&lt;/h2&gt;

&lt;p&gt;This starter is very basic and is not very visually appealing yet. To style your application, you will use &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;TailwindCSS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To set up TailwindCSS, you first need to install a few dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /Documents/projects/catalog-remix
npm i -D tailwindcss postcss autoprefixer concurrently

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

&lt;/div&gt;



&lt;p&gt;These packages provide you the TailwindCSS CLI and PostCSS. You also installed &lt;code&gt;autoprefixer&lt;/code&gt;, which is a PostCSS plugin needed to use TailwindCSS. &lt;code&gt;concurrently&lt;/code&gt; is a tool that will allow you to run your development server and build your TailwindCSS styles at the same time.&lt;/p&gt;

&lt;p&gt;With all of those pieces installed, run the following command to use TailwindCSS CLI to initialize TailwindCSS in your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /Documents/projects/catalog-remix
npx tailwindcss init

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

&lt;/div&gt;



&lt;p&gt;This command will generate a new file at the root of your project named &lt;code&gt;tailwind.config.js&lt;/code&gt;. This file is where you will configure TailwindCSS.&lt;/p&gt;

&lt;p&gt;Open that file and add the following value to the &lt;code&gt;content&lt;/code&gt; key's array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// /Documents/projects/catalog-remix/tailwind.config.js

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./app/**/*.{js,ts,jsx,tsx}", // &amp;lt;-- Added this "blob"
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

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

&lt;/div&gt;



&lt;p&gt;What this does is tells TailwindCSS which files in your project will be using its utilities and classes. This helps TailwindCSS decide which of its utilities and classes should be generated into its minified output when a build is run on your project.&lt;/p&gt;

&lt;p&gt;The next step is to update your development scripts to include a step to build your CSS when you build or develop your application.&lt;/p&gt;

&lt;p&gt;Open up &lt;code&gt;package.json&lt;/code&gt; and replace the contents in the &lt;code&gt;scripts&lt;/code&gt; section with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// /Documents/projects/catalog-remix/package.json 

// ...
"scripts": {
  "build": "npm run build:css &amp;amp;&amp;amp; remix build",
  "build:css": "tailwindcss -m -i ./styles/app.css -o app/styles/app.css",
  "dev": "concurrently \"npm run dev:css\" \"remix dev\"",
  "dev:css": "tailwindcss -w -i ./styles/app.css -o app/styles/app.css"
},
// ...

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

&lt;/div&gt;



&lt;p&gt;Now when you run &lt;code&gt;npm run dev&lt;/code&gt; or &lt;code&gt;npm run build&lt;/code&gt;, rather than simple starting up or building your Remix application it will also generate a CSS file based off of the TailwindCSS classes and utilities you are using in your application.&lt;/p&gt;

&lt;p&gt;These steps require the existence of TailwindCSS's base "layers", as signified in the &lt;code&gt;-i ./styles/app.css&lt;/code&gt; argument of the &lt;code&gt;tailwindcss&lt;/code&gt; command. Those layers provide the pieces TailwindCSS uses to provide its styling.&lt;/p&gt;

&lt;p&gt;Create a new directory named &lt;code&gt;styles&lt;/code&gt; and within that directory create a new file named &lt;code&gt;app.css&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /Documents/projects/catalog-remix
mkdir styles &amp;amp;&amp;amp; touch styles/app.css

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

&lt;/div&gt;



&lt;p&gt;Add the following CSS to that file to import TailwindCSS's layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* /Documents/projects/catalog-remix/styles/app.css */

@tailwind base;
@tailwind components;
@tailwind utilities;

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

&lt;/div&gt;



&lt;p&gt;The new steps that build your CSS file will output your CSS into a file at &lt;code&gt;app/styles/app.css&lt;/code&gt;. In order to actually use those generated styles, however, you will need to import that file into your application.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;app/root.tsx&lt;/code&gt;, add the following to import those styles and use them in your application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// /Documents/projects/catalog-remix/app/root.tsx

import type { 
  MetaFunction,
  LinksFunction // &amp;lt;-- Added the LinksFunction type
} from "@remix-run/node";

// ... other imports

import styles from "./styles/app.css"

export const links: LinksFunction = () =&amp;gt; {
  return [{ rel: "stylesheet", href: styles }]
}

// ...

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

&lt;/div&gt;



&lt;p&gt;Now TailwindCSS is configured and ready to use in your application!&lt;/p&gt;

&lt;p&gt;To verify everything is working correctly, replace the contents of &lt;code&gt;app/routes/index.tsx&lt;/code&gt; with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// /Documents/projects/catalog-remix/app/routes/index.tsx

export default function Index() {
  return (
    &amp;lt;div className="h-screen w-full p-4 font-mono"&amp;gt;
      &amp;lt;div className="rounded-xl p-6 bg-gray-100 border-4 border-gray-600"&amp;gt;
        &amp;lt;h2 className="font-bold text-4xl text-gray-600"&amp;gt;Book Catalog&amp;lt;/h2&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

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

&lt;/div&gt;



&lt;p&gt;If you run &lt;code&gt;npm run dev&lt;/code&gt; and head back to &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;localhost:3000&lt;/a&gt;, you should see a page similar to the following:&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%2Fu1d8yik91uvh51aipp5g.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%2Fu1d8yik91uvh51aipp5g.png" alt="TailwindCSS Working" width="800" height="538"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you get a page similar to this one, TailwindCSS is set up and working!&lt;/p&gt;

&lt;h2&gt;
  
  
  Build a &lt;code&gt;Book&lt;/code&gt; component
&lt;/h2&gt;

&lt;p&gt;Now, you need a component that will display each book in your catalog.&lt;/p&gt;

&lt;p&gt;Create a new folder in the &lt;code&gt;app&lt;/code&gt; directory named &lt;code&gt;components&lt;/code&gt;. Then create a file within that folder named &lt;code&gt;Book.tsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /Documents/projects/catalog-remix
mkdir app/components
touch app/components/Book.tsx

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

&lt;/div&gt;



&lt;p&gt;Paste the following function into that file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// /Documents/projects/catalog-remix/app/components/Book.tsx

export default function Book() {
    return (
        &amp;lt;a href="/" className="m-2 rounded-xl p-6 border-4 border-gray-600 transition hover:-translate-y-1"&amp;gt;
            &amp;lt;h2 className="font-bold text-2xl text-gray-600"&amp;gt;How To: DevRel&amp;lt;/h2&amp;gt;
            &amp;lt;p className="text-xs text-gray-400"&amp;gt;by Sabin Adams&amp;lt;/p&amp;gt;
            &amp;lt;p className="text-gray-500 mt-2 text-md"&amp;gt;
                This book walks the reader through the ins and outs of working in the DevRel space.
            &amp;lt;/p&amp;gt;
        &amp;lt;/a&amp;gt;
    );
}

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

&lt;/div&gt;



&lt;p&gt;This function simply returns some JSX, which will render a dummy &lt;code&gt;Book&lt;/code&gt; onto the page. The data in this component is static for now, however in the next section you will populate this component with your book data from the Sanity API.&lt;/p&gt;

&lt;p&gt;Over in &lt;code&gt;app/routes/index.tsx&lt;/code&gt;, import that new component and render it within a grid a couple of times to populate your screen with a set of dummy books:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// /Documents/projects/catalog-remix/app/routes/index.tsx

import Book from '../components/Book' // &amp;lt;-- Imported the `Book` component

export default function Index() {
  return (
    &amp;lt;div className="h-screen w-full p-4 font-mono"&amp;gt;
      &amp;lt;div className="rounded-xl p-6 bg-gray-100 border-4 border-gray-600"&amp;gt;
        &amp;lt;h2 className="font-bold text-4xl text-gray-600"&amp;gt;Book Catalog&amp;lt;/h2&amp;gt;
      &amp;lt;/div&amp;gt;
      {/* Renders 6 Books within a grid 👇🏻 */}
      &amp;lt;div className="grid grid-cols-3 p-12"&amp;gt;
        &amp;lt;Book /&amp;gt;&amp;lt;Book /&amp;gt;&amp;lt;Book /&amp;gt;&amp;lt;Book /&amp;gt;&amp;lt;Book /&amp;gt;&amp;lt;Book /&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

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

&lt;/div&gt;



&lt;p&gt;Back over in your browser, you should now see your set of books rendered in a stylized grid:&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%2F6j7uae64q3pgn6ptnlwv.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%2F6j7uae64q3pgn6ptnlwv.png" alt="Catalog with dummy data" width="800" height="538"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Get your data from Sanity.io
&lt;/h1&gt;

&lt;p&gt;At this point you have Sanity set up to manage your content, and a Remix application ready to render some live data.&lt;/p&gt;

&lt;p&gt;You will now use Sanity's &lt;a href="https://www.sanity.io/docs/graphql" rel="noopener noreferrer"&gt;GraphQL API&lt;/a&gt; to fetch your content and render it into the browser.&lt;/p&gt;

&lt;p&gt;To do this, you will make use of a tool called &lt;a href="https://www.graphql-code-generator.com/" rel="noopener noreferrer"&gt;GraphQL Codegen&lt;/a&gt; to generate TypeScript types based on the GraphQL schema Sanity provides. You will then use &lt;a href="https://github.com/prisma-labs/graphql-request" rel="noopener noreferrer"&gt;&lt;code&gt;graphql-request&lt;/code&gt;&lt;/a&gt; to actually fetch the data.&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%2Fau1tlzqt4se97o9jpmpz.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%2Fau1tlzqt4se97o9jpmpz.png" alt="Sanity + Remix.png" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up GraphQL Codegen
&lt;/h2&gt;

&lt;p&gt;First, you will set up GraphQL Codegen to generate TypeScript types based off of your GraphQL schema. It will also generate types based on the queries you write that represent the data you actually query for.&lt;/p&gt;

&lt;p&gt;To get started, install these packages in your Remix application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /Documents/projects/catalog-remix
npm i -D graphql @graphql-codegen/cli @graphql-codegen/typed-document-node @graphql-codegen/typescript @graphql-codegen/typescript-operations

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

&lt;/div&gt;



&lt;p&gt;These give you access to the GraphQL Codegen CLI and all of the plugins you need to generate the types representing your GraphQL schema and queries. In order to generate these types, you first need to configure GraphQL Codegen.&lt;/p&gt;

&lt;p&gt;Create a new file at the root of your Remix project named &lt;code&gt;codegen.yml&lt;/code&gt; with the following contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /Documents/projects/catalog-remix/codegen.yml

generates:
  ./app/models/sanity-generated.ts:
    schema: &amp;lt;placeholder&amp;gt;
    documents: &amp;lt;placeholder&amp;gt;
    plugins:
      - typescript
      - typescript-operations
      - typed-document-node

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

&lt;/div&gt;



&lt;p&gt;This configuration lets GraphQL Codegen know to generate a file at &lt;code&gt;app/models/sanity-generated.ts&lt;/code&gt; with all of the types you need.&lt;/p&gt;

&lt;p&gt;There are three different configurations provided for this generated file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;schema&lt;/strong&gt; : The URL of your GraphQL API&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;documents&lt;/strong&gt; : Tells the CLI which files in your project have GraphQL queries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;plugins&lt;/strong&gt; : Lets the CLI know which plugins to use to generate types&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Currently, the &lt;code&gt;schema&lt;/code&gt; and &lt;code&gt;documents&lt;/code&gt; fields have dummy data in them. You will need to populate these.&lt;/p&gt;

&lt;p&gt;To populate &lt;code&gt;schema&lt;/code&gt;, you first need to deploy your Sanity project's GraphQL API. To do so, navigate to the Sanity project's folder and run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /Documents/projects/catalog-sanity
sanity graphql deploy

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

&lt;/div&gt;



&lt;p&gt;After running this command, the URL to your GraphQL API will be outputted into the terminal. Copy that URL:&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%2F0kc3k95t7t5wr9dn17yc.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%2F0kc3k95t7t5wr9dn17yc.png" alt="Sanity GraphQL" width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, paste that value into the &lt;code&gt;codegen.yml&lt;/code&gt; file's &lt;code&gt;schema&lt;/code&gt; field:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /Documents/projects/catalog-remix/codegen.yml

generates:
  ./app/models/sanity-generated.ts:
    schema: # paste the API URL here #
    documents: &amp;lt;placeholder&amp;gt;
    plugins:
      - typescript
      - typescript-operations
      - typed-document-node

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

&lt;/div&gt;



&lt;p&gt;The next piece you will need to fill in is the &lt;code&gt;documents&lt;/code&gt; key. You will write all of your queries in a file at &lt;code&gt;app/graphql&lt;/code&gt;. Create that directory and add a file named &lt;code&gt;books.query.gql&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /Documents/projects/catalog-remix
mkdir app/graphql
touch app/graphql/books.query.gql

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

&lt;/div&gt;



&lt;p&gt;Then paste the file path &lt;code&gt;./app/graphql/**/*.ts&lt;/code&gt; into the &lt;code&gt;documents&lt;/code&gt; field in the &lt;code&gt;codegen.yml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /Documents/projects/catalog-remix/codegen.yml

generates:
  ./app/models/sanity-generated.ts:
    schema: &amp;lt;hidden&amp;gt;
    documents: # paste the file path here #
    plugins:
      - typescript
      - typescript-operations
      - typed-document-node

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

&lt;/div&gt;



&lt;p&gt;GraphQL Codegen is now configured to ready all queries from &lt;code&gt;.ts&lt;/code&gt; files within the &lt;code&gt;app/graphql&lt;/code&gt; folder, but you need a way to actually generate the types.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;package.json&lt;/code&gt;, add the following script to the &lt;code&gt;scripts&lt;/code&gt; field:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// /Documents/projects/catalog-remix/package.json

// ...
"scripts": {
  // ...
  "codegen": "npx graphql-codegen"
}
// ...

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

&lt;/div&gt;



&lt;p&gt;At this point, you are ready to generate types based off of your queries and the GraphQL Schema! There is only one problem... you don't have any queries yet!&lt;/p&gt;

&lt;p&gt;You will use &lt;a href="https://github.com/prisma-labs/graphql-request" rel="noopener noreferrer"&gt;&lt;code&gt;graphql-request&lt;/code&gt;&lt;/a&gt; and its helpers to write your GraphQL queries and fetch the data from Sanity's GraphQL API.&lt;/p&gt;

&lt;p&gt;Install the &lt;code&gt;graphql-request&lt;/code&gt; library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /Documents/projects/catalog-remix
npm i graphql-request

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

&lt;/div&gt;



&lt;p&gt;Then, in &lt;code&gt;app/graphql/books.query.ts&lt;/code&gt;, add the following GraphQL query to fetch your book data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// /Documents/projects/catalog-remix/app/graphql/books.query.ts

import { gql } from "graphql-request";

export default gql`
  query GetBooks {
    allBook {
      _id
      title
      author
      description
    }
  }
`;

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : If you'd like to see all of the data available from the GraphQL API, check out the GraphQL playground by going to your GraphQL API's URL in your web browser.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now that you have a query written, run the following command to generate your types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /Documents/projects/catalog-remix
npm run codegen

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

&lt;/div&gt;



&lt;p&gt;You should see a new &lt;code&gt;app/models&lt;/code&gt; directory with a file named &lt;code&gt;sanity-generated.ts&lt;/code&gt; inside of it. This file contains your TypeScript types!&lt;/p&gt;

&lt;h2&gt;
  
  
  Query Sanity's GraphQL API
&lt;/h2&gt;

&lt;p&gt;You now have TypeScript types to represent the data you expect to retrieve from the Sanity API. At this point, you can write the queries for your data.&lt;/p&gt;

&lt;p&gt;Create a new directory named &lt;code&gt;services&lt;/code&gt; within the &lt;code&gt;app&lt;/code&gt; directory and create a file within that directory named &lt;code&gt;sanity.service.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /Documents/projects/catalog-remix
mkdir app/services
touch app/services/sanity.service.ts

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

&lt;/div&gt;



&lt;p&gt;This is where you will write the function that will fetch the data.&lt;/p&gt;

&lt;p&gt;Add the following code to create a function that fetches the API for your books and properly types the response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// /Documents/projects/catalog-remix/app/services/sanity.service.ts

import { GraphQLClient } from "graphql-request";
import type { GetBooksQuery } from "../models/sanity-generated";
import BookQuery from "../graphql/books.query";

export async function getBooks() {
  const graphcms = new GraphQLClient(process.env.SANITY_API_URL || "");
  const { allBook } = await graphcms.request&amp;lt;GetBooksQuery&amp;gt;(BookQuery);
  return allBook;
}

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

&lt;/div&gt;



&lt;p&gt;The code above assumes you have an environment variable named &lt;code&gt;SANITY_API_URL&lt;/code&gt; that contains the URL of the GraphQL API.&lt;/p&gt;

&lt;p&gt;Create a file named &lt;code&gt;.env&lt;/code&gt; at the root of your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /Documents/projects/catalog-remix
touch .env

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

&lt;/div&gt;



&lt;p&gt;Then add the following contents to that file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /Documents/projects/catalog-remix/.env

SANITY_API_URL=&amp;lt;your_api_url&amp;gt; 
# Example: SANITY_API_URL=https://gsithqzp.api.sanity.io/v1/graphql/production/default

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

&lt;/div&gt;



&lt;p&gt;Now that your &lt;code&gt;getBooks&lt;/code&gt; function is ready and your environment has the correct API URL available you are ready to run your query.&lt;/p&gt;

&lt;p&gt;Within Remix, you have the ability to create a &lt;a href="https://remix.run/docs/en/v1/guides/data-loading" rel="noopener noreferrer"&gt;"loader"&lt;/a&gt; function that, when deployed, is treated as a serverless function and is deployed separately from the client-side code.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;app/routes/index.ts&lt;/code&gt;, create a loader function that simply fetches your books and returns them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// /Documents/projects/catalog-remix/app/routes/index.ts

import Book from '../components/Book'
import type { LoaderFunction } from '@remix-run/node';
import { getBooks } from '../services/sanity.service'

export const loader: LoaderFunction = async () =&amp;gt; {
  const books = await getBooks()
  return { books }
}
// ...

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

&lt;/div&gt;



&lt;p&gt;Then, import the &lt;a href="https://remix.run/docs/en/v1/api/remix#useloaderdata" rel="noopener noreferrer"&gt;&lt;code&gt;useLoaderData&lt;/code&gt;&lt;/a&gt; hook Remix provides and use it to capture the results of your loader function. Be sure to type the variable using the &lt;code&gt;useLoaderData&lt;/code&gt; function's generic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// /Documents/projects/catalog-remix/app/routes/index.ts

// ...

export default function Index() {
  const { books } = useLoaderData&amp;lt;{
    books: GetBooksQuery['allBook'][0][]
  }&amp;gt;()

  return (/* JSX */);
}

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

&lt;/div&gt;



&lt;p&gt;You are now querying your data and accessing that data from your application. The data from your API In the next section, you will fix up your &lt;code&gt;Book&lt;/code&gt; component so that it will render the actual book data and render one for each book in the API response.&lt;/p&gt;

&lt;h2&gt;
  
  
  Render your Book data
&lt;/h2&gt;

&lt;p&gt;Head back over to &lt;code&gt;app/components/Book.tsx&lt;/code&gt; and import the &lt;code&gt;GetBooksQuery&lt;/code&gt; type. Use that type to define a &lt;code&gt;book&lt;/code&gt; prop on the &lt;code&gt;Book&lt;/code&gt; component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// /Documents/projects/catalog-remix/app/components/Book.tsx

import type { GetBooksQuery } from "../models/sanity-generated";

export default function Book({ book }: { book: GetBooksQuery['allBook'][0] }) {
  // Component code
}

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

&lt;/div&gt;



&lt;p&gt;The code above sets up a &lt;code&gt;book&lt;/code&gt; property on the component whose type matches the type of a single book from your API response.&lt;/p&gt;

&lt;p&gt;You can now use that property to render your book data into the component. Update the JSX in that component to use the book's data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// /Documents/projects/catalog-remix/app/components/Book.tsx

import type { GetBooksQuery } from "../models/sanity-generated";

export default function Book({ book }: { book: GetBooksQuery['allBook'][0] }) {
    return (
        &amp;lt;a href="/" className="m-2 rounded-xl p-6 border-4 border-gray-600 transition hover:-translate-y-1"&amp;gt;
            &amp;lt;h2 className="font-bold text-2xl text-gray-600"&amp;gt;{ book.title }&amp;lt;/h2&amp;gt;
            &amp;lt;p className="text-xs text-gray-400"&amp;gt;{ book.author }&amp;lt;/p&amp;gt;
            &amp;lt;p className="text-gray-500 mt-2 text-md"&amp;gt;{ book.description }&amp;lt;/p&amp;gt;
        &amp;lt;/a&amp;gt;
    );
}

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

&lt;/div&gt;



&lt;p&gt;Finally, head back to &lt;code&gt;app/routes/index.ts&lt;/code&gt; and render one &lt;code&gt;Book&lt;/code&gt; component for each book in your &lt;code&gt;books&lt;/code&gt; variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// /Documents/projects/catalog-remix/app/routes/index.ts

// ...

export default function Index() {
  const { books } = useLoaderData&amp;lt;{ books: GetBooksQuery['allBook'][0][] }&amp;gt;()

  return (
    &amp;lt;div className="h-screen w-full p-4 font-mono"&amp;gt;
      {/* ... */}
      &amp;lt;div className="grid grid-cols-3 p-12"&amp;gt;
        {/* Render the books here 👇🏻 */}
        {books.map(book =&amp;gt; &amp;lt;Book book={book} key={book._id} /&amp;gt;)}
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

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

&lt;/div&gt;



&lt;p&gt;Back over in your browser, you should now see a list of your actual data rendered out onto the page!&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%2Fizasz3bblmn8zzh1lry1.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%2Fizasz3bblmn8zzh1lry1.png" alt="Complete application" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point your application is complete! Sanity is managing all of the data for your book catalog, which you are rendering via your Remix application 🎉&lt;/p&gt;

&lt;p&gt;This is something to share with the world! In the next section, you will wrap things up by deploying your application.&lt;/p&gt;

&lt;h1&gt;
  
  
  Deploy your applications
&lt;/h1&gt;

&lt;p&gt;In order to deploy this application, you will need to host both projects on GitHub. You will also deploy the Sanity project so you can access your Sanity Studio at any time via the web browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Push both projects to GitHub
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : If you do not have a GitHub account, you can create one for free &lt;a href="https://github.com/signup" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To host your Remix applicaiton on GitHub, you first need to create a new GitHub repository that will hold your code. Head over to the GitHub dashboard and hit the &lt;strong&gt;New&lt;/strong&gt; button to create a new repository:&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%2Fh6k57ls8j04c139egnuz.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%2Fh6k57ls8j04c139egnuz.png" alt="GitHub Dashboard" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will be asked for a few details about the repository. Give the repository a name and hit &lt;strong&gt;Create repository&lt;/strong&gt;. You should then be redirected to a page that looks similar to this one:&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%2F0rn2zvanwgnqli6jkffe.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%2F0rn2zvanwgnqli6jkffe.png" alt="New GitHub Repository Page" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Grab the SSH URL for the repository by hitting the copy button signified in the image below:&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%2Fzya1i5vdruu9k8kih2kt.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%2Fzya1i5vdruu9k8kih2kt.png" alt="Copy SSH URL Button" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, in your terminal head over to the Remix application and run the following set of commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /Documents/projects/catalog-remix
git init
git remote add origin &amp;lt;YOUR SSH URL&amp;gt;
git branch -m main
git add .
git commit -m "Initial Commit"
git push --set-upstream origin main

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

&lt;/div&gt;



&lt;p&gt;If you head back over to your GitHub repository page and refresh, you should now see your project's contents:&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%2Fjjpv9gdmrtgxveflsr97.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%2Fjjpv9gdmrtgxveflsr97.png" alt="Remix Application On GitHub" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, within your Sanity project's code base create a new file at the root named &lt;code&gt;.gitignore&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /Documents/projects/catalog-sanity
touch .gitignore

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

&lt;/div&gt;



&lt;p&gt;Add the following to the contents of that file:&lt;br&gt;
&lt;/p&gt;

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

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

&lt;/div&gt;



&lt;p&gt;This will ensure you do not push the &lt;code&gt;node_modules&lt;/code&gt; folder to GitHub.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : Your Remix application came with this already set up.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then, repeat all of the steps you followed to push your Remix application to a new GitHub repository on this project.&lt;/p&gt;

&lt;p&gt;Once you have finished adding your Sanity project to its own GitHub repository, you will be ready to deploy your application and the Sanity Studio!&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy the Remix application
&lt;/h2&gt;

&lt;p&gt;You will use &lt;a href="https://vercel.com" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt; to deploy and host your applications.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : You can create a free account if you do not already have one &lt;a href="https://vercel.com/signup" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you are in the dashboard, hit the &lt;strong&gt;Add New...&lt;/strong&gt; button to create a new project in Vercel:&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%2F2okxvv5xi4a6xx66v456.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%2F2okxvv5xi4a6xx66v456.png" alt="Vercel New" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the &lt;strong&gt;Project&lt;/strong&gt; option that drops down when you hit that button:&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%2Farfob8ptk8bhv0p1axw3.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%2Farfob8ptk8bhv0p1axw3.png" alt="Vercel New Project Option" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will land on a page where you can choose a GitHub repository to deploy.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : You may have to connect your GitHub account. The steps to accomplish this will be on the page if you haven't connected an account already.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Select your Remix application's GitHub repository from the list of available repositories:&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%2Fis4qjodc9ok5awjwu7vv.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%2Fis4qjodc9ok5awjwu7vv.png" alt="Remix Project Vercel" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will bring you to a page where you can configure the deployment.&lt;/p&gt;

&lt;p&gt;On this page, expand the &lt;strong&gt;Environment Variables&lt;/strong&gt; section and add a &lt;code&gt;SANITY_API_URL&lt;/code&gt; environment variable, using the Sanity GraphQL API URL as the value:&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%2Fvbqsyy5m2mtc5slkdfha.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%2Fvbqsyy5m2mtc5slkdfha.png" alt="Sanity URL Environment Variable" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Be sure to click &lt;strong&gt;Add&lt;/strong&gt; after filling in the variable's details.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : If you are unsure about what to input for the environment variable's value, check the value you used in your &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Finally, you can hit &lt;strong&gt;Deploy&lt;/strong&gt; to deploy your application. This will kick off the Remix project's build process and deploy the application to a live URL!&lt;/p&gt;

&lt;p&gt;When that finishes up, you will be sent to a page that looks like this:&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%2F79hn4zlnlxxybbdgdxcs.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%2F79hn4zlnlxxybbdgdxcs.png" alt="Vercel Deployed" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you click the image preview of your site, a new tab will open to your newly deployed website!&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%2Fyhjlwux38rhe3ppweraf.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%2Fyhjlwux38rhe3ppweraf.png" alt="Live Application" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy the Sanity project
&lt;/h2&gt;

&lt;p&gt;The steps to deploy your Sanity application are all exactly the same, except you do not have to add an environment variable.&lt;/p&gt;

&lt;p&gt;Head back over to the &lt;a href="https://vercel.com/dashboard" rel="noopener noreferrer"&gt;Vercel dashboard&lt;/a&gt; and click the &lt;strong&gt;Add New...&lt;/strong&gt; button again, selecting the &lt;strong&gt;Project&lt;/strong&gt; option from the dropdown.&lt;/p&gt;

&lt;p&gt;You will again be redirected to a page where you can select with GitHub repository you want to deploy. Choose the repository that holds your Sanity project:&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%2Fks0kedr306ogktk9jxly.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%2Fks0kedr306ogktk9jxly.png" alt="New Vercel Project" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the next page, simply hit the &lt;strong&gt;Deploy&lt;/strong&gt; button to deploy the Sanity Studio:&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%2Faj5by92e4yknmj3k1ve9.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%2Faj5by92e4yknmj3k1ve9.png" alt="Deploy Sanity Studio" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the deployment completes, open up the live site to see what it looks like:&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%2Fkpwhka2h8n7gjk972756.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%2Fkpwhka2h8n7gjk972756.png" alt="Sanity Broken" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Oops... this doesn't look right! This problem occurred because Sanity is currently only accessible through &lt;code&gt;localhost&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Head over to your local Sanity project's directory via a terminal and run the following command, replacing &lt;code&gt;&amp;lt;YOUR_APP_URL&amp;gt;&lt;/code&gt; with the URL of your deployed studio:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /Documents/projects/catalog-sanity
sanity cors add &amp;lt;YOUR_APP_URL&amp;gt; --credentials
# Example: sanity cors add https://book-catalog-sanity-ffwumik6d-sabinadams.vercel.app/desk --credentials

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

&lt;/div&gt;



&lt;p&gt;If you now head back to the browser and refresh, you should reach the Sanity Studio login page. Upon logging in, you will see your studio:&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%2Frbg6cbjsv2x68p3fktrl.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%2Frbg6cbjsv2x68p3fktrl.png" alt="Sanity Live and Working" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Wrapping Up
&lt;/h1&gt;

&lt;p&gt;Throughout this tutorial you accomplished a lot!&lt;/p&gt;

&lt;p&gt;Just to recap, throughout this tutorial you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Built a Sanity project to host your book catalog data&lt;/li&gt;
&lt;li&gt;Built a Remix application to retrieve and render your data&lt;/li&gt;
&lt;li&gt;Added both projects to GitHub&lt;/li&gt;
&lt;li&gt;Deployed both projects with Vercel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The end result is an easy-to-use book catalog, where you can at any time log in to your Sanity Studio from your web browser and add records to your book catalog without having to re-deploy the Remix application.&lt;/p&gt;

&lt;p&gt;Tools like Sanity are super powerful, especially when you have complex content and/or multiple types of content to manage. They allow you to easily manage your data in an environment completely separate from your application.&lt;/p&gt;

&lt;p&gt;If you have any questions, please feel free to reach out to me on &lt;a href="https://twitter.com/sabinthedev" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>sanity</category>
      <category>remix</category>
      <category>vercel</category>
    </item>
    <item>
      <title>Managing Lambda Size with Multiple Prisma Clients</title>
      <dc:creator>Sabin Adams</dc:creator>
      <pubDate>Sun, 06 Feb 2022 07:49:32 +0000</pubDate>
      <link>https://dev.to/sabinthedev/managing-lambda-size-with-multiple-prisma-clients-4m8l</link>
      <guid>https://dev.to/sabinthedev/managing-lambda-size-with-multiple-prisma-clients-4m8l</guid>
      <description>&lt;p&gt;The serverless architecture allows you to set up your applications in a way that is massively scalable, highly available, potentially cheap, and hands-off in terms of managing the host server.&lt;/p&gt;

&lt;p&gt;These benefits have drawn many to begin adopting this architecture. There are, however, some snags you may run into along the way.&lt;/p&gt;

&lt;p&gt;The one we'll be looking at today is Lambda's size-limit, specifically when your application uses Prisma, and how to architect your system in a way that maintains a low lambda size.&lt;/p&gt;

&lt;p&gt;Let's jump right in!&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;We will be talking about and building out a sample serverless function on &lt;a href="https://aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;AWS Lambda&lt;/a&gt; using the &lt;a href="https://www.serverless.com/" rel="noopener noreferrer"&gt;Serverless&lt;/a&gt; framework. As such, you should be at least somewhat familiar with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js&lt;/li&gt;
&lt;li&gt;ExpressJS Framework&lt;/li&gt;
&lt;li&gt;Serverless concepts&lt;/li&gt;
&lt;li&gt;Serverless Framework&lt;/li&gt;
&lt;li&gt;Prisma&lt;/li&gt;
&lt;li&gt;AWS ecosystem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you aren't &lt;em&gt;super&lt;/em&gt; familiar with any or all of these, don't sweat it. I'll try to explain as we go. But a basic understanding will be helpful.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make sure you've got &lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; installed&lt;/li&gt;
&lt;li&gt;Also make sure you have an &lt;a href="https://portal.aws.amazon.com/billing/signup#/start" rel="noopener noreferrer"&gt;AWS Account&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;The full code for the sample project can be found &lt;a href="https://github.com/sabinadams/petstore-prisma-lambda" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Problem We're Solving
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.prisma.io/" rel="noopener noreferrer"&gt;Prisma&lt;/a&gt; is a fantastic tool that allows you to easily set up a fully type-safe &lt;em&gt;"next-gen ORM"&lt;/em&gt; and generate a feature-rich library that you can use to interact with your database.&lt;/p&gt;

&lt;p&gt;As Prisma grows in popularity, more and more people are starting to use it in their serverless applications and functions. One finding resulting from this, however, is that the Prisma library can be pretty expensive in terms of file-size, especially when using multiple &lt;strong&gt;Prisma Clients&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This problem is largely due to the size of the &lt;strong&gt;Prisma Engine&lt;/strong&gt; binaries, which are files that handle the connections and interactions with 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%2Fz0t30ed8hferludlbon2.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%2Fz0t30ed8hferludlbon2.png" alt="I8do25A_ynswyd.png" width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each &lt;strong&gt;Prisma Client&lt;/strong&gt; includes a copy of the binary for your OS (or whichever OS you have configured Prisma to use) and currently you need a &lt;em&gt;separate Prisma Client&lt;/em&gt; for each database and each schema within those databases you would like to use.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: The prisma team is working on an enhancement to alleviate a part of this issue and allow multiple schemas in one client.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are multiple different operating systems the &lt;strong&gt;Prisma Engine&lt;/strong&gt; binary can be built for. AWS Lambda uses the &lt;code&gt;rhel-openssl-1.0.x&lt;/code&gt; binary, which is downloaded into each generated &lt;strong&gt;Prisma Client&lt;/strong&gt; as well as into the &lt;code&gt;node_modules/@prisma&lt;/code&gt; folder. This binary tends to be around &lt;code&gt;41mb&lt;/code&gt; at the time of writing this article.&lt;/p&gt;

&lt;p&gt;AWS Lambda has &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html" rel="noopener noreferrer"&gt;upload limits&lt;/a&gt; of &lt;code&gt;50mb&lt;/code&gt; for zipped artifacts &lt;em&gt;(unless you opt to use S3 to store your deployment package and download it when the function is invoked)&lt;/em&gt; and &lt;code&gt;250mb&lt;/code&gt; for the unzipped version.&lt;/p&gt;

&lt;p&gt;As you can imagine, as you add &lt;strong&gt;Prisma Clients&lt;/strong&gt; &lt;em&gt;(maybe your database has 5 schemas you want access to and you therefore need 5 clients)&lt;/em&gt;, the sizes of all those files add up quickly!&lt;/p&gt;

&lt;p&gt;In order for this awesome technology to be feasible in a serverless setting, we need to figure out a way to get that file size down...&lt;/p&gt;

&lt;p&gt;To demonstrate the method I've come up with to alleviate this size problem, let's build out a simple &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;ExpressJS&lt;/a&gt; application with a couple of &lt;strong&gt;Prisma Clients&lt;/strong&gt; and deploy it in a way that keeps the file size manageable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up An ExpressJS Server
&lt;/h2&gt;

&lt;p&gt;First off, we'll get the basic skeleton of our Express server started. Head over to your directory of choice and create a folder to hold your project. I'll be creating a function that handles recording Dogs and Cats in my pet store 🐶🐈.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;petstore &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;petstore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're going to want a few dependencies to allow us to use and run Express and perform a few tasks later on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
npm i &lt;span class="nt"&gt;-s&lt;/span&gt; express dotenv fs-extra serverless-http
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll also need a few development dependencies to allow us to use Prisma, run our server with live-reload, and configure custom scripts in our Serverless config later on.&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 &lt;span class="nt"&gt;-d&lt;/span&gt; nodemon prisma serverless-scriptable-plugin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open up the project (&lt;code&gt;code .&lt;/code&gt; for VSCode users) and create a file named &lt;code&gt;index.js&lt;/code&gt; at the root of the project with the following boilerplate code to start off our Express app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&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;port&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;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Get express application&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Set up default route&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&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="o"&gt;=&amp;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;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Welcome to the Petstore!`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Start 'er up!&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`Listening on: http://localhost:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; `&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go ahead and run the application using Nodemon&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;You should see your server come up! If you hit that default route at &lt;code&gt;localhost:8000&lt;/code&gt;, either using some HTTP client or your browser, you should see your response come back successfully!&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%2Fdfs53l4838ydmugr24u5.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%2Fdfs53l4838ydmugr24u5.png" alt="Screen Shot 2022-02-04 at 12.03.15 AM.png" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: I'm using &lt;a href="https://www.thunderclient.com/" rel="noopener noreferrer"&gt;Thunder Client&lt;/a&gt;, an HTTP client extension for VSCode. It's &lt;em&gt;amazing&lt;/em&gt;, give it a try if you haven't already!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Setting Up Multiple Prisma Clients
&lt;/h3&gt;

&lt;p&gt;The next thing we'll want to do is set up two &lt;strong&gt;Prisma Clients&lt;/strong&gt; so we can interact with two different databases in our Express app. We'll first use the &lt;strong&gt;Prisma CLI&lt;/strong&gt; to initialize Prisma in our project and scaffold out our first schema.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This will create a &lt;code&gt;/prisma&lt;/code&gt; folder and a fresh schema for you to work with. If you aren't familiar with Prisma and its set of tools, definitely check out the &lt;a href="https://www.prisma.io/docs/" rel="noopener noreferrer"&gt;docs&lt;/a&gt;! It's a powerful piece of software!&lt;/p&gt;

&lt;p&gt;We'll go ahead and rename that initial &lt;code&gt;schema.prisma&lt;/code&gt; to &lt;code&gt;dog.prisma&lt;/code&gt;, as it will define our Dog database. That file should contain a default shell of a schema already set up. We're going to update those contents to use SQLite as the database and add a &lt;code&gt;Dog&lt;/code&gt; model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;generator client {
  provider = "prisma-client-js"
  output = "../node_modules/.prisma/dog-client"
  binaryTargets = ["native", "rhel-openssl-1.0.x"]
}

datasource db {
  provider = "sqlite"
  url = env("DOG_URL")
}

model Dog {
  id String @id @default(cuid())
  name String
  color String
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So what does this do exactly?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sets up a datasource that will connect to a SQLite database found at a path provided in the environment &lt;em&gt;(we'll set that up in a sec)&lt;/em&gt;. &lt;/li&gt;
&lt;li&gt;Defines a &lt;code&gt;Dog&lt;/code&gt; model that will correlate to a &lt;code&gt;Dog&lt;/code&gt; table in our database.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Important&lt;/em&gt;: Specifies that we want to download the &lt;code&gt;rhel-openssl-1.0.x&lt;/code&gt; binary along with the native binary, which is the binary needed by AWS Lambda&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Important&lt;/em&gt;: Specifies an output directory for our generated client. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By default the output of the &lt;strong&gt;Prisma Client&lt;/strong&gt; is &lt;code&gt;node_modules/.prisma/client&lt;/code&gt;. This is fine for a single client, but we are going to use multiple clients! We are creating our own folder in &lt;code&gt;.prisma&lt;/code&gt; to hold our dog client.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: You can output the client anywhere, even outside of &lt;code&gt;node_modules&lt;/code&gt;, but I've chosen here to allow us to easily make use of Layers in AWS later on.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;prisma init&lt;/code&gt; command also created a &lt;code&gt;.env&lt;/code&gt; file. Go ahead and replace the contents with the following to set up our database's file path:&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;DOG_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"file:./dog.db"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll now do the same exact process, but create a &lt;code&gt;Cat&lt;/code&gt; database! Add another file to the &lt;code&gt;/prisma&lt;/code&gt; folder called &lt;code&gt;cat.prisma&lt;/code&gt; with these contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;generator client {
    provider = "prisma-client-js"
    output = "../node_modules/.prisma/cat-client"
    binaryTargets = ["native", "rhel-openssl-1.0.x"]
}

datasource db {
    provider = "sqlite"
    url = env("CAT_URL")
}

model Cat {
    id String @id @default(cuid())
    name String
    color String
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And update &lt;code&gt;.env&lt;/code&gt; to add an environment variable named &lt;code&gt;CAT_URL&lt;/code&gt;:&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;CAT_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"file:./cat.db"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now generate our databases and &lt;strong&gt;Prisma Clients&lt;/strong&gt;.&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="c"&gt;# Create the DBs using Migrations&lt;/span&gt;
prisma migrate dev &lt;span class="nt"&gt;-name&lt;/span&gt; init &lt;span class="nt"&gt;--schema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;prisma/dog.prisma
prisma migrate dev &lt;span class="nt"&gt;-name&lt;/span&gt; init &lt;span class="nt"&gt;--schema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;prisma/cat.prisma
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great! Your file tree should look something like this at this point:&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%2F4qtagbmz57gffamf5hq3.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%2F4qtagbmz57gffamf5hq3.png" alt="Screen Shot 2022-02-04 at 12.23.41 AM.png" width="474" height="638"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Those migrate commands set up a migration history for your databases, created the database files &lt;em&gt;(because we are using SQLite)&lt;/em&gt; and generated the &lt;strong&gt;Prisma Clients&lt;/strong&gt; for us to use in our application!&lt;/p&gt;

&lt;p&gt;Let's put those to use and start playing with data.&lt;/p&gt;

&lt;p&gt;We'll need to import the &lt;strong&gt;Prisma Clients&lt;/strong&gt; and instantiate them in &lt;code&gt;index.js&lt;/code&gt; so we can use them in our routes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;PrismaClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DogClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.prisma/dog-client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;- &lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;PrismaClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CatClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.prisma/cat-client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;port&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;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;8000&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;dogClient&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;DogClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;catClient&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;CatClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Error Handling and Middlewares
&lt;/h3&gt;

&lt;p&gt;Our routes will have some asynchronous actions, so let's add a utility function after we instantiate our Express app to wrap our routes in. We'll use this to gracefully throw errors in the asynchronous context.&lt;/p&gt;

&lt;p&gt;I'm also adding a middleware here to parse out JSON bodies in our requests.&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="c1"&gt;// Parse JSON bodies in requests&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&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="c1"&gt;// Wrapper for async routes&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;asyncHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fn&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;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;next&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'll want to set up an error handler to gracefully catch our application's errors. Add this near the bottom of the file, right before we call &lt;code&gt;app.listen&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Catch any errors, throw detailed info if in development&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&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;next&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;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;500&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;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Something went wrong&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="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;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;development&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;devMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;devStack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}),&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding Routes To Our API
&lt;/h3&gt;

&lt;p&gt;Great, now we're ready to add some routes! We're going to create four endpoints in our API:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;POST /dog&lt;/code&gt;: Creates a dog&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /dog&lt;/code&gt;: Gets all dogs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POST /cat&lt;/code&gt;: Creates a cat&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /cat&lt;/code&gt;: Gets all cats&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Make sure to add these routes before the error handler middleware we added previously&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We'll keep these routes super simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Get all dogs&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/dog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nf"&gt;asyncHandler&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;req&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="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;dogs&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;dogClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findMany&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;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dogs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Create a dog&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/dog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nf"&gt;asyncHandler&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;req&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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;newDog&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;dogClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;color&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="nx"&gt;newDog&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Get all cats&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/cat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nf"&gt;asyncHandler&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;req&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="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;cats&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;catClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findMany&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;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cats&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Create a cat&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/cat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nf"&gt;asyncHandler&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;req&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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;newCat&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;catClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;color&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="nx"&gt;newCat&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;Beautiful! We've got ourselves an API in the works! If you hit a few of the endpoints, you should find you are able to create and view your Cats and Dogs.&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%2Ft4picr2wpeuls391fg1l.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%2Ft4picr2wpeuls391fg1l.png" alt="Screen Shot 2022-02-04 at 12.44.07 AM.png" width="800" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffxy4rq5opyzwdgh45yx9.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%2Ffxy4rq5opyzwdgh45yx9.png" alt="Screen Shot 2022-02-04 at 12.44.56 AM.png" width="800" height="275"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: You can also use Prisma Studio to view this data in your database. Run &lt;code&gt;prisma studio --schema=prisma/dogs.prisma&lt;/code&gt; to check out the Dogs database. Change the schema file to &lt;code&gt;cats.prisma&lt;/code&gt; to see the Cats.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Configuring Serverless
&lt;/h2&gt;

&lt;p&gt;Okay enough setup, we've got our app going and working! Let's deploy this sucker to AWS Lambda so we can start analyzing and trimming things down!&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapping The Express App
&lt;/h3&gt;

&lt;p&gt;In order to run this application in a serverless environment, we'll need to wrap our app using &lt;code&gt;serverless-http&lt;/code&gt; and export that as our serverless function handler.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;PrismaClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DogClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.prisma/dog-client&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;PrismaClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CatClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.prisma/cat-client&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;serverless&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;serverless-http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;port&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;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Our code...&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;serverless&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our application should be runnable in a serverless environment now!&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up Credentials in Serverless Framework
&lt;/h3&gt;

&lt;p&gt;The next thing we need to do is install the &lt;a href="https://www.serverless.com/framework/docs/getting-started" rel="noopener noreferrer"&gt;Serverless Framework CLI&lt;/a&gt; globally.&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 &lt;span class="nt"&gt;-g&lt;/span&gt; serverless
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This provides us with a set of tools and a framework to help us easily build out our AWS deployment configurations and architecture.&lt;/p&gt;

&lt;p&gt;We'll also need to configure our AWS access keys so the Serverless Framework will have access to deploy to our AWS account. Sign in to your AWS account and grab your access keys. You can find them by following along below:&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%2Fxmcddyt8rod0lh9txcci.gif" 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%2Fxmcddyt8rod0lh9txcci.gif" alt="Feb-04-2022 00-57-30.gif" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you've got those, run this command to configure your credentials locally in Serverless Framework.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;serverless config credentials &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--provider&lt;/span&gt; aws &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--key&lt;/span&gt; &amp;lt;access-key&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--secret&lt;/span&gt; &amp;lt;secret-access-key&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;More details on setting up your credentials &lt;a href="https://www.serverless.com/framework/docs/providers/aws/guide/credentials" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Configuring The Service
&lt;/h3&gt;

&lt;p&gt;Next we'll create a &lt;code&gt;serverless.yml&lt;/code&gt; file in the root of the application where we will configure what to deploy to AWS and how.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;petstore&lt;/span&gt;
&lt;span class="na"&gt;frameworkVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&lt;/span&gt;
&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodejs12.x&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dev&lt;/span&gt;
  &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-east-1&lt;/span&gt;
&lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;petstore-api&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;index.handler&lt;/span&gt;
    &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;httpApi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;*'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This does a few different things. Notably:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Defines a service we are going to deploy&lt;/li&gt;
&lt;li&gt;Defines the &lt;code&gt;petstore-api&lt;/code&gt; function we want to deploy&lt;/li&gt;
&lt;li&gt;Sets up our Express API as the function handler &lt;em&gt;(index.handler corresponds to the &lt;code&gt;handler&lt;/code&gt; export in &lt;code&gt;index.js&lt;/code&gt;)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Allows the function to handle &lt;strong&gt;ALL&lt;/strong&gt; HTTP requests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's all the config we need to get this thing up and running. It won't be slimmed down yet, but this is the most basic setup.&lt;/p&gt;

&lt;p&gt;Go ahead and run &lt;code&gt;sls deploy&lt;/code&gt; to deploy this function. This will take a few minutes, but as you are waiting you may notice this output:&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%2Fmfyt71yu059zxxfxb1jw.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%2Fmfyt71yu059zxxfxb1jw.png" alt="Screen Shot 2022-02-04 at 1.15.48 AM.png" width="666" height="136"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our function is already almost &lt;code&gt;114mb&lt;/code&gt;! And that's the zipped artifact! That's already above the limit enforced in AWS Lambda functions. This deployment will fail.&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%2Fihh2lnkyf5bwtsvtccri.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%2Fihh2lnkyf5bwtsvtccri.png" alt="Screen Shot 2022-02-04 at 1.18.10 AM.png" width="800" height="115"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we unzip the artifact we attempted to deploy &lt;em&gt;(found in the &lt;code&gt;.serverless&lt;/code&gt; folder)&lt;/em&gt; and take a look at where the size is coming from you'll find something like this:&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%2Ff6n8g7lobqugvhehyjs1.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%2Ff6n8g7lobqugvhehyjs1.png" alt="Screen Shot 2022-02-04 at 1.30.46 AM.png" width="800" height="186"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see here, unzipped we're at &lt;code&gt;~299mb&lt;/code&gt;, and &lt;code&gt;~281mb&lt;/code&gt; of that is coming from Prisma's files!&lt;/p&gt;

&lt;p&gt;So with two &lt;em&gt;minimal&lt;/em&gt; &lt;strong&gt;Prisma Clients&lt;/strong&gt; configured we can't even deploy! We're going to need to trim some of this down to get things going. No problem though, there are a few things we can do to accomplish this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trimming Things Down
&lt;/h2&gt;

&lt;p&gt;We have a few different tricks we can use to get this file size down and to keep it low as we add more and more &lt;strong&gt;Prisma Clients&lt;/strong&gt;. These can be used individually, or in combinations. In this example, we'll employ each different method together to get a super slim deployment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Patterns To Exclude Files
&lt;/h3&gt;

&lt;p&gt;The first thing we can do is use patterns to exclude files from the zipped output. Prisma generates files in &lt;code&gt;node_modules&lt;/code&gt; within folder called &lt;code&gt;@prisma&lt;/code&gt;, &lt;code&gt;prisma&lt;/code&gt;, and &lt;code&gt;.prisma&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A lot of these files are not needed for our application to run. For example, &lt;code&gt;@prisma&lt;/code&gt; contains a bunch of engine binary files we don't need and that take up a lot of space.&lt;/p&gt;

&lt;p&gt;Add the following configurations above your function definition in &lt;code&gt;serverless.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;package&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;patterns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;!node_modules/@prisma/engines'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;!node_modules/prisma'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;!node_modules/.prisma/**/libquery_engine-*'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;node_modules/.prisma/**/libquery_engine-rhel-openssl-1.0.x.so.node'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;Excluding every engine from &lt;code&gt;@prisma/engines&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Excluding the &lt;code&gt;node_modules/prisma&lt;/code&gt; folder. It's only used locally for things like CLI operations that aren't needed in our running application&lt;/li&gt;
&lt;li&gt;Excluding all engines from the generated clients &lt;em&gt;except for&lt;/em&gt; the &lt;code&gt;openssl-1.0.x&lt;/code&gt; file Lambda needs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you go to deploy this you'll notice your file size is already &lt;em&gt;significantly&lt;/em&gt; smaller and should actually succeed &lt;em&gt;(my deployment ended up around &lt;code&gt;~42mb&lt;/code&gt;)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fviipexxckqlg4yaiv5bd.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%2Fviipexxckqlg4yaiv5bd.png" alt="Screen Shot 2022-02-05 at 12.46.03 AM.png" width="426" height="70"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Does This Solve All The Size Problems?
&lt;/h3&gt;

&lt;p&gt;This is fantastic and should alleviate the majority of your size issues. There is, however, still a potential problem depending on your use-case.&lt;/p&gt;

&lt;p&gt;As more and more clients get added, each of those clients will still have their &lt;code&gt;openssl-1.0.x&lt;/code&gt; binary file. Soon enough we'll get right back to the size we were at before!&lt;/p&gt;

&lt;p&gt;Let's say we add &lt;code&gt;Bird&lt;/code&gt;, &lt;code&gt;Snake&lt;/code&gt;, and &lt;code&gt;Rabbit&lt;/code&gt; clients to the project. Go ahead and create new schemas for each of these, run your migration and generate the &lt;strong&gt;Prisma Client&lt;/strong&gt; for each.&lt;/p&gt;

&lt;p&gt;Now, to make our lives a little easier, create a folder called &lt;code&gt;ci&lt;/code&gt; and add a file named &lt;code&gt;generate-prisma.sh&lt;/code&gt; with these contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Building Libraries to ensure binaries are available..."&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;file &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.prisma
&lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Generating &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="p"&gt;##*/&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 
    npx prisma generate &lt;span class="nt"&gt;--schema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will go through every schema file and generate the &lt;strong&gt;Prisma Client&lt;/strong&gt;. We'll run this automatically every time we start to package a deployment using the &lt;code&gt;serverless-scriptable-plugin&lt;/code&gt; to make sure we have our client generated and ready for use. Over in &lt;code&gt;serverless.yml&lt;/code&gt; add the following config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-scriptable-plugin&lt;/span&gt;
&lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scriptable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;package:initialize'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sh&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;./ci/generate-prisma.sh'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you run &lt;code&gt;sls deploy&lt;/code&gt; again you should see your &lt;strong&gt;Prisma Clients&lt;/strong&gt; all get generated and packaged. My package ended up being around &lt;code&gt;~95mb&lt;/code&gt;, even with the excludes we configured before! That's getting awful big again and doesn't allow much space for your actual function's code.&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%2Fm5mp3orvuenv3jgsof4i.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%2Fm5mp3orvuenv3jgsof4i.png" alt="Screen Shot 2022-02-05 at 12.43.21 AM.png" width="474" height="78"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We need to set something up to consolidate those engine binaries to one location and share it across all clients.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up A Layer
&lt;/h3&gt;

&lt;p&gt;The next thing we can do is make use of the concept of &lt;strong&gt;Layers&lt;/strong&gt; in AWS. A layer allows us to split out libraries and dependencies into a &lt;em&gt;"layer"&lt;/em&gt; that can then be applied to our serverless function to help with code-sharing and maintaining a small file size.&lt;/p&gt;

&lt;p&gt;Each function can have up to five layers attached, however in our scenario we are only going to use one.&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%2Fp0iyibtl0hqzd97axkog.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%2Fp0iyibtl0hqzd97axkog.png" alt="Add a heading (1).png" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The goal here is to break out our Prisma-related dependencies from &lt;code&gt;node_modules&lt;/code&gt; into a layer and apply that layer to our function when invoked.&lt;/p&gt;

&lt;p&gt;To start this off, let's create another script in the &lt;code&gt;ci&lt;/code&gt; folder named &lt;code&gt;create-prisma-layer.sh&lt;/code&gt; that will be responsible for building out our layer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Clearing out old layer..."&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; .prisma-layer

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Generating Prisma Client"&lt;/span&gt;
sh ci/generate-prisma.sh

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Creating Prisma Layer..."&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; .prisma-layer/nodejs/node_modules/.prisma
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; .prisma-layer/nodejs/node_modules/@prisma

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Copying over @prisma and .prisma to the layer"&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; node_modules/.prisma .prisma-layer/nodejs/node_modules
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; node_modules/@prisma .prisma-layer/nodejs/node_modules

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Copying over the prisma folder, where our SQLite DBs are (not necessary for non-sqlite)"&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; prisma .prisma-layer/nodejs/prisma

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Layer Built"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a folder called &lt;code&gt;.prisma-layer&lt;/code&gt; that will hold our generated layer. Then we move in all of the modules we need.&lt;/p&gt;

&lt;p&gt;I am also moving over the &lt;code&gt;prisma&lt;/code&gt; folder that contains our SQLite DBs so we don't have to package those up with our actual function.&lt;/p&gt;

&lt;p&gt;Now over in &lt;code&gt;serverless.yml&lt;/code&gt;, replace the custom hook we added with this to run our script before packaging our artifacts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scriptable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;package:initialize'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sh&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;./ci/create-prisma-layer.sh'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can then describe that layer in our service configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;layers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;prisma&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.prisma-layer&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Layer&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Prisma&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Clients'&lt;/span&gt;
    &lt;span class="na"&gt;package&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;patterns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;!nodejs/node_modules/@prisma/engines/*'&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;!nodejs/node_modules/.prisma/**/libquery_engine-*'&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;nodejs/node_modules/.prisma/**/libquery_engine-rhel-openssl-1.0.x.so.node'&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;!nodejs/prisma/**'&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;nodejs/prisma/*.db'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And apply that new layer to our function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;petstore-api&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;index.handler&lt;/span&gt;
    &lt;span class="na"&gt;layers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;Ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;PrismaLambdaLayer&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;httpApi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;*'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;For info on how to use Layers, check out the AWS &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html" rel="noopener noreferrer"&gt;docs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because we've done this, we no longer need to include any of those Prisma dependencies in our function's package. Let's be sure to filter those out using our &lt;code&gt;patterns&lt;/code&gt; configuration. Replace the current config with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;package&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;patterns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;!node_modules/prisma'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;!node_modules/.prisma'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;!node_modules/@prisma'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;!.prisma-layer'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;!prisma'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;!ci'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;!*.*'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;!.env'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;index.js'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This essentially tells the Serverless Framework not to package any files in the root except &lt;code&gt;index.js&lt;/code&gt; and to not include the modules, temporary folders, and util folders we don't need in our deployment.&lt;/p&gt;

&lt;p&gt;Alright, we've got our &lt;code&gt;CI&lt;/code&gt; functions generating Prisma and building out a Prisma layer. We've got the deployment for our function and layer configured.&lt;/p&gt;

&lt;p&gt;Let's give it a shot! Go ahead and deploy the project.&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%2Fvip19qz6hdpp9a8pumon.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%2Fvip19qz6hdpp9a8pumon.png" alt="Screen Shot 2022-02-05 at 1.53.53 AM.png" width="784" height="120"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fantastic! Our function's artifact size is down to &lt;code&gt;~4.3mb&lt;/code&gt;! But look at the size of that layer! 💥 We just moved the bulk from one place to another...&lt;/p&gt;

&lt;p&gt;A layer has the same size constraints as a full function does, so this deployment is going to fail.&lt;/p&gt;

&lt;p&gt;This is because even though we moved off our Prisma dependencies to a layer, that layer still has all those copies of the &lt;strong&gt;Prisma Engine&lt;/strong&gt; binaries!&lt;/p&gt;

&lt;p&gt;We'll need to somehow find a way to only keep one copy and make sure every &lt;strong&gt;Prisma Client&lt;/strong&gt; uses it... 🤔&lt;/p&gt;

&lt;p&gt;Fortunately I've got a trick for that!&lt;/p&gt;

&lt;h3&gt;
  
  
  Slimming Down The Layer
&lt;/h3&gt;

&lt;p&gt;When a &lt;strong&gt;Prisma Client&lt;/strong&gt; is instantiated in your code it will look in &lt;code&gt;.prisma/&amp;lt;client-folder&amp;gt;&lt;/code&gt; to find the binary it needs. If it doesn't find it there, it searches a number of other places where the binary might be hiding.&lt;/p&gt;

&lt;p&gt;One of those places is a folder called &lt;code&gt;.prisma/client&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What this means for us is that if we create a folder called &lt;code&gt;.prisma/client&lt;/code&gt; in our layer and place the binary there, we can delete it everywhere else and all the clients should use that one!&lt;/p&gt;

&lt;p&gt;Let's see it in action. Pop open that &lt;code&gt;/ci/create-lambda-layer.sh&lt;/code&gt; file and make the following changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Clearing out old layer..."&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; .prisma-layer

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Generating Prisma Client"&lt;/span&gt;
sh ci/generate-prisma.sh

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Creating Prisma Layer..."&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; .prisma-layer/nodejs/node_modules/.prisma
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; .prisma-layer/nodejs/node_modules/@prisma

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Copying over @prisma and .prisma to the layer"&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; node_modules/.prisma .prisma-layer/nodejs/node_modules
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; node_modules/@prisma .prisma-layer/nodejs/node_modules

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Copying over the prisma folder, where our SQLite DBs are (not necessary for non-sqlite)"&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; prisma .prisma-layer/nodejs/prisma

&lt;span class="c"&gt;# Add this&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Copying over the OpenSSL 1.0.x Binary to the generic client folder in the layer"&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; .prisma-layer/nodejs/node_modules/.prisma/client
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; node_modules/.prisma/&lt;span class="k"&gt;**&lt;/span&gt;/libquery_engine-rhel-openssl-1.0.x.so.node .prisma-layer/nodejs/node_modules/.prisma/client

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Layer Built"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will go through each client folder and copy (with a replace) the binary we want into our layer at &lt;code&gt;.prisma/client&lt;/code&gt;. The result is we get one binary file in that folder.&lt;/p&gt;

&lt;p&gt;Now over in our &lt;code&gt;serverless.yml&lt;/code&gt; we can configure our Prisma layer's package pattern matcher to exclude binary files that aren't in this folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;layers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;prisma&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.prisma-layer&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Layer&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Prisma&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Clients'&lt;/span&gt;
    &lt;span class="na"&gt;package&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;patterns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;!nodejs/node_modules/@prisma/engines/*'&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;!nodejs/node_modules/.prisma/**/libquery_engine-*'&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;nodejs/node_modules/.prisma/client/libquery_engine-rhel-openssl-1.0.x.so.node'&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;nodejs/node_modules/.prisma/**/libquery_engine-rhel-openssl-1.0.x.so.node'&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;!nodejs/prisma/**'&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;nodejs/prisma/*.db'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Give that a run and see what you get!&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%2Fq3el165qbjo08nkdpwm6.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%2Fq3el165qbjo08nkdpwm6.png" alt="Screen Shot 2022-02-05 at 2.17.42 AM.png" width="792" height="122"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that's more like it! 🎉&lt;/p&gt;

&lt;p&gt;Our function and layer are pretty slim and should be able to deploy successfully!&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up Environment Variables For Lambda
&lt;/h3&gt;

&lt;p&gt;The only problem at this point is that in order to test out the API running on our serverless function, we need to set up some environment variables and handle an issue with SQLite on serverless.&lt;/p&gt;

&lt;p&gt;In the configuration for your function, we'll add a few environment variables our function needs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;petstore-api&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;DOG_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;file:/tmp/prisma/dog.db&lt;/span&gt;
      &lt;span class="na"&gt;CAT_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;file:/tmp/prisma/cat.db&lt;/span&gt;
      &lt;span class="na"&gt;BIRD_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;file:/tmp/prisma/bird.db&lt;/span&gt;
      &lt;span class="na"&gt;SNAKE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;file:/tmp/prisma/snake.db&lt;/span&gt;
      &lt;span class="na"&gt;RABBIT_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;file:/tmp/prisma/rabbit.db&lt;/span&gt;
      &lt;span class="na"&gt;NODE_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-testing&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;index.handler&lt;/span&gt;
    &lt;span class="na"&gt;layers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;Ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;PrismaLambdaLayer&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;httpApi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;*'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may be confused about why we're pointing to &lt;code&gt;/tmp/prisma&lt;/code&gt; to find the SQLite db files. That's because in a Lambda function's file system, only the &lt;code&gt;/tmp&lt;/code&gt; folder is writable.&lt;/p&gt;

&lt;p&gt;If we leave the db files outside of that directory, we would only be able to perform READ operations on the database!&lt;/p&gt;

&lt;p&gt;Because of this limitation, in our code we need to copy those files over to &lt;code&gt;/tmp&lt;/code&gt; when the application starts up in an AWS Lambda environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fs-extra&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// ... application code ...&lt;/span&gt;

&lt;span class="c1"&gt;// Start 'er up!&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Only needed for SQLite&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;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;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws-testing&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="c1"&gt;// If we are on AWS, our SQLite DBs aren't writable unless in tmp&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/opt/nodejs/prisma&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/tmp/prisma&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Listening on: http://localhost:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; `&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;This is just a workaround to get our example working. In a production setting using a database other than SQLite these steps wouldn't be necessary.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Alright, that's all configured. Now we should be able to re-deploy and actually use our function!&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%2Fhxiz515eugmksyk3e10s.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%2Fhxiz515eugmksyk3e10s.png" alt="Screen Shot 2022-02-05 at 2.32.32 AM.png" width="800" height="232"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl2djmt9n7fesodyhrwlo.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%2Fl2djmt9n7fesodyhrwlo.png" alt="Screen Shot 2022-02-05 at 2.33.01 AM.png" width="800" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: This data will be short-lived as it will only exist as long as the Lambda function exists&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Awesome! We're able to save and return our Dogs! The same should work with Cats. And we're doing it all on a super slimmed-down function with multiple databases!&lt;/p&gt;

&lt;p&gt;Pretty rad 🤘🏻&lt;/p&gt;

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

&lt;p&gt;The solutions we looked at above make it super possible to use Prisma in a serverless setting without having to worry about hitting size constraints.&lt;/p&gt;

&lt;p&gt;While we took a specific path to fit our specific needs, the same concepts can be applied to nearly any project structure you may have with some careful thought.&lt;/p&gt;

&lt;p&gt;The main goals are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✂️ Remove any un-necessary files &lt;/li&gt;
&lt;li&gt;🖖🏻 Split out the large Prisma files into a layer&lt;/li&gt;
&lt;li&gt;♻️ Slim that layer down and consolidate the binaries to one shared location&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hopefully this example has helped and gives you the information you need to slim down your serverless functions that are using Prisma!&lt;/p&gt;

&lt;p&gt;If you have any other tips or tricks to accomplish this same goal, I'd love to hear them! Shoot me a message on &lt;a href="https://twitter.com/sabinthedev" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Thanks for reading, and have fun deploying some serverless functions using Prisma!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Dynamically Setting Meta Tags in Remix</title>
      <dc:creator>Sabin Adams</dc:creator>
      <pubDate>Tue, 01 Feb 2022 11:18:59 +0000</pubDate>
      <link>https://dev.to/sabinthedev/dynamically-setting-meta-tags-in-remix-4e96</link>
      <guid>https://dev.to/sabinthedev/dynamically-setting-meta-tags-in-remix-4e96</guid>
      <description>&lt;p&gt;Often when developing a website, the meta information about a webpage is determined by some of the content that gets loaded into the page.&lt;/p&gt;

&lt;p&gt;A product's page for headphones might have a description: &lt;code&gt;Sony Headphones, the number one product in its class!&lt;/code&gt;, a chat page might be titled: &lt;code&gt;Conversation with Leeland&lt;/code&gt;, or maybe your page has a specific image you'd like to show up on google's search results, etc...&lt;/p&gt;

&lt;p&gt;This is easy enough to set up with Meta tags in HTML, but how would you set the metadata on a page that uses a shared component that can handle many different pages? &lt;em&gt;(For example a re-usable product page component)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://remix.run/" rel="noopener noreferrer"&gt;Remix&lt;/a&gt; gives us a way to set this up super easily.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The repository for the final sample project can be found &lt;a href="https://github.com/sabinadams/remix-dynamic-meta-tags" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Starting A Remix Project
&lt;/h2&gt;

&lt;p&gt;We're going to create a Profile Page at a url like &lt;code&gt;/profile/&amp;lt;username&amp;gt;&lt;/code&gt; and updates the browser's title tab using metadata to &lt;code&gt;&amp;lt;username&amp;gt;'s Profile Page&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To get things started, we'll go ahead and create a new &lt;code&gt;Remix&lt;/code&gt; 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-remix@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;This tutorial assumes you have node installed and up-to-date&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you've gone through that, go ahead and pop open your new project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a Profile Route
&lt;/h2&gt;

&lt;p&gt;Remix's routing system works off of the files in your project. The existing &lt;code&gt;/app/routes/index.tsx&lt;/code&gt; will be your home page route at &lt;code&gt;/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We need to set up a route for a profile that can take any username and fetch the user's data accordingly. &lt;br&gt;
In &lt;code&gt;/app/routes&lt;/code&gt; create a file named &lt;code&gt;profile.$username.tsx&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Because of the naming convention used here, this will be a route at &lt;code&gt;/profile&lt;/code&gt; and has a sub-route with a wild-card param &lt;code&gt;$username&lt;/code&gt;. Combined we get our &lt;code&gt;/profile/$username&lt;/code&gt; route.&lt;/p&gt;

&lt;p&gt;Go ahead and paste the following code into that file:&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;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;LoaderFunction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useLoaderData&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;remix&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;username&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;first&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;last&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LoaderFunction&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="nx"&gt;params&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="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&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;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sabinthedev&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sabin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;last&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Adams&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;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;leeland&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Leeland&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;last&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Adams&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Not Found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;404&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="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Profile&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useLoaderData&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;flex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;justifyContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;alignItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#0c0f12&lt;/span&gt;&lt;span class="dl"&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;textAlign&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#f1f1f1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fontFamily&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;system-ui&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;last&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sets up just a basic page that will display the user's first and last name. Currently, we have manually added two users to our &lt;em&gt;"database"&lt;/em&gt;, but we can imagine this is connected to an actual data store!&lt;/p&gt;

&lt;p&gt;To test this out, start up your server by running &lt;code&gt;npm run dev&lt;/code&gt; and head over to &lt;a href="http://localhost:3000/profile/leeland" rel="noopener noreferrer"&gt;http://localhost:3000/profile/leeland&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foxfesube7gs5khtzrbyc.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%2Foxfesube7gs5khtzrbyc.png" alt="Screen Shot 2022-02-01 at 2.31.29 AM.png" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Beautiful! But notice up at the top that not-so-useful &lt;code&gt;New Remix App&lt;/code&gt; tab title? We'll want to change that to something more meaningful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Dynamic Metadata
&lt;/h2&gt;

&lt;p&gt;To set up our metadata, we can export a meta function from our route that Remix will use to automatically wire up our desired metadata.&lt;/p&gt;

&lt;p&gt;Start off by making sure to import &lt;code&gt;MetaFunction&lt;/code&gt; from the &lt;code&gt;remix&lt;/code&gt; library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import { 
&lt;/span&gt;    json,
    LoaderFunction,
    useLoaderData,
&lt;span class="gi"&gt;+    MetaFunction
&lt;/span&gt;} from 'remix'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then to get things started go ahead and add this exported &lt;code&gt;meta&lt;/code&gt; function:&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;const&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MetaFunction&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Profile Page&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;If you check back in your browser now, you'll see that Remix registered that function and automatically added the meta tag for you to set up the tab title!&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%2Fud409nqw91tvultzgcmw.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%2Fud409nqw91tvultzgcmw.png" alt="Screen Shot 2022-02-01 at 2.37.37 AM.png" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is cool, but what if we want a custom title depending on the user's profile we are visiting? The &lt;code&gt;MetaFunction&lt;/code&gt; in remix takes in an object with a bunch of useful data. Particularly the &lt;code&gt;data&lt;/code&gt; key, which contains the data from our &lt;code&gt;Loader&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;Let's tap into that to get access to the user we loaded up.&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;const&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MetaFunction&lt;/span&gt; &lt;span class="o"&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="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="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;formatName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charAt&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="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;title&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="nf"&gt;formatName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;'s Profile Page`&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now back over on our profile page we should see a much more descriptive message!&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%2F6puagc440weytjv0bxn5.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%2F6puagc440weytjv0bxn5.png" alt="Screen Shot 2022-02-01 at 2.40.25 AM.png" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using a process like this, we can dynamically set any kind of metadata we'd like for our page!&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: Setting up Twitter Metadata
&lt;/h2&gt;

&lt;p&gt;What if we want to share the link to this profile on twitter? &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I'll be using a tool called &lt;a href="https://ngrok.com/" rel="noopener noreferrer"&gt;Ngrok&lt;/a&gt; and a &lt;a href="https://cards-dev.twitter.com/validator" rel="noopener noreferrer"&gt;Twitter Card Validator&lt;/a&gt; to preview what our link preview would look like in a Twitter post.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Currently if we check out our link preview, we will see something like this 👎🏻:&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%2Fcuw1cal12ur1cm6xlhz4.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%2Fcuw1cal12ur1cm6xlhz4.png" alt="Screen Shot 2022-02-01 at 2.52.53 AM.png" width="800" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We don't have any metadata describing to Twitter how we want this data displayed! Let's update our &lt;code&gt;meta&lt;/code&gt; function to include some details:&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;const&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MetaFunction&lt;/span&gt; &lt;span class="o"&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="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="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;formatName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charAt&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="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;title&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="nf"&gt;formatName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;'s Profile Page`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;twitter:card&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;summary_large_image&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;twitter:creator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`@&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;twitter:site&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`@&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;twitter:title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;last&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;twitter:description&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;last&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'s profile page. Check it out @&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we should get something more like this:&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%2Fqb5w43ayn4pjgn77fk71.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%2Fqb5w43ayn4pjgn77fk71.png" alt="Screen Shot 2022-02-01 at 2.56.07 AM.png" width="800" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahh, much better! It displays some useful information about the link we are sharing! We could also add a preview image to this using the &lt;code&gt;twitter:image&lt;/code&gt; property.&lt;/p&gt;

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

&lt;p&gt;Remix has a great set of tools that take a lot of the grunt-work out of the mix for you. This is just one example of those!&lt;/p&gt;

&lt;p&gt;Hopefully this was helpful and will encourage you to set some of that important metadata to help provide users and search engines more context into what your site has to offer!&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;p.s.&lt;/em&gt; If you like this article, be sure to follow me on &lt;a href="https://twitter.com/sabinthedev" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; for updates when I post new articles!&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>react</category>
      <category>seo</category>
      <category>html</category>
    </item>
    <item>
      <title>When Serverless Meets Traditional Relational Databases</title>
      <dc:creator>Sabin Adams</dc:creator>
      <pubDate>Sat, 22 Jan 2022 04:02:52 +0000</pubDate>
      <link>https://dev.to/sabinthedev/when-serverless-meets-traditional-relational-databases-2d0n</link>
      <guid>https://dev.to/sabinthedev/when-serverless-meets-traditional-relational-databases-2d0n</guid>
      <description>&lt;p&gt;FaaS, or &lt;em&gt;Functions as a Service&lt;/em&gt;,  is a concept you have likely heard of recently as it has rapidly risen in popularity over the past few years. &lt;/p&gt;

&lt;p&gt;As more and more people are beginning to take a look at and try out Serverless models in their own projects, be it via AWS Lambda, Azure Functions, or any other provider available, we have began to see the amazing possibilities it brings to the table.&lt;/p&gt;

&lt;p&gt;We have also, however, found a few pitfalls. One being the realization that a Serverless model does not get along with a traditional Relational Database very well. &lt;/p&gt;

&lt;p&gt;In this article we're going to take a look at some specific problems relating to traditional databases that have been found, and potential solutions to those problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Serverless and Why Is It Popular?
&lt;/h2&gt;

&lt;p&gt;Before we dive into the potential issues with Serverless and traditional databases, let's get some insight into what Serverless is and some of the problems it &lt;em&gt;solves&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shift of Responsibility
&lt;/h3&gt;

&lt;p&gt;A Serverless model, despite its name, still must involve a server. The difference here is a shift in who has to manage that server. &lt;/p&gt;

&lt;p&gt;A major selling point of the Serverless architecture is that we as Developers and DevOps Engineers don't have to worry about maintaining the actual server our code is running on. The Serverless provider you use spins up and manages a container for your application to live on automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Potentially Cheaper
&lt;/h3&gt;

&lt;p&gt;Another upside of Serverless is the potential for it to, in the long-run, end up being cheaper than a traditional deployment model. &lt;/p&gt;

&lt;p&gt;Your code in this model is no longer running on a server that is charged by the hour or second. Instead, your code becomes available &lt;em&gt;as-needed&lt;/em&gt; on a container that is spun up by your provider and brought back down when the request is complete. &lt;/p&gt;

&lt;h3&gt;
  
  
  Scalability
&lt;/h3&gt;

&lt;p&gt;The last upside is definitely one of the major points of Serverless that makes it a game-changer, and a different class of deployment models.&lt;/p&gt;

&lt;p&gt;As mentioned above, your code becomes available &lt;em&gt;as-needed&lt;/em&gt;, and as your demand increases your infrastructure will automatically scale up the amount of available instances of your code to support that demand. Individual containers are kept alive for pre-configured amounts of time in case they can be re-used.&lt;/p&gt;

&lt;p&gt;This is &lt;em&gt;HUGE&lt;/em&gt; as it allows for a significant amount of traffic to be handled in a way that is efficient and cost-effective. &lt;/p&gt;

&lt;p&gt;This is also where we find one of the major issues with Serverless in relation to traditional Relational Databases such as MySQL or Postgres.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Problems Arise
&lt;/h2&gt;

&lt;p&gt;To better understand why the otherwise beneficial scaling capabilities of Serverless could be a &lt;em&gt;bad thing&lt;/em&gt; when paired with traditional databases, let's get an idea of how different deployment models connect to and interact with a database server.&lt;/p&gt;

&lt;p&gt;There are many different architectures and models, but we will look at three major ones that tend to be the most commonly seen &lt;em&gt;in the wild&lt;/em&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Monoliths&lt;/li&gt;
&lt;li&gt;Microservices &lt;em&gt;(Distributed Systems)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Serverless &lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Monoliths
&lt;/h3&gt;

&lt;p&gt;In a monolithic architecture, your entire application lives on one server. You might have multiple copies of your entire application on separate servers behind a load-balancer, but the idea is that all of your services, data access layers, user interface, and everything else relating to your application is shipped as one package.&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%2Fe7145h9tq73zstt6o4nv.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%2Fe7145h9tq73zstt6o4nv.png" alt="Monolith.png" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This type of architecture makes it relatively easy to manage connections to a database server. In your application, you can define a &lt;em&gt;connection pool&lt;/em&gt; limit and fairly simply and confidently know how many connections to your database to expect from your applications at any given time. &lt;/p&gt;

&lt;p&gt;No auto-scaling is going on, no changes are going on. A single set of connections are used for your entire application. &lt;/p&gt;

&lt;h3&gt;
  
  
  Microservices
&lt;/h3&gt;

&lt;p&gt;In a microservice architecture, things start to get a little bit more complicated. Rather than having one large layer where every piece of your application lives and one database to serve them all, you instead split the application up into logical &lt;em&gt;services&lt;/em&gt;. Each service typically has its own set of connections to its own 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%2Fcsfwmal8zyxuplkv8nmd.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%2Fcsfwmal8zyxuplkv8nmd.png" alt="Copy of Copy of Add a subheading.png" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Serverless
&lt;/h3&gt;

&lt;p&gt;Now we get to the topic in question, the serverless model. In a serverless model you can have many different serverless functions running in containers and autoscaling to fit your needs. &lt;/p&gt;

&lt;p&gt;These containers are not in existence until called upon via an API gateway, which may trigger a new connection pool to your database server.&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%2Fk1wr5u5bhqxq6543lv7l.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%2Fk1wr5u5bhqxq6543lv7l.png" alt="Copy of Copy of Add a subheading (1).png" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As your application receives more and more traffic, possibly during a peak time, new instances will pop into existence and run concurrently, each setting up a connection pool to the database server. Depending on the traffic this could reach up to 1,000 concurrent executions of your serverless function! &lt;em&gt;(or more)&lt;/em&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Can Be A Problem
&lt;/h2&gt;

&lt;p&gt;As you may have begun to already see, this can pose a real problem for a traditional database. &lt;/p&gt;

&lt;p&gt;Any database has a limited amount of connections it will support in order to reserve network and memory usage. In a traditional architecture you would likely have a &lt;em&gt;connection pool&lt;/em&gt; set up, which helps manage the re-use of connections and removal of idle or unused connections. &lt;/p&gt;

&lt;p&gt;This whole orchestration, however, depends on the concept of keeping a connection open and available. That doesn't really fit into the model of serverless functions that only exist when they are needed. Following this model, you will find that you are frequently and quickly exhausting your connection pool when traffic picks up.&lt;/p&gt;

&lt;p&gt;To put this into perspective let's think about some numbers. Let's say we've configured a connection pool in a serverless function with the following settings:&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="nl"&gt;"pool"&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;"min"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"idle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10000&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;This will tell our function instance that it should open up 15 connections and close out any connections that have been idle for 10 seconds.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Function Instances&lt;/th&gt;
&lt;th&gt;Connections&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;~75&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;~150&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;~300&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;~750&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now keeping this in mind, let's take a look at the connection limits for some of AWS's instance classes. The &lt;code&gt;connection_limit&lt;/code&gt; for MySQL-Flavored RDS is determined by the calculation: &lt;code&gt;{DBInstanceClassMemory/12582880}&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;If we were to choose the &lt;code&gt;db.m5.xlarge&lt;/code&gt; instance class which has 16gb of memory, that equates to 1,365 maximum connections. &lt;em&gt;(Keep in mind, we don't want to get close to the limit for performance reasons)&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For more info on AWS's connection limits, there is documentation &lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Limits.html#RDS_Limits.MaxConnections" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thinking back on those numbers in the table, imagine your product was having a huge spike in traffic due to an event and 200 concurrent requests hit your API gateway.&lt;/p&gt;

&lt;p&gt;At this point, your database would begin to bottleneck. Connections would begin to stack up and soon enough you'd hit the limit.&lt;/p&gt;

&lt;p&gt;This could end up being detrimental to the functionality of your code, your data, and even your product's reputation.&lt;/p&gt;

&lt;p&gt;While this problem is inevitable with this infrastructure, there are some potential solutions and workarounds that can alleviate, and depending on your needs &lt;em&gt;resolve&lt;/em&gt;, the symptoms of this issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Potential Code-Based Solutions
&lt;/h2&gt;

&lt;p&gt;The first set of potential solutions are changes and precautions you can implement in your serverless functions to help manage the connection pool a bit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lowering The Connection Pool Limit
&lt;/h3&gt;

&lt;p&gt;While keeping a balanced connection pool may be important in a traditional architecture to allow your application to handle concurrent requests to the database, that isn't very import &lt;em&gt;(actually it isn't important at all)&lt;/em&gt; in the context of a serverless function.&lt;/p&gt;

&lt;p&gt;A serverless function, by design, can only handle a single request at a time. It executes upon receiving a request and traffic to that instance is blocked until the execution resolves.&lt;/p&gt;

&lt;p&gt;What this means for us is that we don't really need to care about having multiple connections available to any single instance of our function. We can, and should, set the connection maximum in our pool to &lt;code&gt;1&lt;/code&gt;.&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="nl"&gt;"pool"&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;"min"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"idle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10000&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;This will significantly boost the amount of concurrent requests your function should be able to handle. As new instances spin up and queues build up on existing instances each new instance will have one open connection to your database server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adjusting The Idle Time
&lt;/h3&gt;

&lt;p&gt;While the previous potential solution will likely help out a ton, there are still scenarios where a limit can be hit. Heavy traffic for an extended period of time can cause a myriad of problems.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;More and more instances will be spun up, each opening a database connection&lt;/li&gt;
&lt;li&gt;As instances finish their processes, they will remain open for some time, possibly holding on to their connection&lt;/li&gt;
&lt;li&gt;When a connection is finally dropped from the pool, it does not necessarily mean that connection is available right away. The database engine still needs to process the closing of the connection.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because of the composition of these problems, connections will continue to rise and rise when receiving massive amounts of rapid requests until the database reaches its max and gets plugged up.&lt;/p&gt;

&lt;p&gt;In a &lt;strong&gt;short-lived function&lt;/strong&gt;, lowering the &lt;code&gt;idle&lt;/code&gt; time will allow the connections to be dropped from the pool in a shorter amount of time to free up connections for new instances that need a connection.&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="nl"&gt;"pool"&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;"min"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"idle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5000&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;&lt;strong&gt;WARNING&lt;/strong&gt;: While lowering the idle time can significantly help under extended periods of heavy traffic, lowering it too much can be a negative. In fact, it could significantly hurt your connection availability. &lt;/p&gt;

&lt;p&gt;This is because of the fact that a function's execution time may be slower than that idle time if it gets too low. In some edge cases, this may cause a database connection to be dropped from the pool before the function needs it mid-execution, and a new one will need to be created to finish off the request. &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%2F9wy8ztxdnfc0h3d2ly7u.gif" 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%2F9wy8ztxdnfc0h3d2ly7u.gif" alt="Copy of Copy of Add a subheading.gif" width="1000" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The database server likely hasn't closed the connection yet so you are essentially doubling your connections in that instance!&lt;/p&gt;

&lt;p&gt;In a &lt;strong&gt;long-living function&lt;/strong&gt;, it may be a good idea to do the opposite and increase the timeout limit to allow you to keep your connections open long enough to be effectively re-used across multiple executions in your instance's lifetime.&lt;/p&gt;

&lt;p&gt;Another &lt;strong&gt;warning&lt;/strong&gt; is worth mentioning here. Keeping the connections open for too long may result in an overwhelmed database because more connections may begin to stack up before the cleanup process drops idle connections. &lt;/p&gt;

&lt;p&gt;Finding a good balance is key.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;A Warning&lt;/em&gt;: Manually Closing Connections
&lt;/h3&gt;

&lt;p&gt;One potential workaround worth you might initially think of is manually opening and closing your connections within your actual function to ensure the connection closes at the end of execution. &lt;/p&gt;

&lt;p&gt;While this can theoretically lower the amount of concurrent connections, &lt;em&gt;this should not be the go-to solution&lt;/em&gt;. You'll likely want to try the other options first and make sure your connection pool settings are optimized. &lt;/p&gt;

&lt;p&gt;This is because manually opening a connection on each run creates a trade-off: you get easy connection handling at the cost of huge amounts of latency. &lt;/p&gt;

&lt;p&gt;Take this code for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&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;var&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createConnection&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="cm"&gt;/* your connection info */&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="cm"&gt;/* Your business logic */&lt;/span&gt;

  &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&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;While this would fix the problem of having a stale connection, the latency this would cause by having to open and close a connection on each execution is likely not worth it. There would also be no potential for re-use of connections.&lt;/p&gt;

&lt;p&gt;In general, it is recommended to initialize your connection outside of your handler because that connection will get &lt;code&gt;frozen&lt;/code&gt; with the instance during downtime and will be &lt;code&gt;thawed&lt;/code&gt; if another request in the queue executes the function before it is spun down.&lt;/p&gt;

&lt;h2&gt;
  
  
  Potential Infrastructure-Based Solutions
&lt;/h2&gt;

&lt;p&gt;Until now we have looked at changes to the actual code that could help lower the amount of concurrent connections. There are also measures we can take on the Infrastructure side to try to streamline some of this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Database Proxy
&lt;/h3&gt;

&lt;p&gt;One possible remedy to the connection pool issue is a Database Proxy such as &lt;a href="https://aws.amazon.com/rds/proxy/" rel="noopener noreferrer"&gt;AWS RDS Proxy&lt;/a&gt; or Prisma’s &lt;a href="https://www.prisma.io/docs/concepts/components/prisma-data-platform#prisma-data-proxy" rel="noopener noreferrer"&gt;Prisma Data Proxy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What a database proxy does is manage a connection pool for you outside of your serverless function's context. In doing so, it removes the latency caused by opening a connection for each new instance of your function.&lt;/p&gt;

&lt;p&gt;The configured proxy will queue up requests from your functions and throttle them in a way that, although causing some latency, prevents your database from being bombarded with an overwhelming amount of requests at once. &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%2Fc2u89z3kifrb39lklaf0.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%2Fc2u89z3kifrb39lklaf0.png" alt="Copy of Copy of Add a subheading (3).png" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Caching
&lt;/h3&gt;

&lt;p&gt;The last potential solution I will mention is Caching. Effective usage of tools such as AWS's &lt;a href="https://aws.amazon.com/elasticache/" rel="noopener noreferrer"&gt;ElastiCache&lt;/a&gt; may allow some requests to not have to hit the database at all.&lt;/p&gt;

&lt;p&gt;If a set of data is being retrieved from the database often, storing that in the cache will allow you to check for the existence of that data in the cache before running your query. If it exists, you can skip the query altogether!&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%2Frp4j9njcsn5yx4zb75ub.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%2Frp4j9njcsn5yx4zb75ub.png" alt="Copy of Copy of Add a subheading (4).png" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This would cause some, and potentially many, executions of your function that would have otherwise used up a connection to not use one at all! In the long run, under heavy load, this could be &lt;em&gt;HUGE&lt;/em&gt;.&lt;/p&gt;

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

&lt;p&gt;In this article we took a look at the potential problems that come about when connecting to a traditional database from a function, or set of functions, deployed using the serverless model. &lt;/p&gt;

&lt;p&gt;The solutions, whether used individually or in combination with each other, provide potential resolutions and definite alleviation of the symptoms of this bad relationship between the two technologies.&lt;/p&gt;

&lt;p&gt;The main takeaway here should be that a serverless architecture can definitely run effectively in conjunction with a traditional database as long as the proper configurations are put in place and precautions are taken, while taking into consideration how both pieces work individually.&lt;/p&gt;

&lt;p&gt;I hope this was helpful in understanding the problem presented and how we might go about avoiding them! Thanks so much for following along!&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>aws</category>
      <category>devops</category>
      <category>database</category>
    </item>
    <item>
      <title>End-To-End Type Safety: What, Why and How</title>
      <dc:creator>Sabin Adams</dc:creator>
      <pubDate>Fri, 21 Jan 2022 11:46:45 +0000</pubDate>
      <link>https://dev.to/sabinthedev/end-to-end-type-safety-what-why-and-how-179n</link>
      <guid>https://dev.to/sabinthedev/end-to-end-type-safety-what-why-and-how-179n</guid>
      <description>&lt;p&gt;A difficult challenge developers often face is creating and managing types across the entirety of their software stack in a way that allows for quick and easy error and change detection.&lt;/p&gt;

&lt;p&gt;Without a proper system in place, simple changes to your database's schema, your API layer's definition of an object, or even your web client's definition of that object could result in missing or malformed data somewhere in the chain of commands if each place wasn't updated properly.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;These kinds of problems are NO FUN to debug!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this article we're going to take a look at the cause of this issue, what a safe solution might look like, and then work through a simple full-stack application that puts a solution in place to solve the problem, making the DX (developer experience) a million times better!&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;The application we will be building will require the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; installed on your machine&lt;/li&gt;
&lt;li&gt;A basic understanding of JavaScript, TypeScript, and their ecosystem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will be using these technologies and tools to build our application:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nx.dev/" rel="noopener noreferrer"&gt;Nx&lt;/a&gt;: A build system that makes developing monorepos simple&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://reactjs.org/" rel="noopener noreferrer"&gt;React&lt;/a&gt;: Front-end library&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nestjs.com/" rel="noopener noreferrer"&gt;NestJS&lt;/a&gt;: Back-end Node.js Framework&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.prisma.io/" rel="noopener noreferrer"&gt;Prisma&lt;/a&gt;: ORM&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sqlite.org/index.html" rel="noopener noreferrer"&gt;SQLite&lt;/a&gt;: Database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't worry if you aren't familiar with the individual pieces. I'll explain as we go! &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can find the final application on &lt;a href="https://github.com/sabinadams/bookstore-type-safe" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  A Little History
&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%2Fhffzlh96amwjr2u0wo21.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%2Fhffzlh96amwjr2u0wo21.png" alt="Add a subheading (1).png" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's take a step back in time for a second. It's the early 2010's and Node.js is the cool new kid on the block. Every developer is eager to jump in and get their hands into some JavaScript that magically runs on a server! &lt;/p&gt;

&lt;p&gt;More and more people begin adopting and contributing to this new technology, and soon even large companies like Uber and LinkedIn start switching over to the shiny new toy!&lt;/p&gt;

&lt;p&gt;But then the applications start to get big... a little too big for their developers to remember things like &lt;em&gt;"What does my &lt;code&gt;createUser&lt;/code&gt; function actually expect as its parameters? And what does it return? What all is available from the database?"&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Organizing functionality becomes tedious as the concept of &lt;em&gt;Object Oriented programming&lt;/em&gt; doesn't exist in JavaScript and every time you hit deploy you have a little voice in the back of your head that wonders if you're sure everything was set up correctly...&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter, TypeScript
&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%2Fdx7x30bcl1uopwesjkgy.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%2Fdx7x30bcl1uopwesjkgy.png" alt="Untitled design (6).png" width="150" height="150"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This exact scenario is what lead to the development of what we know today as &lt;strong&gt;TypeScript&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;TypeScript brought with it a whole new world of tooling and type-safety that was previously impossible. You could organize your code into classes, provide interfaces for those classes, and set up types for various pieces of your code.&lt;/p&gt;

&lt;p&gt;Editor tooling also evolved in a way that made it super easy to develop efficiently and detect bugs before even compiling your code!&lt;/p&gt;

&lt;p&gt;This all sounds great and was a huge step in the right direction, but it shed light on another problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;While TypeScript made development way smoother, safer, and less error-prone, developers began to realize that there was some disconnect in their applications even with these types. &lt;/p&gt;

&lt;p&gt;Here's why:&lt;/p&gt;

&lt;p&gt;A &lt;em&gt;typical&lt;/em&gt; application nowadays is organized generally into three main layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Client Layer: The website you interact with&lt;/li&gt;
&lt;li&gt;API Layer: The layer that allows your client to indirectly interact with the database&lt;/li&gt;
&lt;li&gt;Database Layer: The layer where your data is kept&lt;/li&gt;
&lt;/ul&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%2Flt4pmrm8k6tkbiht49bx.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%2Flt4pmrm8k6tkbiht49bx.png" alt="Copy of Add a subheading.png" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's imagine we have an application following this structure and in our database we have a table called &lt;code&gt;users&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9331a852mpzcubnqg66o.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%2F9331a852mpzcubnqg66o.png" alt="Blank diagram - Page 1.png" width="340" height="220"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your front-end code &lt;em&gt;(the client layer)&lt;/em&gt; and your back-end code &lt;em&gt;(the api layer)&lt;/em&gt; each have their own typings that describe what a &lt;code&gt;User&lt;/code&gt; from your database schema &lt;em&gt;(the database layer)&lt;/em&gt; should look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;fullname&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;email&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;If everything was set up correctly, we can assume our imaginary application is working great! Your front-end might be able to fetch an array of users from the API. Both of those ends are aware of what a user is and how to handle it within its own layer and all is well.&lt;/p&gt;

&lt;p&gt;... But then things change. A nit-picky database admin decides the &lt;code&gt;fullname&lt;/code&gt; column should be split into two: &lt;code&gt;firstName&lt;/code&gt; and &lt;code&gt;lastName&lt;/code&gt;. A schema update is prepared and it's up to you as a developer to make absolutely sure the code and types are updated to reflect the new schema changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;type User = {
&lt;/span&gt;  id: number;
&lt;span class="gd"&gt;-  fullname: string;
&lt;/span&gt;&lt;span class="gi"&gt;+  firstName: string;
+  lastName: string;
&lt;/span&gt;  email: string;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens, however, if you forget to update the front-end code? Your editor and the TypeScript compiler won't throw any errors because, as far as they're concerned, in the front-end a &lt;code&gt;User&lt;/code&gt; still only has the &lt;code&gt;fullname&lt;/code&gt; column!&lt;/p&gt;

&lt;p&gt;We can imagine our layers currently look like this:&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%2F7k8sr9z0z7wtyw8c8zux.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%2F7k8sr9z0z7wtyw8c8zux.png" alt="Copy of Copy of Add a subheading (2).png" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each individual layer has its own definition of the object's shape, or a &lt;code&gt;type&lt;/code&gt;. But they are unaware of their counterpart's version of that type because they live in their own &lt;em&gt;box&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Requests made between the individual layers are working fine, but the shape of the data being passed around can't be known for sure as it crosses borders.&lt;/p&gt;

&lt;p&gt;This issue is what can, and tends to, arise as an application grows without implementing &lt;strong&gt;end-to-end type safety&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Fixing the type in your front-end code would suddenly reveal a bunch of squiggly red lines under every instance of &lt;code&gt;user.fullname&lt;/code&gt; that was accidentally left behind, but you would never have known unless the type was fixed or an error popped up after thorough testing &lt;em&gt;(or a deployment 😬&lt;/em&gt;)!&lt;/p&gt;

&lt;p&gt;In a less-severe scenario, we can imagine all of the types were properly updated throughout the stack and everything works fine. While the end-result is functional, the developer experience is not great at all because every change to a type or the database schema would require the developer to have to make the same change in a bunch of different locations.&lt;/p&gt;

&lt;h2&gt;
  
  
  End-To-End Type Safety
&lt;/h2&gt;

&lt;p&gt;With &lt;strong&gt;end-to-end type safety&lt;/strong&gt;, the goal is to have a single source of truth for your types across all layers of your application. Ideally this would occur in an automated fashion as your database schema changes. &lt;/p&gt;

&lt;p&gt;If this is achieved, the walls between each layer are essentially broken down and allow the data to flow to and from each layer in a much more simple way that makes sense to the developer who has to work with it.&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%2Farv04ev2cx7aj3bxd3p9.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%2Farv04ev2cx7aj3bxd3p9.png" alt="Copy of Copy of Add a subheading (3).png" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As data passes through each layer of the application, crossing borders via requests, we can be sure that in each &lt;em&gt;area&lt;/em&gt; of the stack we are expecting the same object.&lt;/p&gt;

&lt;p&gt;The benefits of this implementation include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Great DX&lt;/li&gt;
&lt;li&gt;Less testing, because TypeScript handles a lot of what we would normally test for&lt;/li&gt;
&lt;li&gt;Easier debugging because of the tooling and linting TypeScript comes with&lt;/li&gt;
&lt;li&gt;Ease-of-mind when making changes because we can allow ourselves to lean on the TypeScript Compiler&lt;/li&gt;
&lt;li&gt;A lot of your code ends up becoming self-documented across your stack&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are, of course, many different ways to achieve &lt;strong&gt;end-to-end type safety&lt;/strong&gt;, and those implementations can vary depending on your tech stack.&lt;/p&gt;




&lt;h2&gt;
  
  
  Putting It Into Practice
&lt;/h2&gt;

&lt;p&gt;As a developer myself, I understand that the best way for a developer to grasp a concept like this is to jump in and get your hands dirty, so let's take a look at one possible implementation of &lt;strong&gt;end-to-end type safety&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We'll set up a Monorepo with Nx that has a NestJS API and a React client. The API will consume a SQLite database.&lt;/p&gt;

&lt;p&gt;Our goal with the application will be to have fully automated type safety across all three layers. Making changes to our database should automatically update the type definitions in the API and Client layers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generate an Nx Workspace
&lt;/h3&gt;

&lt;p&gt;We'll start up by setting up the Nx Workspace. Navigate to a directory where you'd like to generate your project and run the following command:&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-nx-workspace bookstore 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should take you through a series of prompts asking you how to initialize your monorepo. Go ahead and pick &lt;code&gt;nest&lt;/code&gt; to start off and name the nest application &lt;code&gt;api&lt;/code&gt;.  I chose &lt;code&gt;no&lt;/code&gt; for the Nx Cloud option.&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%2F536lu1gh3ppzd225dgjj.gif" 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%2F536lu1gh3ppzd225dgjj.gif" alt="nxinit.gif" width="500" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you pop open the workspace that was generated, inside of the &lt;code&gt;/apps/api&lt;/code&gt; folder you should find a boilerplate NestJS application!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;bookstore
code &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="c"&gt;# if you're using VSCode&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2F3ixhpubzm4k18p61rjh0.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%2F3ixhpubzm4k18p61rjh0.png" alt="YKNdYzib8.png" width="500" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was conveniently set up for you by Nx and is ready to run!&lt;/p&gt;

&lt;p&gt;We're going to also need our React front-end, so lets download Nx's React project generator and generate a project in our monorepo.&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 &lt;span class="nt"&gt;-D&lt;/span&gt; @nrwl/react
nx g @nrwl/react:app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are the options I went with for the react app:&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%2Fa6irl7drtvcbmsb0hfpr.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%2Fa6irl7drtvcbmsb0hfpr.png" alt="82ET6rMwn.png" width="800" height="90"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: A &lt;code&gt;client-e2e&lt;/code&gt; folder was also generated. This is where any e2e tests for your react application will live. We'll ignore that folder in this tutorial.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And viola! We have a monorepo set up with a NestJS API and React application all ready to serve. &lt;/p&gt;

&lt;p&gt;If you'd like to serve the projects, you can use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nx serve client &lt;span class="c"&gt;# The react app&lt;/span&gt;
nx serve api    &lt;span class="c"&gt;# The nest api&lt;/span&gt;
nx run-many &lt;span class="nt"&gt;--parallel&lt;/span&gt; &lt;span class="nt"&gt;--target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;serve &lt;span class="nt"&gt;--projects&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;client,api &lt;span class="c"&gt;# Both&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;If you are unfamiliar with Nx and want to learn more about what it can do, check out the docs &lt;a href="https://nx.dev/getting-started/intro" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Initialize Prisma
&lt;/h3&gt;

&lt;p&gt;The next thing we'll want to set up is our database, and we're going to do that through Prisma. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.prisma.io/" rel="noopener noreferrer"&gt;Prisma&lt;/a&gt; has a rich set up features that go beyond just being a fantastic ORM. Through it we can define the shape of our database in a schema file, apply our schema to the actual database, and manage deployments and our migration history.&lt;/p&gt;

&lt;p&gt;Along with this, Prisma generates an ORM that is derived from the schema we define and is fully type safe. This allows us to already tick a few things off our list of type-related concerns!&lt;/p&gt;

&lt;p&gt;To use Prisma we'll first need to install it as a development dependency and initialize Prisma in 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 i &lt;span class="nt"&gt;-D&lt;/span&gt; prisma
npx prisma init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will generate a &lt;code&gt;/prisma&lt;/code&gt; folder at the root of your project with a file inside named &lt;code&gt;schema.prisma&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;schema.prisma&lt;/code&gt; is what we'll call our &lt;em&gt;source of truth&lt;/em&gt;. We'll see more about why later on, but for now let's move on to setting up an actual database for Prisma to interact with.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set Up SQLite
&lt;/h3&gt;

&lt;p&gt;To keep things nice and simple, we're going to use SQLite as our database.&lt;/p&gt;

&lt;p&gt;Add the following &lt;em&gt;blocks&lt;/em&gt; to your &lt;code&gt;schema.prisma&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "sqlite"
  url = "file:./dev.db"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells Prisma we are using SQLite and it should generate the db file into the same directory as the schema file.&lt;/p&gt;

&lt;p&gt;It also lets Prisma know we want to generate the &lt;em&gt;Prisma Client&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For more information about Prisma's &lt;code&gt;PSL&lt;/code&gt; &lt;em&gt;(Prisma Schema Language)&lt;/em&gt;, check out their &lt;a href="https://www.prisma.io/docs/concepts/components/prisma-schema" rel="noopener noreferrer"&gt;docs&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Add A Model
&lt;/h3&gt;

&lt;p&gt;Now that we've got a database set up and Prisma configured, let's model out our data. We'll keep things clean and just add a &lt;code&gt;Book&lt;/code&gt; model to the &lt;code&gt;schema.Prisma&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;model Book {
  id         Int    @id @default(autoincrement())
  title      String
  authorName String
  pages      Int
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Remember&lt;/em&gt;, this schema is the source of truth that not only describes the database schema, but will generate types for us to use in our code via the &lt;em&gt;Prisma Client&lt;/em&gt;!&lt;/p&gt;

&lt;p&gt;To apply the new model &lt;em&gt;(or table)&lt;/em&gt; to our SQLite database, we can run Prisma's migrate tool.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;prisma migrate dev &lt;span class="nt"&gt;--name&lt;/span&gt; init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command generates a migration file in &lt;code&gt;/prisma/migrations&lt;/code&gt;, applies that migration to our database, and finishes by generating our Prisma client.&lt;/p&gt;

&lt;p&gt;At this point, we have successfully set up control of our database schema, but those &lt;em&gt;walls&lt;/em&gt; are still up between each layer.&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%2Fnz9m1j3xf63f104v4pdj.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%2Fnz9m1j3xf63f104v4pdj.png" alt="Copy of Copy of Add a subheading (11).png" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Set Up An API Endpoint
&lt;/h3&gt;

&lt;p&gt;Okay, so we've got a database set up, our API and Client generated, and the Prisma client automatically modeled around our database. Let's put these to use.&lt;/p&gt;

&lt;p&gt;Inside of your &lt;code&gt;/apps/api/src&lt;/code&gt; folder, create a new file called &lt;code&gt;prisma.service.ts&lt;/code&gt;. This file will initialize and handle the &lt;code&gt;Prisma Client&lt;/code&gt; that was generated when we ran our migration.&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="c1"&gt;// prisma.service.ts&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;Injectable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnModuleInit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnModuleDestroy&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;@nestjs/common&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;PrismaClient&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;@prisma/client&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="nd"&gt;Injectable&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;class&lt;/span&gt; &lt;span class="nc"&gt;PrismaService&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;PrismaClient&lt;/span&gt;
  &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnModuleInit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnModuleDestroy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;onModuleInit&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;onModuleDestroy&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$disconnect&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;blockquote&gt;
&lt;p&gt;Here we are wrapping Prisma in a service so that it can be provided via NestJS's dependency injection system&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, over in your &lt;code&gt;app.module.ts&lt;/code&gt; we need to register the new &lt;code&gt;PrismaService&lt;/code&gt; as a provider for that module. &lt;/p&gt;

&lt;p&gt;First, go ahead and get rid of the existing &lt;code&gt;app.service.ts&lt;/code&gt; and &lt;code&gt;app.service.spec.ts&lt;/code&gt; files and remove that service's references in the app module file. We won't be needing those.&lt;/p&gt;

&lt;p&gt;Once those are cleaned out, replace them with references to the &lt;code&gt;PrismaService&lt;/code&gt; we created.&lt;/p&gt;

&lt;p&gt;Your &lt;code&gt;app.module.ts&lt;/code&gt; file should look like this:&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;Module&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;@nestjs/common&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;AppController&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;./app.controller&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;PrismaService&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;./prisma.service&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="na"&gt;controllers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;AppController&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;PrismaService&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;class&lt;/span&gt; &lt;span class="nc"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our service is registered in NestJS's DI &lt;em&gt;(Dependency Injection)&lt;/em&gt; system, so we should be able to reference the &lt;code&gt;PrismaService&lt;/code&gt; in our controller. Open up &lt;code&gt;app.controller.ts&lt;/code&gt; and update it to match the code below:&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;Controller&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Get&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;@nestjs/common&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;PrismaService&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;./prisma.service&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Controller&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;class&lt;/span&gt; &lt;span class="nc"&gt;AppController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PrismaService&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="nd"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nf"&gt;getData&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;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This controller is where we can set up our API routes. The &lt;code&gt;@Get&lt;/code&gt; decorator on &lt;code&gt;getData&lt;/code&gt; lets NestJS know that it can be accessed at the base route: &lt;code&gt;/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We want this endpoint to return all of the books in our database.&lt;/p&gt;

&lt;p&gt;In the return of &lt;code&gt;getData&lt;/code&gt;, if we begin to type out a query with Prisma, you will see we get some nice autocompleting features.&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%2Fuwudrbwk9rhewlhi3pjg.gif" 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%2Fuwudrbwk9rhewlhi3pjg.gif" alt="prismaclient.gif" width="516" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the query for all of the books is written, if you hover over the function definition you should notice the return type of that function is &lt;code&gt;PrismaPromise&amp;lt;Book[]&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F47vj92umqd2cjge4dlt3.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%2F47vj92umqd2cjge4dlt3.png" alt="Untitled design (4).png" width="500" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's super convenient! ...but where did the &lt;code&gt;Book&lt;/code&gt; type come from?? That was Prisma, our source of truth! &lt;/p&gt;

&lt;p&gt;We have now broken down the wall between our database schema's shape and our API types by having a single source defining each of those.&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%2Fmu4cw695rrvkeaodx5z2.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%2Fmu4cw695rrvkeaodx5z2.png" alt="Copy of Copy of Add a subheading (13).png" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our types in the API are automatically updated whenever the database changes and the prisma client gets re-generated! If you play around with the query a bit and narrow down the selected fields, you should see that the return type of the route function dynamically changes based on the fields you select.&lt;/p&gt;

&lt;p&gt;That's pretty slick, and checks off two layers of the three layers we need to worry about!&lt;/p&gt;

&lt;p&gt;Before moving on to that third layer though, let's add some data to the database via Prisma Studio so we can query it and make sure everything is working nicely.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This command should open up the studio to a list of models. If you click into the &lt;code&gt;Book&lt;/code&gt; model you should see a table view of our &lt;code&gt;Book&lt;/code&gt; table. Go ahead and add a few records to 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%2Fcop9k4dov4ov2tla1z6k.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%2Fcop9k4dov4ov2tla1z6k.png" alt="Screen Shot 2022-01-20 at 2.15.53 AM.png" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, serve up the &lt;code&gt;api&lt;/code&gt; via Nx and head over to &lt;a href="http://localhost:3333/api" rel="noopener noreferrer"&gt;&lt;code&gt;http://localhost:3333/api&lt;/code&gt;&lt;/a&gt; to check out your data.&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%2F6deg21m9y4hm4r2a9w5c.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%2F6deg21m9y4hm4r2a9w5c.png" alt="Screen Shot 2022-01-20 at 2.15.28 AM.png" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Awesome! We're getting data and ready to set up our front-end to safely consume that data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build The Front-End
&lt;/h3&gt;

&lt;p&gt;In order to interact with our api, we'll first need to enable &lt;code&gt;cors&lt;/code&gt; on the server. In &lt;code&gt;/apps/api/src/main.ts&lt;/code&gt;, we can use our NestJS app's &lt;code&gt;enableCors&lt;/code&gt; method to accomplish this.&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="c1"&gt;// main.ts&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;bootstrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&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;NestFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppModule&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enableCors&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;Now we should be okay to make requests from our client to our api. In &lt;code&gt;/app/client/src/app/app.tsx&lt;/code&gt;, we'll start off by fetching our list of books from the api.&lt;/p&gt;

&lt;p&gt;Add this effect and state variable to the top of the &lt;code&gt;App&lt;/code&gt; component function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;books&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setBooks&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;

&lt;span class="nf"&gt;useEffect&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="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3333/api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;setBooks&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;And to display those books, we'll replace the return of that function with:&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;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1px solid black&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2rem&lt;/span&gt;&lt;span class="dl"&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&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;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&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;book&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;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&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;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&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;If you serve up the API and Client and navigate to &lt;a href="http://localhost:4200/" rel="noopener noreferrer"&gt;&lt;code&gt;http://localhost:4200/&lt;/code&gt;&lt;/a&gt;, you should see our books beautifully displayed 🎨 &lt;em&gt;(or not so beautifully...)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs8vrwiti788p6zfe0tl2.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%2Fs8vrwiti788p6zfe0tl2.png" alt="Screen Shot 2022-01-20 at 3.06.22 AM.png" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Okay, before you TypeScript junkies start getting queazy seeing that &lt;code&gt;any&lt;/code&gt; type, let me explain. &lt;/p&gt;

&lt;p&gt;Currently, even though our Database knows what a &lt;code&gt;Book&lt;/code&gt; looks like and our API knows what it looks like, our front-end has no clue! The TypeScript compiler complains about that when we try to access properties on the mapped books.&lt;/p&gt;

&lt;p&gt;Fortunately, we're implementing an &lt;strong&gt;end-to-end type safe&lt;/strong&gt; system and Prisma gives us access to those types.&lt;/p&gt;

&lt;p&gt;At the top of this file, let's import the &lt;code&gt;Book&lt;/code&gt; type Prisma generated for us &lt;em&gt;(yes, the same book type we're using in the API layer!)&lt;/em&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;Book&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;@prisma/client&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;And we'll tell our state variable that it should hold an array of books.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;books&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setBooks&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Book&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you remove the &lt;code&gt;any&lt;/code&gt; type now from the mapped books, you should see that the editor stopped complaining! &lt;/p&gt;

&lt;p&gt;Also, if you go to modify a key being accessed on the &lt;code&gt;book&lt;/code&gt; variable, you should see you get a nice set of auto-complete options that show the fields available to a &lt;code&gt;Book&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbe21lw0cq1x5ghqgrrb2.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%2Fbe21lw0cq1x5ghqgrrb2.png" alt="Screen Shot 2022-01-20 at 1.51.45 PM.png" width="800" height="214"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's pretty awesome if you ask me! We now have a single source of truth for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Our database schema&lt;/li&gt;
&lt;li&gt;Our back-end types&lt;/li&gt;
&lt;li&gt;Our front-end types&lt;/li&gt;
&lt;/ul&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%2F9y32nq9fy08lefq3rsu9.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%2F9y32nq9fy08lefq3rsu9.png" alt="Copy of Copy of Add a subheading (5).png" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All the walls between layers have been broken down and our types and data flow nicely and automatically across our entire stack! &lt;/p&gt;

&lt;p&gt;Congratulations, you have implemented an &lt;strong&gt;end-to-end type safe&lt;/strong&gt; full-stack application! &lt;/p&gt;

&lt;h2&gt;
  
  
  Now We Break It
&lt;/h2&gt;

&lt;p&gt;Alright, enough celebrating! What fun is building a working project if you don't get to break it in the end?&lt;/p&gt;

&lt;p&gt;I've decided I don't really care how many pages a book has. That data is taking up precious (and expensive) space in my database server, so let's get rid of it. &lt;/p&gt;

&lt;p&gt;Pop open that &lt;code&gt;schema.prisma&lt;/code&gt; file we worked in before and remove the &lt;code&gt;pages&lt;/code&gt; field from the model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;model Book {
&lt;/span&gt;  id         Int    @id @default(autoincrement())
  title      String
  authorName String
&lt;span class="gd"&gt;-  pages      Int
&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since our schema definition changed, run a new migration to apply that to our database and generate the new Prisma Client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;prisma migrate dev &lt;span class="nt"&gt;--name&lt;/span&gt; removed-field
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will get some prompts letting you know you have non-null values in the field you are removing. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;That's pretty awesome Prisma thinks to warn you about that!&lt;/li&gt;
&lt;li&gt;Go ahead and allow it, we aren't concerned about data loss here 💣&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now that our schema is migrated and the new client generated, let's find out what we broke!&lt;/p&gt;

&lt;p&gt;Run both the API and the Client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nx run-many &lt;span class="nt"&gt;--parallel&lt;/span&gt; &lt;span class="nt"&gt;--target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;serve &lt;span class="nt"&gt;--projects&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;client,api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aha! We broke it! You should see an error in your console letting you know what the problem is. Also in your code you'll see those red squiggly lines I mentioned earlier.&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%2Fy7n9saotmx6xr0lir6pv.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%2Fy7n9saotmx6xr0lir6pv.png" alt="Screen Shot 2022-01-20 at 2.00.09 PM.png" width="800" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Think about what just happened. Our Database changed and because we have implemented &lt;strong&gt;end-to-end type safety&lt;/strong&gt; our front-end code was smart enough to tell us it needs to be updated because of that! All without us having to change anything in the code!&lt;/p&gt;

&lt;p&gt;Our back-end code would have done the same if we were actually accessing the &lt;code&gt;pages&lt;/code&gt; field directly anywhere. &lt;/p&gt;

&lt;p&gt;That is the power of TypeScript and end-to-end type safety. Because of this, we would have been able to easily catch any problems using the TypeScript compiler.&lt;/p&gt;

&lt;p&gt;Okay, I know the developer inside you is dying to fix the bug, so go ahead and remove that &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tag with the erroneous key.&lt;/p&gt;




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

&lt;p&gt;I hope after following through that example you're as excited as I am about how powerful TypeScript is when combined with tools like Prisma and Nx that allow you to generate and share types across the entire stack of your application.&lt;/p&gt;

&lt;p&gt;Of course, as mentioned near the beginning of this article, there is no &lt;em&gt;one-size-fits-all&lt;/em&gt; solution and this example was one specific case. Maybe you need partial types, are using GraphQL, or have some other requirement. Implementing a &lt;strong&gt;end-to-end type safe&lt;/strong&gt; experience is possible with the proper tools and configuration. &lt;/p&gt;

&lt;p&gt;Thanks so much for following along and I hope you found this useful&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>sql</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Adding Custom Font Classes to TailwindCSS</title>
      <dc:creator>Sabin Adams</dc:creator>
      <pubDate>Tue, 18 Jan 2022 05:29:12 +0000</pubDate>
      <link>https://dev.to/sabinthedev/adding-custom-font-classes-to-tailwindcss-o5l</link>
      <guid>https://dev.to/sabinthedev/adding-custom-font-classes-to-tailwindcss-o5l</guid>
      <description>&lt;p&gt;In this article we'll be taking a look at how to use Custom Fonts with TailwindCSS and make those available as Tailwind classes.&lt;/p&gt;

&lt;p&gt;TailwindCSS is one of the most useful CSS frameworks to date and has tons of amazing features that make building beautiful UIs quick and simple. &lt;/p&gt;

&lt;p&gt;A lot of its features come out-of-the-box and it's up to you to combine those building blocks into the UI you envision.&lt;/p&gt;

&lt;p&gt;While that alone is awesome, TailwindCSS takes things a step further and allows you to configure custom options by extending the themes available in case you have specific needs that it just doesn't support.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Goal
&lt;/h2&gt;

&lt;p&gt;To learn how to use custom fonts, we're going to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get a basic React app started &lt;/li&gt;
&lt;li&gt;Set up TailwindCSS &lt;/li&gt;
&lt;li&gt;Add our custom font and configure it in TailwindCSS's config&lt;/li&gt;
&lt;li&gt;Put the font to use!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'll approach this from the very basics all the way up, so no worries if you don't know React or Tailwind yet!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In order to follow along you'll want to make sure you have &lt;a href="https://nodejs.org" rel="noopener noreferrer"&gt;NodeJS&lt;/a&gt; installed.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Setting Up React using &lt;code&gt;create-react-app&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The first thing we'll want to do is get a project going in React. We're going to use a tool called &lt;a href="https://create-react-app.dev/" rel="noopener noreferrer"&gt;&lt;code&gt;create-react-app&lt;/code&gt;&lt;/a&gt; to scaffold the project out for us.&lt;/p&gt;

&lt;p&gt;Go ahead and use your terminal to navigate to a folder you'd like to generate your project in. Then run the following command to create a React application &lt;em&gt;(name it whatever you want)&lt;/em&gt;:&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-react-app react-tailwind-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should create a folder for your project, configure some things for you, and then give you instructions on how to manage your new 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%2Fv5oar4wcyfq1x5uzg76d.gif" 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%2Fv5oar4wcyfq1x5uzg76d.gif" alt="Jan-17-2022 18-23-04.gif" width="666" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For now, we'll just navigate into the project and start our React application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;react-tailwind-project &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will start up your dev server at &lt;a href="http://localhost:3000/" rel="noopener noreferrer"&gt;&lt;code&gt;http://localhost:3000&lt;/code&gt;&lt;/a&gt; and should look something like this.&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%2Fjvngfnl3nv0zg3brddo8.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%2Fjvngfnl3nv0zg3brddo8.png" alt="Screen Shot 2022-01-17 at 6.26.29 PM.png" width="800" height="596"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we've got our starter, let's move on to setting up Tailwind!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can stop your dev server by hitting &lt;code&gt;CTRL + C&lt;/code&gt; in your terminal window&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Setting Up Tailwind
&lt;/h2&gt;

&lt;p&gt;Before we start initializing and configuring Tailwind in our project, we'll need to install a few dependencies it will need.&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; &lt;span class="nt"&gt;-D&lt;/span&gt; tailwindcss postcss autoprefixer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We should have all the packages now we'll need to run TailwindCSS in our project. Next we'll initialize TailwindCSS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx tailwindcss init &lt;span class="nt"&gt;-p&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should generate a two files in your project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;postcss.config.js &lt;em&gt;(we won't touch this)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;tailwind.config.js&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Go ahead and pop open that &lt;code&gt;tailwind.config.js&lt;/code&gt; file. We need to tell Tailwind which files to care about in our project.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;content&lt;/code&gt; array, add the following glob pattern to match any of our files that will be using Tailwind's classes and tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;content&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;./src/**/*.{js,jsx,ts,tsx}&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;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;extend&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;plugins&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;Tailwind uses that to know which files to scan when generating the classes it needs during build time.&lt;/p&gt;

&lt;p&gt;The last thing we'll need to get Tailwind set up and usable in our project is to import Tailwind's directives into our root &lt;code&gt;index.css&lt;/code&gt; file at &lt;code&gt;/src/index.css&lt;/code&gt;. Add these imports to the top of that file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;utilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's make sure this is all working. In &lt;code&gt;/src/App.js&lt;/code&gt;, we'll add a Tailwind class to some of the text. How about we change the "Edit" instructions to a yellow color.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"text-yellow-500"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Edit &lt;span class="nt"&gt;&amp;lt;code&amp;gt;&lt;/span&gt;src/App.js&lt;span class="nt"&gt;&amp;lt;/code&amp;gt;&lt;/span&gt; and save to reload.
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything was set up properly you should see the text color change!&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%2F7grlxrano9v2276xg34c.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%2F7grlxrano9v2276xg34c.png" alt="Screen Shot 2022-01-17 at 8.48.38 PM.png" width="606" height="539"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Adding Our Custom Font and Class
&lt;/h2&gt;

&lt;p&gt;Now comes the part you've all been waiting for! &lt;/p&gt;

&lt;p&gt;In Tailwind, we have a set of classes that allow us to change our font family, such as &lt;code&gt;font-sans&lt;/code&gt;, &lt;code&gt;font-serif&lt;/code&gt;, and &lt;code&gt;font-mono&lt;/code&gt;. But what if we want to use a font that Tailwind doesn't have built in?&lt;/p&gt;

&lt;p&gt;Fortunately, TailwindCSS allows us to build our own custom extensions of the theme to provide custom font families along with classes for those families.&lt;/p&gt;

&lt;p&gt;The first thing we'll need to do is pick a font we like and import it into our &lt;code&gt;index.css&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;I'll be using Google Fonts' &lt;a href="https://fonts.google.com/specimen/Nova+Flat" rel="noopener noreferrer"&gt;&lt;code&gt;Nova Flat&lt;/code&gt;&lt;/a&gt;, but feel free to pick your own!&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;index.css&lt;/code&gt; after our Tailwind directive imports, import the font you like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;utilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="sx"&gt;url('https://fonts.googleapis.com/css?family=Nova+Flat')&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, the font is usable in our project, but I'm lazy and want Tailwind to build up a class for me automatically so I can use that font 🤣&lt;/p&gt;

&lt;p&gt;To configure this, head back over to &lt;code&gt;tailwind.config.js&lt;/code&gt;. Under the &lt;code&gt;theme&lt;/code&gt; key, we can use the &lt;code&gt;fontFamily&lt;/code&gt; key to add a custom font family to Tailwind.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;content&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;./src/**/*.{js,jsx,ts,tsx}&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;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;fontFamily&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;nova-flat&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;"Nova Flat"&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;extend&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;plugins&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;blockquote&gt;
&lt;p&gt;If your font name has spaces, be sure to surround it in Quotes. Tailwind doesn't like spaces&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you want to add multiple families to &lt;code&gt;nova-flat&lt;/code&gt;, you can add them either as a comma-separated list &lt;em&gt;(e.g. '"Nova Flat", arial, mono')&lt;/em&gt; or turn that value into an array *(e.g. ['"Nova Flat"', 'arial', 'mono'])&lt;/p&gt;

&lt;p&gt;After saving that, we will now have a new class available via Tailwind named &lt;code&gt;font-&amp;lt;our name&amp;gt;&lt;/code&gt;. In my case it will be &lt;code&gt;font-nova-flat&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's put it to use!&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;/src/App.js&lt;/code&gt;, we'll change the font of the "Learn React" label to our new font...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt;
  &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"App-link font-nova-flat"&lt;/span&gt;
  &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://reactjs.org"&lt;/span&gt;
  &lt;span class="na"&gt;target=&lt;/span&gt;&lt;span class="s"&gt;"_blank"&lt;/span&gt;
  &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"noopener noreferrer"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Learn React
&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything was set up properly, your cool new font should show up! &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%2Fkc60bbuo3ya8dyep3z4z.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%2Fkc60bbuo3ya8dyep3z4z.png" alt="Screen Shot 2022-01-17 at 9.15.44 PM.png" width="574" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pretty awesome how Tailwind created a usable class for us that we can now use anywhere!&lt;/p&gt;




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

&lt;p&gt;This example we looked at is just the beginning of the many options we have when configuring TailwindCSS to fit our picky, artsy needs 🎨&lt;/p&gt;

&lt;p&gt;I definitely encourage you to check out all the things &lt;a href="https://tailwindcss.com/docs/installation" rel="noopener noreferrer"&gt;TailwindCSS&lt;/a&gt; has to offer!&lt;/p&gt;

&lt;p&gt;Thanks so much for reading, hope you found this helpful!&lt;/p&gt;

&lt;p&gt;Til' next time, and Happy Coding!&lt;/p&gt;




&lt;h2&gt;
  
  
  P.S. 🧠🔎
&lt;/h2&gt;

&lt;p&gt;There is a shortcut to what we learned here.&lt;/p&gt;

&lt;p&gt;Without configuring the theme extension in &lt;code&gt;tailwind.config.js&lt;/code&gt;, we could have used what Tailwind calls an &lt;strong&gt;arbitrary value&lt;/strong&gt;, which essentially is a class that we can pass a value. &lt;/p&gt;

&lt;p&gt;In our case, our arbitrary value would have looked like &lt;code&gt;font-['Nova_Flat']&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>react</category>
      <category>tailwindcss</category>
      <category>javascript</category>
      <category>css</category>
    </item>
  </channel>
</rss>
