TubeSum ← Transcribe a video

Next js Tutorial for Beginners | Nextjs 13 (App Router) with TypeScript

1h 02m video Published Sep 11, 2023 Transcribed Aug 5, 2026 P Programming with Mosh
Beginner 25 min read For: Beginners to web development with basic React and TypeScript knowledge who want to learn Next.js 13.
AI Trust Score 75/100
⚠️ Average / Some Fluff

"Delivers a solid beginner tutorial with practical examples, though it's a promo for the full course."

AI Summary

This video is a comprehensive tutorial for beginners on Next.js 13, focusing on the App Router and TypeScript. It covers everything from setting up a development environment to advanced concepts like server and client components, data fetching, caching, and static and dynamic rendering. The tutorial is hands-on, building a full-stack issue tracking app with a modern tech stack including Tailwind, Prisma, and more.

[00:04]
Course Overview

The video is a complete Next.js course for beginners, aiming to take viewers from zero to hero. It promises to cover basics to advanced concepts, enabling viewers to build fast and scalable applications. The course builds a production-grade issue tracking app with features like dashboards, filtering, sorting, authentication, and CRUD operations.

[02:19]
Prerequisites

No prior Next.js knowledge is required, but basic familiarity with React and TypeScript is necessary. The instructor recommends his React tutorial for those lacking React knowledge.

[04:01]
What is Next.js?

Next.js is a powerful framework built on React for building fast and search engine friendly applications. It includes its own routing, compiler, CLI, and Node.js runtime, enabling full-stack development and server-side rendering.

[06:42]
Setting Up Development Environment

Requirements: Node version 16.8 or higher, VS Code recommended. Install extensions: ES7+ React/Redux/React-Native snippets, TypeScript Nightly, Tailwind CSS IntelliSense.

[08:16]
Creating a Next.js Project

Use 'npx create-next-app' with version 13.4. Answer prompts: project name, TypeScript yes, ESLint yes, Tailwind yes, source directory yes, app router yes, custom import alias no.

[10:28]
Project Structure

The app folder contains the routing system (app router). Files: layout.tsx (basic HTML structure), page.tsx (home page), global.css. The public folder holds static assets. Configuration files for ESLint, Next, PostCSS, Tailwind, TypeScript.

[13:21]
File-based Routing

Routes are defined by creating folders and page files. For example, /users requires a users folder with page.tsx. Nested routes like /users/new are created by nesting folders. Only page files are accessible; other files in the folder are not.

[16:15]
Navigation with Link Component

Using anchor tags causes full page reloads, re-downloading all resources. The Link component from next/link enables client-side navigation, only fetching the necessary content.

[18:33]
Server vs Client Components

Components can render on client (CSR) or server (SSR). SSR benefits: smaller bundles, less client resources, SEO-friendly, secure for sensitive data. Client components are needed for interactivity (event handlers, state, effects). Default to server components.

[21:57]
Server Components in Practice

All components in the app folder are server components by default. The HTML response contains rendered content, visible to search engines. To make a component client-side, add 'use client' directive at the top.

[26:42]
Promotion of Full Course

The tutorial is the first hour of a 5-hour full course. The full course covers everything needed to build full-stack applications with Next.js, includes certificate and 30-day money-back guarantee.

[27:26]
Data Fetching on Server

Fetching data in server components is simpler and avoids extra round trips. Use fetch() directly in async server components. No need for state/effect hooks. Data is rendered on server, improving performance and SEO.

[33:31]
Caching in Next.js

Next.js has a built-in data cache (file system based). Fetch results are cached by default. Options: cache: 'no-store' to disable caching, or next: { revalidate: 10 } to refresh every 10 seconds. Caching only works with fetch, not third-party libraries like Axios.

[35:56]
Static vs Dynamic Rendering

Static rendering (SSG) happens at build time, serving cached content. Dynamic rendering happens at request time. Next.js automatically statically renders pages with static data. Disabling caching forces dynamic rendering.

[40:24]
Global Styles

globals.css contains Tailwind directives and global styles. Use for styles that apply to all pages (body, headings). Avoid defining component-specific classes here to prevent dead styles.

[42:58]
CSS Modules

CSS modules are scoped to a component. File naming: component.module.css. Import as styles object, use styles.className. Class names are auto-generated to avoid clashes. Use camelCase for class names.

[47:25]
Tailwind CSS

Tailwind is a utility-first CSS framework. Classes like p-5, m-5, bg-sky-400, text-white, text-xl, hover:bg-sky-600. Benefits: styles co-located with markup, automatic purging of unused classes, high demand in industry.

[55:05]
DaisyUI

DaisyUI is a component library for Tailwind, like Bootstrap. Install as dev dependency, add to Tailwind plugins. Use classes like btn btn-primary. Themes can be applied via data-theme attribute on HTML element.

This tutorial provides a solid foundation in Next.js 13, covering essential concepts and practical implementation. By the end, viewers can build full-stack applications with confidence, leveraging server components, data fetching, and modern styling tools.

Mentioned in this Video

Tutorial Checklist

1 06:42 Install Node.js version 16.8 or higher from nodejs.org.
2 06:55 Install VS Code from code.visualstudio.com.
3 07:09 Install VS Code extensions: ES7+ React/Redux/React-Native snippets, TypeScript Nightly, Tailwind CSS IntelliSense.
4 08:16 Run 'npx [email protected]' in terminal.
5 08:42 Answer prompts: project name, TypeScript yes, ESLint yes, Tailwind yes, source directory yes, app router yes, custom import alias no.
6 09:50 Run 'npm run dev' to start development server.
7 13:21 Create routes by adding folders and page.tsx files in the app folder.
8 16:15 Use Link component from next/link for client-side navigation.
9 21:57 Use 'use client' directive to make a component a client component.
10 27:26 Fetch data in server components using fetch() and async/await.
11 33:31 Configure caching with fetch options: cache: 'no-store' or next: { revalidate: 10 }.
12 42:58 Create CSS modules with .module.css extension and import as styles object.
13 47:25 Apply Tailwind utility classes directly in JSX.
14 55:05 Install DaisyUI: npm i daisyui, add to tailwind.config.js plugins, set data-theme on HTML.

Study Flashcards (13)

What is Next.js?

easy Click to reveal answer

Next.js is a framework built on React for building fast and search engine friendly applications. It includes routing, compiler, CLI, and Node.js runtime.

04:01

What are the prerequisites for this Next.js course?

easy Click to reveal answer

Basic familiarity with React and TypeScript is required. No prior Next.js knowledge is needed.

02:19

How do you create a new Next.js project?

easy Click to reveal answer

Run 'npx create-next-app' and answer the prompts. Use version 13.4 for this course.

08:16

What is the difference between the app router and pages router?

medium Click to reveal answer

The app router is the new routing system in Next.js 13, based on file system conventions. The pages router is the legacy router. The app router does not expose non-page files publicly.

09:24

What are the benefits of server-side rendering (SSR)?

medium Click to reveal answer

SSR reduces bundle size, requires fewer client resources, improves SEO, and keeps sensitive data like API keys on the server.

18:33

How do you make a component a client component in Next.js?

easy Click to reveal answer

Add the 'use client' directive at the top of the file.

24:38

What is the default caching behavior of fetch in Next.js?

medium Click to reveal answer

Fetch results are cached by default in the data cache (file system based).

33:31

How can you disable caching for a fetch request?

medium Click to reveal answer

Pass { cache: 'no-store' } as the second argument to fetch.

34:41

What is static rendering?

medium Click to reveal answer

Static rendering (SSG) renders pages at build time and serves cached content. It is used for pages with static data.

35:56

What is the purpose of CSS modules?

medium Click to reveal answer

CSS modules scope styles to a specific component, preventing clashes. Class names are auto-generated to be unique.

42:58

What is Tailwind CSS?

easy Click to reveal answer

Tailwind is a utility-first CSS framework that provides small utility classes to style components directly in markup.

47:25

What is DaisyUI?

easy Click to reveal answer

DaisyUI is a component library for Tailwind, providing pre-styled components like buttons and tables.

55:05

How do you apply a DaisyUI theme?

medium Click to reveal answer

Add the theme to the DaisyUI config in tailwind.config.js and set the data-theme attribute on the HTML element.

58:36

💡 Key Takeaways

💡

Next.js as a Framework

Clearly distinguishes Next.js from React, explaining the framework concept and its built-in features.

04:01
📊

Benefits of SSR

Lists concrete advantages of server-side rendering, crucial for understanding architecture decisions.

18:33
📊

Server Components by Default

Highlights the default behavior of the app router, a key difference from the pages router.

21:57
🔧

Built-in Data Cache

Explains the caching mechanism and its control options, essential for performance optimization.

33:31
🔧

Static vs Dynamic Rendering

Demonstrates the difference with a timestamp example, making the concept tangible.

35:56
💡

Tailwind's Selling Point

Articulates the benefit of automatic purging of unused classes, a strong argument for using Tailwind.

47:25

[00:04] everything you need to know about Next.js from the basics to more advanced concepts. So, by the end of the course, you'll be able to confidently build fast and scalable applications with Next.js. If you have been searching for a

[00:18] comprehensive, easy-to-follow, well-organized, and practical course that takes you from zero to hero, this is the right Next.js course for you. You Next.js to get started. Everything you need is right here, so you won't need to

[00:31] tutorials. But, here's the catch. Unlike other courses, we're not just building a dummy app. We'll be building a beautiful, full-stack, production-grade app for tracking issues. An app complete with

[00:45] all the features and UI patterns you would expect in modern applications. On the home page, we have this beautiful dashboard that displays the latest issues and their status. And all of this data is stored in a MySQL database. We

[00:58] can go to the issues page, we can filter issues, sort them, and go to different pages. We can assign an issue to a user. So, here we have full authentication and

[01:14] authorization. We can edit an issue. editor. We can also delete an issue, and here we We can also delete an issue, and here we get this confirmation dialog box.

[01:27] a cutting-edge stack. Next.js 13, Tailwind, Radix UI, Prisma, React Query, React Hook Forms, Zod, and more. And don't worry if some of these

[01:39] tools are alien to you. Just like my other courses, I will walk you through each one, explaining the what, the why, and the how. So, if you follow along, you will master Next.js and will be able to build full-stack applications with

[01:52] confidence. I'm Mosh Hamedani, a software engineer with over 20 years of experience, and I've taught millions how to code and become professional software engineers through my YouTube channel and online school codewithmosh.com.

[02:05] If you're new here, make sure to subscribe as I upload new videos all the time. Now, let's jump in and get started.

[02:19] to know to take this course? Well, to take this course, you don't need any prior knowledge of Next.js because I'm going to teach you everything from the ground up. However, you need to have basic familiarity with React and

[02:31] TypeScript because Next.js is a React framework, and if you don't know React, this course. Now, if you want to learn React, I have a great tutorial on my YouTube channel. The link is below this video. I also

[02:43] have a comprehensive course that goes way beyond that. It teaches you everything you need to know to build modern applications with React 18 and TypeScript. The full course is 14 hours divided into two parts, so you can

[02:57] easily finish each part. In this course, you will learn how to build this beautiful application for discovering video games. Here we have all the common UI patterns you see in real applications like filtering, sorting, infinite

[03:10] Again, in case you're interested, the link is below this video. this section, we'll be talking about the fundamentals of Next.js.

[03:24] First, I'll explain what exactly Next.js is and why is it so popular. Shortly after, we'll set up our development environment and create our first Next.js project. From there, we'll talk about some foundational concepts such as

[03:38] client and server components, data fetching, caching, as well as static and dynamic rendering. This section is a great introduction to Next.js, so let's great introduction to Next.js, so let's jump in and get started.

[04:01] Next.js thing everyone is talking about and why should I bother with it? Well, Next.js is an incredibly powerful framework for building fast and search engine friendly applications. It's built on top of React, so everything you have

[04:16] learned about React is still relevant. But, Next.js takes web development to the next level. While React is just a library for creating interactive user interfaces, Next.js is a comprehensive framework.

[04:28] Think of a framework as a collection of libraries, tools, and conventions that streamline application development. For instance, Next.js includes its own routing library, so we don't need to use a separate library like React Router.

[04:44] In terms of tooling, it comes with a compiler for transforming and minifying our JavaScript code, a command-line interface for building and starting our interface for building and starting our application, and a Node.js runtime.

[04:57] Now, you might wonder, what exactly is a Node.js runtime? Well, there are two main ways we can execute JavaScript code. Within a web browser on the client side, or within a Node.js runtime on the server. So, a Node.js runtime is just a

[05:11] fancy term for a program that can execute JavaScript code. So, Next.js comes with a Node.js runtime, and this allows us to do some really cool things. The first thing is that we can do full-stack development. So, we can write

[05:26] both the front-end and back-end code within the same Next.js project. The back-end code gets executed within the Node.js runtime, and the front-end code gets bundled and sent to the client for execution within a web browser.

[05:41] In contrast, when building applications with React, we have to maintain a separate back-end project in a potentially different programming This Node.js runtime also allows us to render our components on the server and

[05:55] send their content to the client. This technique is called server-side rendering or SSR, and can make our applications faster and more search We'll talk about it in detail later in the course.

[06:08] But, wait, there's more. With Next.js, we can pre-render certain pages and components that have static data when we build our application. We just render them once and serve them whenever they're needed.

[06:21] This technique is called static site generation and can make our applications super fast. So, in a nutshell, Next.js is a framework for building super fast and search engine friendly applications.

[06:42] up our development environment. To run Next.js, you should have Node version 16.8 or higher. So, head over to nodejs.org and download the latest version. Now, in this course, I will be using VS

[06:55] courses. You're welcome to use your preferred editor, but I encourage you to use VS Code because along the way, I'll be sharing a lot of tips and techniques for writing code fast. So, you can get VS Code from

[07:09] code.visualstudio.com. Now, here in VS Code window, let's talk this course. So, in this panel, search for ES7. All right. Look at this extension.

[07:24] All right. Look at this extension. ES7 plus React, Redux, and React Native. This extension gives us a bunch of code snippets, so we can quickly and easily generate React components. The next extension is TypeScript.

[07:41] JavaScript and TypeScript Nightly. And the last one is Tailwind CSS IntelliSense. Tailwind before, don't worry. It's super easy, and I'm going to hold your hands

[07:56] easy, and I'm going to hold your hands through the entire course. project, open up a terminal window and run NPX create-next-app

[08:16] this course, I'm going to use version 13.4. So, I strongly recommend you to use the same version, so you don't have any difficulties going through the course. Let's go ahead.

[08:28] Now, it's asking if you want to install this package, create-next-app version 13.4.13. Let's proceed. bunch of questions about our new project. The first question is the name

[08:42] of our project. I'm going to use next-app. The next question is if you want to use TypeScript in this project. The default answer is yes, so let's press enter to accept it. The next question is about

[08:56] using ESLint, which is a common code analysis tool that we can use to find common errors like syntax errors, formatting issues, and so on. Again, which is yes. The next question is about using

[09:09] Tailwind CSS. One more time, we're going to accept yes. The next question is about using the source directory. A lot of Next.js projects don't use the source here. The next question is about using the new

[09:24] app router. I'm going to talk about this later in this section, but very briefly, in Next.js 13, we have two types of routers. We have the new app router and the legacy pages router. In this course, we're going to use the new app router.

[09:38] So, let's select yes. The last question is about customizing the default import alias. We're going to select no. All right. Now, it's going to install all these dependencies, so you see we

[09:50] have React, React DOM, Next, TypeScript, and so on. folder and run npm run dev.

[10:09] port 3000. So, let's control and click on this link. And this confirms that our first Next.js project is up and running.

[10:28] folders in this project. So, at the top we have the app folder or this is also called the app router. This is the container for our routing system. So, in Next.js our router is based on the file system. So, unlike React router, we

[10:43] don't have to configure our routes and map them to our components. We can simply create files and folders to represent our routes. We'll talk about them in the next lesson. So, in the app folder we have a favicon. We have our

[10:56] global CSS file. A layout file, which is a basic React component that returns an HTML and body element. This pages. Now, inside the body element we have

[11:09] children, which is replaced by a page dynamically at runtime depending on where the user is in our application. Now, in this folder we also have a page file, page.tsx. This represent our home page. Now, for

[11:22] This represent our home page. Now, for this demo, let's delete everything here and replace it So, we're going to return a main element.

[11:34] Inside main we want to add an h1 and say hello world. Now, back to the browser. Here we have fast refresh. So, anytime we make any changes to our TypeScript or CSS files, the changes are reflected

[11:48] immediately. Now, here we have a bit of styling issue because there is a gradient, a linear gradient applied to the body element. So, let's go to our global CSS file. Down the bottom,

[12:00] look at the styles applied to the body element. The background attribute is set to a linear gradient and that is why we have So, simply remove the background

[12:13] attribute and the issue goes away. Beautiful. Now, I want to apply a padding here so the content is not so close to the edges of the screen. So, let's set padding to

[12:25] 1 rem. Okay? That is better. So, we're done with the app folder. Now, in this project, after the app folder, we have the public

[12:37] folder. This is where we can put our public assets like images. In this case, we have two SVG files here, which are vector graphics. One is Next, the other is Vercel, which is the company that has created Next.js.

[12:51] configuration files. We have one for ESLint, another for Next, PostCSS, Tailwind, and TypeScript. touch these configuration files, but if the situation changes in the future,

[13:07] the situation changes in the future, we'll come back and revisit them. All right, I told you that routing in Next.js is based on the file system. So,

[13:21] here in the app folder, we can create a new folder called users. Now, to make this publicly accessible, here we should add a page file in this folder. So, page.

[13:34] in this folder. So, page. Now, the extension can be JS, JSX, or TSX for TypeScript. In this course, we use TypeScript, so I'm going to go with Now, make sure to name this file correctly, page in lower case, because

[13:48] this is one of the conventions that Next.js looks for. So, the routing system in Next.js is based on convention, not configuration. So, here we have a page file. Now, in this page file, we should export

[14:02] a React component that will be rendered when the user is at this location, /users. Earlier we installed a very useful extension in VS Code. With that extension, we can generate a React

[14:15] extension, we can generate a React component using this shortcut, r a f c e. That is short for React arrow function component with an export. Now, function component with an export. Now, the way I remember this is rafce. Okay?

[14:28] So, let's generate it. Beautiful. Now, here we have multiple cursors activated, so we can rename this component to something more meaningful like users The name we assign here doesn't really matter in terms of routing. This is just

[14:42] Okay? Now, let's press escape to deactivate multiple cursors. So, back to the browser. Now, let's go to /users and here's our new users page.

[14:56] Now, one thing you need to know about this routing system is that if you add any other files in this folder, let's say test.css, this file is not going to be accessible. So, if you go to /users/test.css,

[15:16] this is how the new app router is different from the old pages router. In the pages router, if you put any files in this folders, those files would be publicly accessible, but this is not the case with the new router. Okay?

[15:30] So, let's delete this file. Now, here we can also create nested routes. So, inside the users folder, we can add a new folder called new. And in this folder we add a new page file. So, page.tsx.

[15:47] One more time, let's create a React component and we're going to call this new user page. page. Good. So, now we can go to users/new

[16:01] and see this new page. Beautiful. Now, let's talk about navigation. So, we're going to go back to our home page. So, here we press command and P on Mac or control and P on Windows to look up files by their name.

[16:15] If we type page, we can see all our page files. So, the first item is our home page. This is the one we're looking for. Now, on this page, let's add So, here we add an anchor. We set href to /users

[16:32] and give it a label like users. Now, there is a problem with this way of you. So, let's go back to our home page.

[16:44] All right. Now, I'm going to open up dev tools. look at all the requests sent to the server. The first one is our HTML document. The second one is a font. The third one is a

[16:57] CSS file. And after that, we have a bunch of JavaScript files. Now, I'm going to clear this list. Look what happens when we click on the users link. Let's go back to the network tab. Look,

[17:12] all these resources are re-downloaded. This is not the optimal way to implement navigation because in a real application, we probably have a navigation bar on the top, a side panel on the left. So, as the user navigates

[17:26] from one page to another, we don't want to reload all these repetitive parts. We right? This is where we use the link component in Next.js. So, back to our code. We're going to replace this anchor

[17:41] with the link component that is defined in next/link library. Okay? Let's replace it here as well. Now, back to our home page. Once again, I'm going to bring up the

[17:55] network tab and clear this list. Now, look what happens when we click on the users link. Look, we only have two requests and these requests are for downloading the

[18:07] content of the users page. So, we're not re-downloading a font, a CSS file, and a This is what we call client-side navigation. Now, there's more to section about this topic later in the course. This was just a basic overview.

[18:33] environments where we can render our components and generate HTML markup. Either on the client within a web browser or on the server within a Node.js runtime. Rendering components on the client is similar to how React

[18:48] applications work. We refer to this technique as client-side rendering or CSR. On the flip side, we have server-side rendering or SSR, where components are rendered on the server. So, what are the

[19:01] with client-side rendering, we have to bundle all our components and send them to the client for rendering. This means as our application grows, so does our bundle size because it must contain all of our components. Now, the larger the

[19:16] bundle, the more memory we need on the client to load all these components. So, The other problem is that search engine bots, which are machines that browse and index our websites, can't view our

[19:29] content because they can't execute JavaScript code, so they cannot render our components like a web browser. And last but not least, any sensitive data we have in our components or their dependencies like API keys will be

[19:43] exposed to the client. Now, if we render our components on the server, we can get rid of all these problems. We only send the essential components to the client and prevent our bundle from becoming unnecessarily large. Also, because the

[19:57] server handles most of the rendering, we need less resources on the client. Plus, because rendering is done on the server and we send the actual content to the client, search engine bots can view and index our pages. And finally, we can

[20:12] keep sensitive data like API keys on the server. So, these are all the great benefits of server-side rendering. However, with server-side rendering, we lose interactivity.

[20:24] components that are rendered on the server, cannot listen to browser events server, cannot listen to browser events like click, change, submit, and so on. They cannot access browser APIs like the local storage. They cannot maintain

[20:37] state or use effects. These functionalities are only available in client components. So, in real-world applications, we often use a mixture of server and client components. We should default to server

[20:51] components and use client components only when we absolutely need them. Here is an example. Let's imagine we want to build a page to show a list of products. To build this page, we probably need several components like

[21:04] navbar, sidebar, product list, product card, pagination, and footer. Now, in standard React applications, we have to package all these components and send them to the client for rendering. But in Next.js, we can keep all these

[21:18] components on the server and minimize the bundle size. There is just one To add a product to a shopping cart, we need to handle the click event of a button. Typically, we implement this functionality in the product card

[21:31] component. So, we have to make it a client component. That's one option, but We can keep this component on the server and do most of the rendering there, and and do most of the rendering there, and instead extract a small component that

[21:45] only contains the add button. With this change, we only ship a tiny component to the client and keep everything else on the server. Let's see this in action. Back to our project. In Next.js, all

[21:57] components inside the app folder are server components by default. So, that means all the pages we have created so far, these are server components and are rendered on the server. Let me show you. So, back to the browser. Let's bring up

[22:13] the network tab and look at the first request. This is the HTML document that we get from the back end. So, look. We have our content here. We have our hello world and the users link. This is exactly what

[22:26] search engine bots see when they browse our website. In contrast, if we used client-side rendering, which is how standard React applications work, search content. They would see a blank page

[22:40] because all components, all the content is rendered on the client. Okay? back to our project. All components inside the app folder are server components by default. Now, if you have worked with Next.js before, I should

[22:54] mention that the pages router doesn't support server components. So, going forward, you should stop using it and switch to the new app router. Okay? a new folder here called components.

[23:09] Earlier, I told you that this folder is not publicly accessible unless we add a page file inside it. So, that means we can colocate our project files like our components and other building blocks with our pages. We can put them next to

[23:23] each other, and this is perfectly fine. So, here in the components folder, let's add a new file called product card.tsx. Here, we create a basic React component. Now, earlier, I told you that server

[23:38] components cannot have interactivity. So, they cannot handle browser events like click, change, and so on. So, that means if we add a button here and handle the click event

[23:53] we get a runtime error. Let me show you. So, let's pass a basic arrow function So, let's pass a basic arrow function and log something on the console. And we set the label to add to cart. Now, let's add this component to our

[24:08] home page. So, we go to our first page file So, we go to our first page file and add our new product card component. Now, back to the browser. Look, we got an error saying event handlers cannot be

[24:22] passed to client component props. If you need interactivity, consider component. Like here, we have two options. One option is to make this entire component a client component. So, we go to the top

[24:38] and use the client directive. So, in quotes, we type use client. That's all we have to do. With this, we tell the Next.js compiler to include this file or this component in our JavaScript bundle.

[24:52] And that means if this component is dependent on other components, those components will automatically become client components and will be included in our JavaScript bundle. So, we don't have to repeat this directive on every

[25:05] client component. Okay? So, here's one option. Now, if you go the error is gone. But there is a better way. To make our applications faster and more search engine friendly, we want to

[25:17] render our components on the server as much as possible and use client components only when absolutely necessary. So, here our product card could have some complex markup. We want to render all that

[25:30] markup on the server and move this button to the client. So, I'm going to extract this button and put it inside a separate component. here in the components folder, let's add a new file

[25:44] add to cart. Again, we create a basic React component. On the top we use the client directive and then we move this button to our new component.

[26:02] Okay? So, now we have a client component and we're going to use this in our product card. Okay? With this, we can remove use client from this file. So, this component will be

[26:16] rendered on the server. And that means where we have a client component, in this case, where we have this button, there's going to be a hole or a slot where React will later inject our client component. Okay?

[26:29] Now, if you go back to the home page, again, we don't see any errors. So, this is how we can create and use client and server components. Hey guys, I hope you've been having fun watching this tutorial. I just wanted to

[26:42] mention that this tutorial is the first hour of my complete Next.js course. So, after you finish this, if you want to learn more, I highly recommend you to enroll in the full course because it's much faster and easier than jumping

[26:55] between a bunch of random, disconnected tutorials here on YouTube. The full course is 5 hours long and teaches you everything you need to build full-stack everything you need to build full-stack applications with Next.js. It also comes

[27:07] with a certificate of completion and a 30-day money-back guarantee. So, if you get all your money back, no questions asked. In case you're interested, the link is below this video.

[27:26] data. We can fetch it on the client or on the server. To fetch data on the client, we typically use the state hook to declare a state variable and the effect hook to call the back end, get the data, and put it into our state

[27:39] variable. Now, in my React course, I talked about React Query as a better alternative to manually using the state and effect hooks. But regardless of how we fetch data, fetching data on the client in client components has all the

[27:53] problems we talked about in the previous lesson. So, over time, our bundles would get larger because we have to ship more and more components to the client. Also, this approach is resource intensive because all the rendering is done on the

[28:06] client. Plus, our content or our data is not visible to search engines, and this approach is less secure because our API keys or any kind of sensitive data will end up on the client. But there is one extra problem. The problem is that with

[28:21] this approach, there's always an extra round trip to the back end. So, when a React application loads, first the browser downloads the HTML template as well as the CSS and JavaScript files from the back end. Then, it will send an

[28:35] extra request to fetch data from the back end. So, there's always an extra round trip to the back end. Now, we can fetch data in our server components and get rid of all these problems. Let me show you.

[28:49] In this lesson, we're going to use JSON Placeholder to get some dummy data into our application. In case you are not familiar with JSON Placeholder, it's a fake API for getting some dummy data.

[29:01] So, head over to jsonplaceholder.typicode.com. endpoints for getting dummy data like a list of posts, comments, albums, photos,

[29:13] In this lesson, we're going to get a list of users into our application. So, look. Each user object has a bunch of properties like ID, name, username, So, back to our project let's go

[29:28] to the app folder and then open the users folder and then go to this page. Now, this is a server component, and in server components, we can use the fetch with. This function is defined in browsers,

[29:43] and with this, we can send HTTP requests to the back end. So, here we pass the URL of our endpoint, which we grab from here. and paste it. Now, this returns a promise, so we have

[29:58] to await it to get the response. Now, because we're using await here, we have to make this component async. approach. With this approach, we don't have to use a state variable, we don't

[30:11] have to use the effect hook with zero dependencies. There's no ceremony. We just call fetch to get the data. And all of this happens on the server. You'll see that in a minute. So, we get the response. Then we call

[30:25] response.json. This also returns a promise, so we await it to get the data, in this case, our users. Next, we map these users to a bunch of

[30:37] list items, exactly like how we render them in a React application. So, for our markup, let's replace this div with a fragment. Here we add an h1 called users. Then we add an unordered list, and here

[30:52] these users. We grab each user. Now, if you type user. Look, we don't see anything because the compiler doesn't know about the type of these user objects. So, if you hover our mouse

[31:05] over this constant, look, the type of this constant is any, which means we don't know. It could be anything. This is where we can use some TypeScript magic to improve our code. So, outside of this component,

[31:19] we define an interface or a type called user. And here we say that each user has a property called ID of type number. It also has name of type string and so on. We could list all the properties we

[31:35] have here, but that is not necessary for this lesson, so we're going to keep things simple. So, with this interface, we're defining the shape of our user objects, okay? Now, where we declare this constant,

[31:48] we annotate it with its type, which is user array. Okay? With this, when we type user. we can see the properties of user objects. So, this is the benefit of

[32:02] using TypeScript. With TypeScript, we get auto-completion when we're coding, and also if we have any kind of errors like typos, we can catch those errors at build time, before we run and deploy our application, okay?

[32:16] a list item. First, we give it a key, which we set to user.id. And here we render user.name. That's all we had to do. So, our code is simpler, there's no state and effect

[32:31] hook here. Our bundle is going to be smaller because this component will be Now, back to the browser, let's go to the users page. Here's our users, beautiful. Now, let's bring up the network tab

[32:45] and refresh the page. So, take a look at the document that we received from the back-end. So, all our users are rendered right here. This is because rendering is happening on the server. In contrast, in

[32:59] typical React applications or wherever we use client-side rendering, the we use client-side rendering, the browser initially gets a blank document. Then it will call the back-end to fetch the data and then render the content.

[33:11] So, there's always an extra round trip to the back-end, and our application is not search engine friendly. So, to fetch data, whenever possible, we should fetch data, whenever possible, we should fetch it in server components.

[33:31] extra benefit, and that is caching. What is caching? Well, the idea of caching is to store data somewhere that is faster to access. Basically, there are three places where we can get the data from. We can get it

[33:44] from the memory, from the file system, or from the network. Now, as we go down this list, getting data becomes slower. For example, getting data from the network is always slower than getting it from the file system. For this reason,

[33:58] Next.js comes with a built-in data cache. So, whenever we use the fetch function to get some data, Next.js will automatically store the result in its data cache, which is based on the file

[34:11] system. So, the next time we need the same piece of data, that next time we hit the same URL, Next.js is not going to go to JSON Placeholder, it's going to get the data from its data cache, from the file system. Of course, we have full

[34:25] control over this caching behavior. If you have data that changes frequently, we can disable caching or treat data in cache as fresh for a certain period of So, here when we call the fetch function, we can pass a second argument,

[34:41] which is an options object. Let me put this on a new line, so you can see clearly. In this object, we can set cache to no-store to disable caching. That's one option,

[34:54] and this is useful if you have data that changes frequently. In those situations, we always want to show fresh data to our users, right? The other option is to keep data fresh for a certain period of time.

[35:08] no-store, we set next to an object. In this object, we can specify configuration parameters that are specific to Next.js. So, here we can set revalidate to value

[35:22] like 10, and this means Next.js is going to run a background job and get fresh data from the back-end every 10 seconds. So, this is how caching works in Next.js. Now, one thing you need to know is that

[35:36] this caching behavior is only implemented in the fetch function. So, if you use a third-party library like Axios, you're not going to get this. Axios, you're not going to get this. You're not going to get the data cache.

[35:56] optimization technique called static rendering or static site generation. The idea of static rendering is that if you have pages or components that have static data, we can have Next.js render them once when we build our application

[36:11] for production. So, next time those pages or components are needed, Next.js is not going to re-render them. It's going to get their payload or content from its cache, which is based on the file system. This is static rendering,

[36:25] meaning rendering at build time. In comparison, we have dynamic rendering, which happens at request time. Let's see this in action. So, back to our users page, let's add a timestamp above the list of users. So,

[36:39] here we add a paragraph and render. First, we create a new date object, and First, we create a new date object, and then call toLocaleTimeString. rendered. Now, back in the browser, let's refresh

[36:53] a few times. So, look, the timestamp is changing. This only happens in development mode. But if we build this application for production, you'll see that the timestamp is not going to change because Next.js will treat this

[37:07] reason. Earlier, I told you that by default, whenever we use the fetch function, Next.js will cache the data. So, it treats our data as static or unchanging data. So, when rendering this page,

[37:22] Next.js sees that this page has static data, so it decides to render this page statically at build time. But if we disable caching, Next.js thinks the data not going to render this page statically, it's going to render it at

[37:38] request time. To see this action, let's go back to the stop this process. Now, earlier we used npm run dev to start this application in our development server. Now, to build this

[37:51] development server. Now, to build this for production, we run npm run build. routes that are generated when we build our application for production.

[38:04] So, this is our root route or the home page. We have a route for our favorite We have one for the users page, another for the users/new page, and so on. Now, look at the icon before each of these routes. Here, we only see circles.

[38:19] Now, down here, you can see that a circle means static. So, these pages are automatically rendered as static HTML. Now, if you start this application in production, which we can do by running

[38:32] npm start, and then go back to the browser, let's refresh. Look, the timestamp is not changing statically at build time. Now, back to this page, let's disable

[38:45] caching and rebuild this application for production. So, as a second argument, we pass an options object, and here we set cache to Okay? Now, back to the terminal, let's stop

[38:59] this process, and rebuild the application. before the users route. Instead of a circle, we have a lambda. And down here,

[39:14] you can see that lambda means rendering on the server. So, server-side renders Now, let's start the application in production. Back to the browser, let's refresh.

[39:27] Now, look, every time you refresh, the timestamp changes. Let's recap everything you have learned about rendering. In Next.js, rendering can happen on the client or on the server. If it happens on the server, it

[39:40] can happen at build time, which is called static rendering, or at request time, which is called dynamic rendering. So, that brings us to the end of this section. In the next section, we'll talk about styling Next.js applications. So,

[39:54] about styling Next.js applications. So, I will see you there. this section, we'll explore various ways to style our applications and make them beautiful. We'll cover global styles, CSS modules,

[40:09] Tailwind, and Daisy UI. So, let's jump in and get started.

[40:24] about our global style sheet in the app folder. So, let's open up globals.css. In this file, on the top, we have three directives to import the base styles from Tailwind. Now, we're going to talk

[40:37] about Tailwind later in this section, but very briefly, Tailwind is a very popular CSS framework, okay? Then after that, we have this root selector. This is where we typically define custom properties like foreground

[40:51] RGB, and so on. Then we have media prefers-color-scheme: dark. With this CSS feature, which is relatively new, we can detect if the user is in the dark mode or not. If so, you can see that the value of these

[41:06] custom properties is overwritten. Now, down here, you can see that we have used the value of this custom property as the color of the body element. So, we are not using background start and end RGB. They were

[41:21] used earlier when we had a gradient on our home page. So, before going further, let's do a bit of cleanup here. I'm going to delete these two lines, and these two lines from here. And also, let's go back to the terminal

[41:34] and make sure that we're running this application in changes here, we can see the changes changes here, we can see the changes immediately. So, npm run dev.

[41:46] Good. Now, back to this file. So, this is our global style sheet, and we should use it for styles that are truly global in our application, styles that apply to all pages, like anything to do with the body element, our

[41:59] headings, our hyperlinks, and so on. Anything that is specific to a page or a somewhere else. So, one thing you shouldn't do here is you shouldn't shouldn't do here is you shouldn't define custom classes like user list,

[42:13] because this only applies to a particular component or page. With this approach, as we build more and more components, this global style sheet grows really large and becomes unmanageable. And more importantly, as

[42:25] we change or delete our components, we'll have to remember to come back and do some cleanup here. Otherwise, over time, we'll have a lot of dead styles in this file. If you have been working with CSS for a while, you know what I'm

[42:38] So, reserve this file for styles that are truly global. For styles that are specific to a page or a component, use CSS modules or Tailwind, which we're CSS modules or Tailwind, which we're going to talk about next.

[42:58] A CSS module is a CSS file that is scoped to a page or a component. It's a way to prevent styles from clashing or overriding each other. If you have been working with CSS for a while, you know that if you have the same class defined

[43:13] in two different places in two different style sheets, these classes can override each other depending on how we import these style sheet files. CSS modules aim they work. So, here in the components folder,

[43:28] So, here in the components folder, we have a component called product card. Now, let's say you want to create some styles for this component. So, here we add a new file. We can call this file anything, but it's

[43:40] better to call it the same as the component, so product card. What matters is that the extension has to be dot module.css. Now, in this file or in this CSS module, we can define classes that are scoped to

[43:57] our product card component. So, let's define a class called card. And of course, we can define this class somewhere else without worrying that these classes would clash, okay? So, here we can apply a padding of 1

[44:11] rem, and a border of 1 pixel solid and a border of 1 pixel solid CCC. and import this style sheet. So, we type import

[44:26] from current folder, productcard.module.css. The name we assign here doesn't matter, but typically we go with styles, and this will be a JavaScript object. So, the classes that we define in this CSS

[44:41] module will end up being properties of that object. So, here if we type styles, we should see those properties, but I don't know why IntelliSense is not currently working for me, so I apologize

[44:54] for that. So, here we should see the classes we have defined like card, and so on. And that means in CSS modules, we cannot use hyphens when naming these classes, like card container, because this is not a valid

[45:08] name for a JavaScript property. So, in these files, always use the camel case notation. So, we remove the hyphen and make the first letter of the second word uppercase, okay? Now, let's just simplify things. We go

[45:22] with card. Back to our component. Now, on this div, we set class name to we use our curly braces and set it to styles.card.

[45:42] style applied to our card. But, let me show you something interesting. Let's right-click here, and inspect this in Chrome DevTools. Here's our div. Look at the class name. This is not the class that we created,

[45:55] right? This is auto-generated. So, what is happening here is that this project uses a tool called PostCSS for transforming our CSS class names. So, back to our project. Here in the root folder,

[46:10] Here in the root folder, we have a file called postcss.config.js. plugins. One is Tailwind, the other is autoprefixer. Now, for the most part, we don't have to touch this configuration file, but if you're an advanced PostCSS

[46:25] user, you know this is where you can provide your custom configuration. So, when building our application, Next.js uses PostCSS to transform our class names and generate unique class names that don't clash. This is how CSS

[46:41] modules work. Now, one last thing before we finish this lesson. Currently, I've put the CSS file and the TypeScript file next to each other. If you don't like mixing up your CSS and TSX files, you

[46:54] can group them in folders. So, here we can create a folder like product card. This is a container for our component. In this component, we can have a TSX file and a CSS file, okay?

[47:08] And of course, we can use the same technique with our pages. So, we can use CSS modules to define styles that are local to a particular page.

[47:25] So, Tailwind is a very popular CSS framework that uses the concept of utility classes. So, here on tailwindcss.com, you can see that we have a bunch of classes like flex,

[47:38] pt-4, which is short for padding top four, text center, and so on. So, here we have a ton of small utility classes, and we can combine them to style our application. Some people love it, some people hate

[47:51] it. I have to confess that I also have a love-hate relationship with Tailwind, but I think I love it more than I hate it. If you have never used it before, I strongly encourage you to give it a chance, because these days, a lot of

[48:03] projects are built with Tailwind. So, if you want to upgrade your skills and expand your job opportunities, you should have Tailwind in your skill set. So, in Tailwind, we have a ton of small utility classes.

[48:16] For example, for controlling paddings, we have a bunch of classes that start with P, followed by a number, which can be 1 2 3 4, and so on. The larger the number, the more padding we'll have. We also have px for applying horizontal

[48:30] padding. This is the same as applying a left and a right padding. We also have left and a right padding. We also have py for vertical padding. We have pt for padding top, pr for padding right, pb for padding bottom, and pl for padding

[48:46] left. Now, you don't have to memorize any of this stuff. As you practice, quickly. Now, for margins, we have similar classes, but they start with M, followed by a number, mx for horizontal margin,

[49:00] my for vertical margin, and so on. Now, for styling text, again, we have a ton of classes. For example, for controlling the size, we have text-xs, which is extra small. We have text small, text base, which is like the

[49:15] regular size. We have text large, x large, 2x large, and so on. For applying colors, we have classes that start with text, followed by a So, if you Google Tailwind color palette,

[49:29] on this page, you can see the default color palette that comes with Tailwind. So, we have all these beautiful colors, and for the most part, we don't need to customize them. They just look great as they are,

[49:42] but you can always customize these and use colors that are specific to your brand. Now, look for example for sky, we have various shades of blue that start with 50 and go all the way to 950. The larger

[49:56] the number, the darker the color. You will see an example of this later in this video. Now, back to our slide. For controlling the background color, we have a bunch of classes that start with BG followed by a color code. Now, for

[50:09] controlling the thickness of font, we have a bunch of classes like font thin, have a bunch of classes like font thin, font light, normal, medium, bold, and so on. That's the idea of Tailwind. Now, there are a lot more classes in Tailwind

[50:22] that we can cover here, but our focus here in this course is on Next.js and not Tailwind. I just want to show you the basics so you can learn the rest on So, let's see these classes in action and then I will explain why you may want

[50:34] to use Tailwind. So, back to our project. Earlier we used the CSS module to style our product card. Let's see how we can use Tailwind instead of a CSS module to style this component. So,

[50:48] in this file, we don't need to import our CSS module. Instead, we can apply Tailwind utility classes right here. Now, in this lesson, I'm going to use a different set of styles than the styles

[51:02] we applied in our CSS module so you can see more of Tailwind in action. So, we're going to give this some padding which I type P- Now, if you press control and space, you can see all the padding classes. So, we have P-0

[51:17] which is equivalent to padding zero. We have padding one which is equivalent We have padding one which is equivalent to 0.25 REM or 4 pixels. And as the number increases, we get more padding. So, this IntelliSense comes with the

[51:31] beginning of the course. So, let's give this a padding of five. A vertical margin of five. Now, I want to give it a background color so we type BG-

[51:45] Now, look again in IntelliSense, we can see all the colors. I'm going to go with sky- 400. Now, to make the text white, here we apply text- white.

[51:59] We can make it large. So, here we use text XL or 2XL, 3XL, and Again, on the right side you can see the actual size that is applied. So, for actual size that is applied. So, for text XL, font size is 1.25 REM or 20

[52:14] Now, here's the part that gets interesting. Here we have pseudo selectors like hover and with this, we can apply styles when we hover over this box or this div. So, we can change the background color

[52:28] So, we can change the background color to BG sky 600 or 500 to make it slightly Now, back to the browser. Here's our div. If you hover over it, you can see So, this is how we style our applications with Tailwind. Now, the

[52:44] selling point of Tailwind is that we can style our components right here in our component file. We don't have to juggle back and forth between a CSS file and a component file. Everything is in one place. Now, some people argue that this

[52:58] violates the separation of concerns principle, but I have to disagree with that because the whole idea of separation of concerns is organize our code into distinct sections or modules, each having a separate concern.

[53:13] If you follow this principle, we'll have more opportunities for reuse. But in this case, this React component itself is a module and defines the reuse boundary. So, what we have inside this boundary is purely implementation

[53:27] detail. We can have markup with JavaScript and style all next to each other. What is inside is irrelevant to the outside world as long as this component or this module is reusable. That's just what I think. If you

[53:40] disagree or don't like using Tailwind, that's totally fine. But again, if you want to expand your job opportunities, I highly encourage you to learn Tailwind because it's in high demand these days. But there's one more benefit to using

[53:52] Tailwind and this is the reason I personally love Tailwind. With Tailwind, when we build our application, our final CSS bundle will only have the utility classes that we have used in our markup. So, if tomorrow we delete this div, none

[54:07] of these classes will be in our final CSS bundle unless we have used them somewhere else. So, with Tailwind, we don't have to remember to clean up as we change or delete our components. With CSS modules, if we delete this

[54:21] component, we have to remember to delete the CSS file as well. Or, if we change the structure here, we might still have unused classes in our CSS module. So, we have to remember to come back and clean up. So, that's the selling point that

[54:35] convinced me to start using Tailwind. But on the flip side, I don't like that over time, as our markup gets complex, we'll have a lot of these classes and it's just a matter of getting used to it. It's not terribly bad, but it's

[54:49] something that put some people off early on, but over time, I think the benefits on, but over time, I think the benefits outweigh the downside.

[55:05] DaisyUI is a very popular component library for Tailwind. It's kind of like Bootstrap for Tailwind. So, if you head over to daisyui.com, you can see all these components. For example, we have accordions, alerts,

[55:20] For example, we have accordions, alerts, we have breadcrumbs, buttons, cards, carousel, chat bubbles, and so on. Very, very useful. It's very easy to use, so let's go to the installation page.

[55:33] Daisy as a development dependency. So, I'm going to copy this line. Now, back in VS Code, I've opened my terminal window. You can open it from terminal, new terminal.

[55:47] terminal, new terminal. Now, let's paste that. we should add Daisy as one of the plugins of Tailwind. So, we should go to

[55:59] Tailwind configuration file in the root of our project. So, that is right here. Currently, there are no plugins. So, let's copy

[56:11] this line and paste it here. That's literally all we have to do. Now, let's see how we can use these Now, let's see how we can use these components. So, as an example,

[56:26] component. So, here we have a bunch of classes like BTN, BTN- neutral, BTN-primary, secondary, and so on. Exactly like Bootstrap. Under these classes use Tailwind. So, instead of us manually

[56:40] combining a bunch of small Tailwind classes to create a button, we can just use the button that comes with Daisy. And of course, we can always customize these buttons, okay? So, to create a button,

[56:53] look, we should have an example down here. There you go. This is just a basic button. We also have neutral, primary, secondary, and so on. So, back to our code. Let's style this component that we

[57:07] created earlier. Add to cart. So, here we have a button. we have a button. We set class name to BTN, BTN-primary. file, okay? Now, back to the home page. Here's what

[57:21] we get. Let's remove this blue background because it looks kind of odd. we're going to go back to product card.tsx and I'm going to remove all these Tailwind classes.

[57:35] Okay? So, here's what we are left with. Now, in Daisy, we have the concept of themes. For example, if you look at this page, themes, you can see all the available themes.

[57:50] Now, in this lesson, I'm going to use a theme called winter. And you can always preview these themes. So, on the top, you can select them and see what your application looks like. Here's the dark mode. Here we have the cupcake theme,

[58:04] Now, to use a theme, there are two steps we have to follow. First, we have to go in Tailwind configuration file and add this section for DaisyUI. So, here we activate the themes we want to use. So, let's copy

[58:20] this section and go back to tailwind.config.ts. Right after plugins, we paste this. So, we have DaisyUI. We have themes. I want to use the winter theme.

[58:36] The second step is to apply this theme on our HTML element. So, back in the documentation, look, here we have a data attribute for specifying the theme. To do that, we have to go to our layout file

[58:50] because this is where we have our HTML element. So, we set data-theme to winter. Now, back to our home page, our button looks blue. Beautiful. Now, let's go to the users page and

[59:04] put these users inside a table. So, let's go to the users page and replace this unordered list with a table. So, we select this and press command and D on Mac or control and D on Windows to

[59:20] activate multiple cursors. Now, we can change these two elements in one go. So, we change it to a table. Then, we press escape to deactivate Now, inside this table, you want to have a t head. Inside a t head, we want to

[59:36] have a t r, and inside the t r, we want to have two t h elements. Let's press Here's our markup, beautiful. Now, here we want to have two columns. The first one is username, the second is user email.

[59:51] Now, after the t head element, we should add a t body. Then we move mapping over users inside t body mapping over users inside t body and replace l i with t r. So, once

[1:00:04] again, we press command and d on Mac or control and d on Windows to change both these elements in one go. So, let's change it to t r. Now, inside this t r, we want to have two t h elements. So, t

[1:00:18] h * 2. Let me put it on a separate line. Good. In the first t h, we want to render user.name. In the second, we want to render user.email.

[1:00:32] Now, currently, we don't have email in the interface that we defined for our users. That is why we get a compilation error. So, this is another benefit of using TypeScript. The TypeScript compiler tells us about these issues

[1:00:45] before we run or deploy our application. We can catch these errors at compile We can catch these errors at compile time or even while coding. So, up here, we have the user interface. Let's add an email property of type

[1:00:58] Now, the error goes away. Lovely. So, back to Here's what we get. Now, let's apply a couple of classes from Daisy to make this table look a little bit nicer. So, back to our code.

[1:01:13] Here's our table. We set class name to table and table- bordered. And of course, you can find these in the documentation for the table component in

[1:01:25] DaisyUI. Okay, this is much better. Now, I made a mistake earlier. When rendering these rows, I used the t h element. That is why they appear as bold, but we

[1:01:38] should use t h only as the column of our tables. So, let's change all of these t h elements to t d. Once again, we select one of them and we press command and d to select

[1:01:51] So, now we have four cursors. Let's change all of them to t d. Okay, here's what we get. so let's remove it from here as well.

[1:02:08] next section, we're going to talk about routing and navigation in more detail. watching this tutorial. I just wanted to mention that this tutorial is the first mention that this tutorial is the first hour of my complete Next.js course. So,

[1:02:23] learn more, I highly recommend you to enroll in the full course because it's much faster and easier than jumping between a bunch of random, disconnected tutorials here on YouTube. The full course is 5 hours long and teaches you

[1:02:37] everything you need to build full stack applications with Next.js. It also comes with a certificate of completion and a 30-day money-back guarantee. So, if you're not happy, ask for a full refund, you get all your money back, no

[1:02:50] interested, the link is below this video.

More from Programming with Mosh

View all

⚡ Saved you 1h 02m reading this? Transcribe any YouTube video for free — no signup needed.