Skip to content

This Dot Blog

This Dot provides teams with technical leaders who bring deep knowledge of the web platform. We help teams set new standards, and deliver results predictably.

Newest First
Tags: NextJS
Deploying Next.js Applications to Fly.io cover image

Deploying Next.js Applications to Fly.io

Fly.io has gained significant popularity in the developer community recently, particularly after being endorsed by Kent C. Dodds for hosting his Epic Web project. It's a go-to choice for hobby projects, thanks to its starting plans that are effectively free, making it highly accessible for individual developers. While Next.js applications are often deployed to Vercel, Fly.io has emerged as a perfectly viable alternative, offering robust hosting solutions and global deployment capabilities. In this blog post, we'll give an overview of how to install a Next.js app to Fly.io, mentioning any gotchas you should be aware of along the way. The Project Our project is a simple Next.js project using the latest version of Next.js at the time of the writing (14). It uses the app directory and integrates with Spotify to get a list of episodes for our podcast, Modern Web. The bulk of the logic is in the page.tsx file, shown below, which represents the front page that is server-rendered after retrieving a list of episodes from Spotify. ` The getEpisodes is a custom function that is a wrapper around the Spotify API. It uses the Spotify client ID and secret (provided through the SPOTIFY_CLIENT_ID and SPOTIFY_CLIENT_SECRET environment variables, respectively) to get an access token from Spotify and invoke a REST endpoint to get a list of episodes for the given show ID. As can be seen from the above code, the Home is an async, server-rendered component. Scaffolding of Fly.io Configuration To get started with Fly.io and deploy a new project using flyctl, you need to go through a few simple steps: installing the flyctl CLI, logging into Fly.io, and using the flyctl launch command. Installing the CLI Installing flyctl is different depending on the operating system you use: - If you're on Windows, the easiest way to install flyctl is by using scoop, a command-line installer. First, install scoop if you haven’t already, then run scoop install flyctl in your command prompt or PowerShell. - For macOS users, you can use Homebrew, a popular package manager. Simply open your terminal and run brew install superfly/tap/flyctl. - Linux users can install flyctl by running the following script in the terminal: curl -L https://fly.io/install.sh | sh. This will download and install the latest version. Logging In After installing flyctl, the next step is to log in to your Fly.io account. Open your terminal or command prompt and enter flyctl auth login. This command will open a web browser prompting you to log in to Fly.io. If you don’t have an account, you can create one at this step. Once you're logged in through the browser, the CLI will automatically be authenticated. Scaffolding the Fly.io Configuration The next step is to use fly launch to add all the necessary files for deployment, such as a Dockerfile and a fly.toml file, which is the main Fly.io configuration file. This command initiates a few actions: - It detects your application type and proposes a configuration. - It sets up your application on Fly.io, including provisioning a new app name if you don’t specify one. - It allows you to select a region to deploy to. There are really many to choose from, so you can get really picky here. Once the process completes, flyctl will be ready for deploying the application. In our case, the process went like this: ` Deploying Now, if this was a simpler Next.js app without any environment variables, running flyctl deploy would build the Docker image in a specialized "builder" app container on Fly.io and deploy that image to the app container running the app. However, in our case, executing flyctl deploy will fail: ` This is because our page is statically rendered, and the Next.js build process attempts to run Home, our server-rendered component to cache its output. Before we can do this, we need to add our environment variables so that Fly.io is aware of them, but this is somewhat a tricky subject, so let's explain why in the following chapter. Handling of Secrets Most complex web apps will need some secrets injected into the app via environment variables. Environment variables are a good way to inject sensitive information, such as API secret keys, to your web app without storing them in the repository, the file system, or any other unprotected place. Unlike other providers such as the previously mentioned Vercel, Fly.io distinguishes built-time and run-time secrets, which are then injected as environment variables. Build-time secrets are those secrets that your app requires to build itself, while run-time secrets are needed while the app is running. In our case, due to the fact that Next.js will attempt to cache our static pages upfront, the Spotify client ID and client secret are needed during both build-time and run-time (after the cache expires). Build-Time Secrets Our Next.js app is built while building the Docker image, therefore build-time secrets should be passed to the Docker context. The recommended, Docker-way of doing this, is through Docker's build-time secrets, which are added through a special --mount=type=secret flag to the RUN command that builds the site. This is a relatively newer feature that allows you to securely pass secrets needed during the build process without including them in the final image or even as an intermediate layer. This means that, instead of having the following build command in our Dockerfile: ` we will have: ` Now, you can either modify the Dockerfile manually and add this, or you can use a helpful little utility called dockerfile: ` If we were using docker build to build our image, we would pass the secret values like so: ` However, in our case we use fly deploy, which is just a wrapper around docker build. To pass the secrets, we would use the following command: ` And now, the app builds and deploys successfully in a few minutes. To summarize, if you have any secrets which are necessary at build-time, they will need to be provided to the fly deploy command. This means that if you have a CI/CD pipeline, you will need to make sure that these secrets are available to your CI/CD platform. In the case of GitHub actions, they would need to be stored in your repository's secrets. Run-Time Secrets Run-time secrets are handled in a different way - you need to provide them to Fly.io via the fly secrets set command: ` Now, you might be wondering why fly deploy cannot use these secrets if they are already stored in Fly.io. The architecture of Fly.io is set up in such a way that reading these secrets through the API, once they are set, is not possible. Secrets are stored in an encrypted vault. When you set a secret using fly secrets set, it sends the secret value through the Fly.io API, which writes it to the vault for your specific Fly.io app. The API servers can only encrypt; they cannot decrypt secret values. Therefore, the fly deploy process, which is, if you remember, just a wrapper around docker build, cannot access the decrypted secret values. Other Things to Consider Beware of .env Files In Next.js, you can use .env as well as .env.local for storing environment variable values for local development. However, keep in mind that only .env.local files are ignored by the Docker build process via the .dockerignore file generated by Fly.io. This means that if you happen to be using an .env file, this file could be bundled into your Docker image, which is potentially a security risk if it contains sensitive information. To prevent this from happening, be sure to add .env to your .dockerignore file as well. Not Enough Memory? For larger Next.js sites, you might run into situations where the memory of your instance is simply not enough to run the app, especially if you are on the hobby plan. If that happens, you have two options. The first one does not incur any additional costs, and it involves increasing the swap size. This is not ideal, as more disk operation is involved, making the entire process slower, but it is good enough if you don't have any other options. To set swap size to something like 512 MB, you need to add the following line to the fly.toml file near the top: ` The second one is increasing memory size of your instance. This does incur additional cost, however. If you decide to use this option, the command to use is: ` For example, to increase RAM memory to 1024 MB, you would use the command: ` After making the changes, you can try redeploying and seeing if the process is still crashing due to lack of memory. Conclusion In conclusion, deploying Next.js applications to Fly.io offers a flexible and robust solution for developers looking for alternatives to more commonly used platforms like Vercel. We hope this blog post has provided you with some useful insights on the things to consider when doing so. Be sure to also check out our Next starter templates on starter.dev if you'd like to integrate a few other frameworks into your Next.js project. The entire source code for this project is available on Stackblitz....

Exploring the Hidden Gems of the Next Image Component: What You Might Be Overlooking cover image

Exploring the Hidden Gems of the Next Image Component: What You Might Be Overlooking

A blog post that explores hidden features that are easy to overlook...

Next.js Route Groups cover image

Next.js Route Groups

Learn how to organize and optimize your application routing with ease. Say goodbye to messy routes and hello to a more intuitive and maintainable structure with the new Next.js Group Routes!...

Demystifying React Server Components cover image

Demystifying React Server Components

React Server Components (RSCs) are the latest addition to the React ecosystem, and they've caused a bit of a disruption to how we think about React....

Build Beautiful Storefronts Quickly with Shopify and Next cover image

Build Beautiful Storefronts Quickly with Shopify and Next

Introduction Shopify is one of the world’s best e-commerce platforms for building online stores of any size. It’s a hosted platform, which means you don’t have to worry about the technical details of managing a server or dealing with software updates. You can focus on building your business instead. Next.js is a React framework for building static and server-side rendered applications. It’s a great choice for building e-commerce storefronts and enables you to do more customization, and it’s what we’ll be using in this article. Shopify Next.js Starter Kit Recently, we’ve created a starter kit that you can use to build your own Shopify storefront with Next.js. It’s a great way to get started quickly especially since it is powered by the new App Router and React Server Components, and it’s completely free. You can find it on GitHub here: Shopify Next.js Starter Kit We also have a live demo of the starter kit here: Shopify Next.js Starter Kit Demo Getting Started To get started, open your terminal and run the following command: And choose Shopify, NextJS 13.4 and Tailwind CSS Then, choose the project name And everything ready to go, next steps are to go to the directory and install the packages Setup Shopify Account Next, you’ll need to create a Shopify store. There are two ways to get a Shopify account: 1- You can do this by going to Shopify and clicking on the “Start free trial” button and create a Shopify account. 2- Or you can create a Shopify Partner Account for development purposes Once you’ve created your store, you’ll need to create a private app. You can do this by going to the “Apps” section of your Shopify admin and clicking on the “Manage private apps” link. Then click on the “Create a new private app” button. Give your app a name, and then click on the “Save” button. You’ll then be taken to a page where you can see your API credentials. You’ll need to copy these credentials into your .env.local file. You can find the .env.local file at the root of your project. It should look something like this: Modify the design After adding the required secrets, run npm run dev to run the development server locally The project structure is simple and easy. Since we are using the App Router, all of the routes are under /app folder and the shared components are under /components folder. This structure make it easy for you to edit and modify easily on the design Also all of the components have been written in a clean way with Tailwind CSS to make it easy for you to edit it. Deploy Since it’s a Next.js project, its deployment is easier than ever, most of the modern host providers support deploying it with just one click like * Vercel * Netlify * Cloudflare Page * AWS Amplify * Render * Fly.io Just push the project to a remote git repository using GitHub and connect it to the hosting provider of your choice. Conclusion In this article, we’ve shown you how to build a Shopify storefront with Next.js with our new starter kit from Starter.dev. We’ve also shown you how to use the new App Router and React Server Components to build a fast and performant storefront. We hope you’ve enjoyed this article and found it useful. If you have any questions or comments, please feel free to reach out to us on Twitter or GitHub. We’d love to hear from you!...

Introducing the New Shopify and Next.js 13 Starter Kit cover image

Introducing the New Shopify and Next.js 13 Starter Kit

Rapidly build custom Shopify storefronts with Next.js 13 App Router. Features include light/dark themes, authentication, infinite scroll, Zustand for state management, and exceptional performance....

Next.js 13 Server Actions cover image

Next.js 13 Server Actions

Start using Server Action in your Next.js 13 application now. Break down the separation between Server and Client with Server Actions...

Utilizing API Environment Variables on Next.js Apps Deployed to AWS Amplify cover image

Utilizing API Environment Variables on Next.js Apps Deployed to AWS Amplify

Although Next.js is a Vercel product, you may choose not to deploy to Vercel due to their pricing model or concerns with vendor lock-in. Fortunately, several other platforms fully support deployment of Next.js including AWS Amplify. Whether you’re using the Next.js app directory or not, you still have API routes that get deployed as serverless functions to whatever cloud provider you choose. This is no different on AWS Amplify. However, Amplify may require an extra step for the serverless functions if you’re using environment variables. Let’s explore how AWS Amplify is deploying your API routes, and how you can properly utilize environment variables in this context. How AWS Amplify manages Next.js API Routes When you deploy Next.js apps via Amplify, it takes the standard build outputs, stores them in S3, and serves them from behind a Cloudfront distribution. However, when you start introducing server side rendering, Amplify utilizes Lambda Edge functions. These edge functions execute the functionality required to properly render the server rendered page. This same flow works for API routes in a Next.js app. They’re deployed to individual lambdas. In Next.js apps, you have two (2) types of environment variables. There are the variables prefixed with NEXT_PUBLIC_ that indicate to Next.js that the variable is available on the frontend of your application and can be exposed to the general public. At build time, Amplify injects these variables, and values that are stored in the Amplify Console UI, into your frontend application. You also have other environment variables that represent secrets that should not be exposed to users. These will not be included in your build. However, neither set of these variables will be injected into your API routes. If you need any environment variable in your API routes, you will need to explicitly inject these values into your application at build time so they can be referenced by the Next.js systems, and stored alongside your lambdas. Injecting Environment Variables into the Amplify Build By default, Amplify generates the following amplify.yml file that controls your application’s continuous delivery (CD). The following is that default file for Next.js applications: ` To inject variables into our build, we need to write them to a .env.production file before the application build runs in the build phase. We can do that using the following bash command: ` env pulls all environment variables accessible. We use the pipe operator (|) to pass the result of that command to the grep -e which searches the output for the matching pattern. In this case, that’s our environment variable which will output the line that it is on. We then use the >> operator to append to the .env.production file, or create it if it does not exist. Be careful not to use a single > operator as that will overwrite your file’s full content. Our amplify.yml should now look like this: ` It is important to note that you have to do this for all environment variables you wish to use in an API route whether they have the NEXT_PUBLIC_ prefix or not. Now, you can use process.env.VARIABLE NAME] in your API routes to access your functions without any problems. If you want to learn more about environment variables in Next.js, [check out their docs. Conclusion In short, AWS Amplify deploys your Next.js API routes as Lambda Edge functions that can’t access your console set environment variables by default. As a result, you’ll need to use the method described above to get environment variables in your function as needed. If you want to get started with Next.js on Amplify today, check out our starter.dev kit to get started, and deploy it to your AWS Amplify account. It’ll auto-connect to your git repository and auto-deploy on push, and collaborating with others won’t cost you extra per seat....

Avoiding Null and Undefined with NonNullable<T> in TypeScript cover image

Avoiding Null and Undefined with NonNullable<T> in TypeScript

Use Cases Use Case 1: Adding Two Numbers Scenario: A function that adds two numbers and returns their sum. But if one of the numbers is undefined or null, it returns the other number as-is. ` In this code snippet, the addNumbers() function takes two parameters, a and b. a is a required parameter of type number, while b is an optional parameter of type number or null. The function uses the NonNullable&lt;T&gt; conditional type to ensure that the return value is not null or undefined. If b is null or undefined, the function returns the value of a. Otherwise, it adds a and b together and returns the sum. To handle the case where b is null or undefined, the code uses the nullish coalescing operator, ??, which returns the value on its left-hand side if it is not null or undefined, and the value on its right-hand side otherwise. Use Case 2: Checking Contact Information Scenario: A class representing a person, but with optional email and phone properties. The contact() function logs the email and phone numbers if they are defined and not null. Otherwise, it logs a message saying that no contact information is available. ` Explanation: In this code snippet, the Person class has a name property and optional email and phone properties. The contact() function checks if both email and phone are not undefined and not null before logging the details. Otherwise, it logs a message saying that no contact information is available. To initialize the properties with null, the constructor uses the nullish coalescing operator, ??. When creating a new Person, you can pass null or undefined as arguments, and the class will interpret them as null. Conclusion Understanding and correctly implementing conditional types like NonNullable&lt;T&gt; in TypeScript is crucial to reduce potential code pitfalls. By reviewing examples of numerical operations and contact information handling, we've seen how this conditional type helps reinforce our code against null or undefined values. This highlights the utility of TypeScript's conditional types not only for enhancing code stability, but also for easing our coding journey. So keep experimenting and finding the best ways to deploy these tools for creating robust, secure, and efficient programs!...

NextJS App Router - Examining the First RSC Implementation cover image

NextJS App Router - Examining the First RSC Implementation

What is the NextJS App Router and why is it important? Why are we talking about the NextJS App Router? What’s the big deal about another application router in the React ecosystem? On the surface level, it doesn’t seem that important or interesting, but it turns out that it’s not just another run-of-the-mill routing library. Until now, React has been a client-side library that concerned itself only with the view layer. It has avoided having opinions on just about everything that isn’t rendering your UI. But with React Server Components (RSC) on the horizon, it’s become more difficult for them to not have a concern with some of our other application layers like routing. If React is now going to have a hand in our server it’s going to need to be more integrated with our stack to be able to coordinate work from the server all the way back to the client side of the application. So what is the plan for this? Instead of shipping a router or an entire full-stack framework, they are going to provide an API that framework authors can integrate with to support Server Components and Suspense. This is the reason why the React team has been working closely with the NextJS team. They are figuring out the API’s that React will provide and what an implementation of it will look like. Queue drumroll… Meet the NextJS App Router. So the App Router isn’t just your grandpa’s router. It’s the reference implementation of an integration with the new RSC architecture. It’s also a LOT more than just a routing library. Glancing at the documentation page on the Next beta docs it appears to span across almost all concerns of the framework. It turns out there’s a lot of pieces involved to support the RSC puzzle. Pieces of the App Router puzzle On the getting started page of the NextJS beta documentation, there’s a summary list of features in the new App Router. Let’s take a look at some of the important pieces. Routing This seems like the most obvious one given the name “App Router”. The routing piece is extremely important to the RSC implementation. It’s still a file-based routing setup like we’re used to with NextJS with some new features like layouts, nested routing, loading states, and error handling. This is truly where the magic happens. The docs refer to it as “server-centric” routing. The routing happens on the server which allows for server-side data fetching and fetching RSC’s. But don’t worry, our application can still use client-side navigation to give it that familiar SPA feel. With nested routing, layouts, and partial rendering a navigation change and page render might only change a small part of the page. Loading states and error handling can be used to apply a temporary loading indicator or an error message nested in your layout to handle these different states. Rendering Since the App Router is RSC based, it needs to know how to render both client and server components. By default, App Router uses server components. Client components are opt-in by placing a use client directive at the top of a file. One of the main selling points of using RSCs is that you don’t have to ship JavaScript code for your RSCs in your client bundles. You can interleave server and client components in your component tree. Your pages and components can still be statically rendered at build time or you have the option for dynamic (server) rendering using either node or edge runtimes. Data Fetching One of the main selling points of RSC is being able to collocate your data-fetching with your components. Components are able to do data fetching using async/await using the fetch API. This will probably end up being a point of controversy since according to the documentation, both React, and NextJS “extend” the built-in fetch primitive to provide request deduping and caching/revalidation. The docs recommend that you do your data-fetching inside server components for several different reasons. Some of the main ones being: - Reducing client-side waterfalls. - Possible direct access to databases. - Aggregating your data-fetching in requests to a single server call (think GraphQL resolvers). This pattern is definitely becoming the norm in newer frameworks. These are similar benefits that you would reap when using something like data loaders in Remix. The big difference is that you will be able to do the fetching directly from your server components which is a nice win for co-location. Caching We touched on part of this in the Fetching section. It’s one of the reasons why NextJS is extending the fetch primitive. It’s adding support for caching your data using HTTP. If you’re used to client-side React, and tools like React Query, you can kind of think of this as the server version of that. If the data from a particular fetch request is already available in the cache, it will return right away, instead of making a trip to the origin server to get it. The other piece of the App Router caching story has to do with server components specifically. NextJS App Router stores the result of RSC payloads in an in-memory client-side cache. If a user is navigating around your application using client-side navigation, and encounters a route segment that they have visited previously, and is available in the cache, it will be served right away. This will help to provide a more instantaneous feel to certain page transitions. Tooling (bundler) We still haven’t covered the entire App Router, and RSC story because in order to support RSC, you need a bundler that understands the server component graph. This is where Vercel’s new Webpack replacement Turbopack comes into play. It’s built on a modern low-level language named Rust. This provides improved build times and hot-module-reloading (HMR) times in development, which is fantastic. Since it’s a Webpack replacement, it will be able to handle a lot of different concerns like styles, static files, etc. Goals of RSC and NextJS App Router In this Twitter thread, Vercel CEO Guillermo Rauch highlights what he believes NextJS App Router brings to User Experience. The first one is that less JavaScript code gets shipped to the client. I don’t think anyone is arguing that this is not a good thing at this point. He also mentions fast page/route transitions that feel more like a SPA, and being able to quickly stream and render above-the-fold content like a hero section while the rest of the page below finishes loading. I’ve heard a counter-argument from some RSC critics that aren’t as confident about these gains, and believe that RSC trades off UX for better DX (things like co-locating data fetching with components). Since RSC and NextJS App Router are still largely untested beta software, it’s really hard to say that this new, novel idea will be all that they are hyping it up to be. There’s a major paradigm shift currently occurring in the community though, and there are a lot of new frameworks popping up that are taking different approaches to solving the problems brought on by the proliferation of large client-side JavaScript applications. I, for one, am excited to see if React can once again push some new ideas forward that will really change how we go about building our web applications. Opening the black box I don’t know about you, but I feel like I’ve been hearing about RSC for a long time now, and it’s really just felt like this fictional thing. It's as if nobody knows what it is or how it works. Its secrets are locked away inside these experimental builds that have been released by the React team. NextJS 13 Beta has finally started to give us a glimpse behind the curtain to see that it is a tangible thing, and what it looks like in practice. I’ll be honest, up to this point, I haven’t been interested enough to dig for answers to the half-baked questions and ideas about it swimming in my mind. I know that I’m not the only one that has had this feeling. If you’re keen on learning more about what an RSC implementation looks like, there’s a good Tweet thread from Dan Abramov that highlights a lot of the important pieces and links to the relevant source code files. Some other really curious people have also embarked on a journey to see if they could create an RSC implementation similar to App Router using Vite. The repo is a great reference for understanding what’s involved, and how things work. What’s left? Even if it does feel like a lot of things have been happening behind the scenes, to their credit, NextJS has provided a beta version of the new App Router that is still experimental, and very much a work in progress. We can try out RSC today to get a feel for what it’s like, and how they work. On top of that, the NextJS documentation includes a nice roadmap of the pieces that are completed, and things that are still in progress or not quite fleshed out. As of the time of this writing, some of the major items on the list that look like blockers to a stable release are related to data fetching like use(fetch() and cache(). The most important one that I’m excited to see a solution for is mutations. They currently have a “temporary workaround” for mutations that basically involves re-running all of the data-loading in the component tree where the mutation happens. I think the plan is to have some sort of RPC built into the React core to handle mutations. Final thoughts It’s been a long time coming, but I for one am excited to see the progress and evolution of RSC through the new NextJS App Router. Since it’s still an experimental and incomplete product, I will wait before I do any real application development with it. But I will probably spend some time trying it out and getting more familiar with it before that day comes....

Introducing the Next.js 12 and Chakra UI Starter Kit cover image

Introducing the Next.js 12 and Chakra UI Starter Kit

Next.js is a very popularly used React framework, and to help support developers using Next, This Dot Labs has just created a new starter kit that they can use to bootstrap their next projects. This Next.js 12 starter kit comes with formatting, linting, example components, unit testing and styling with Chakra UI. In this article, we will take a deeper look into what this kit has to offer. Table of Contents - How to initialize a new project - Technologies and tools included with the kit - Next.js v.12 - Chakra UI - Jest - Storybook - ESLint and Prettier - A note about state management - Deployment options - Reasons for using this kit - Conclusion How to initialize a new project 1. Run npm create @this-dot/starter -- --kit next12-chakra-ui or yarn create @this-dot/starter --kit next12-chakra-ui 2. Follow the prompts to select the next12-chakra-ui starter kit, and name your new project. 3. cd into your project directory and run npm install or yarn install . 4. Run npm run dev or yarn run dev to start the development server. 5. Open your browser to http://localhost:3000 to see the included example code running. Technologies and tools included with the kit Next.js v.12 This starter kit uses version 12 of Next.js with the TypeScript configuration. We have also included an example inside the src/pages/api/hello.ts file on how to work with the built-in types for API routes. ` Chakra UI This starter kit uses Chakra UI for all of the styling. We have already setup the ChakraProvider inside the src/pages/_app.tsx file, which includes extended theme objects for colors, font weights, and breakpoints that you can customize to your liking. ` You can take a look at any of the example components inside of the src/components folder on how to best use Chakra's components. Jest This starter kit uses the Jest testing framework for its unit tests. The unit tests for the home page can be found in the tests directory. ` Storybook This starter kit comes with Storybook so you can test out your UI components in isolation. We have also included the @storybook/addon-a11y addon, which is used to check for common accessibility errors in your components. When you run Storybook, each story will show detailed explanations with suggested fixes if errors are found. Examples of stories can be found in the components directory. ESLint and Prettier This start kit uses ESLint for linting and Prettier for formatting. All of the configurations have been setup for you so you can get to building out your project faster. A note about state management This starter kit does not use a global state management library. Instead we are managing state within the routing system. For examples, please look at the /src/pages/counter-example.tsx and src/pages/fetch-example.tsx files. Deployment options You can use services like Netlify or Vercel to deploy your application. Both of these services will come with a built-in CI/CD pipeline and live previews. Reasons for using this kit Next.js is a versatile framework, and can be used for a variety of situations. Here are some examples of what you can use our starter kit for. - personal blog - e commerce application - user dashboard application - MVP (Minimum Viable Product) Conclusion Next.js has a lot to offer, and this new starter kit will help you bootstrap your next project. Study the example components to learn about best practices with Next.js and Chakra UI. Get started building out new features for your project with our new starter kit!...

Next.js Authentication Using OAuth cover image

Next.js Authentication Using OAuth

Modern web apps have come a long way from their early days, and as a result, users have come to expect certain features. One such feature is being able to authenticate in the web app using external accounts owned by providers such as Facebook, Google, or GitHub. Not only is this way of authenticating more secure, but there is less effort required by the user. With only a few clicks, they can sign in to your web app. Such authentication is done using the OAuth protocol. It's a powerful and very commonly used protocol that allows users to authenticate with third-party applications using their existing login credentials. These days, it has become an essential part of modern web applications. In this blog post, we will explore how to implement OAuth authentication in a Next.js application. Why OAuth? Implementing authentication using OAuth is useful for a number of reasons. First of all, it allows users to sign in to your web app using their existing credentials from a trusted provider, such as Facebook and Google. This eliminates the need to go through a tedious registration process, and most importantly, it eliminates the need to come up with a password for the web app. This has many benefits for both the web app owner and the user. Neither need to store the password anywhere, as the password is handled by the trusted OAuth provider. This means that even if the web app gets hacked for some reason, the attacker will not gain access to the user password. For exactly that reason, you'll often hear experienced developers advise to "never roll your own authentication". OAuth in Next.js Next.js is the most popular React metaframework, and this gives you plenty of options and libraries for implementing authentication in your app. The most popular one, by far, is definitely Auth.js, formerly named NextAuth.js. With this library, you can get OAuth running in only a few simple steps, as we'll show in this blog post. We'll show you how to utilize the latest features in both Next.js and Auth.js to set up an OAuth integration using Facebook. Implementing OAuth in Next.js 13 Using Auth.js Creating Facebook App Before starting with the project, let's create an app on Facebook. This is a prerequisite to using Facebook as an OAuth provider. To do this, you'll need to go to Meta for Developers and create an account there by clicking on "Get Started". Once this is done, you can view the apps dashboard and click "Create App" to create your app. Since this is an app that will be used solely for Facebook login, we can choose "Consumer" as the type of the app, and you can pick any name for it. In our case, we used "Next.js OAuth Demo". After the app is created, it's immediately visible on the dashboard. Click the app, and then click Settings / Basic on the left menu to show both the app ID and the app secret - this will be used by our Next.js app. Setting Up Next.js For the purpose of this blog post, we'll create a new Next.js project from scratch so you can have a good reference project with minimum features and dependencies. In the shell, execute the npx create-next-app@latest --typescript command and follow the prompts: ` As you can see, we've also used this opportunity to play with the experimental app directory which is still in beta, but is the way Next.js apps will be built in the future. In our project, we've also set up Tailwind just to design the login page more quickly. Next, install the Auth.js library: ` Now we need to create a catch-all API route under /api/auth that will be handled by the Auth.js library. We'll do this by creating the following file: ` Note that even though we will be utilizing Next.js 13's app directory, we need to place this route in the pages directory, as Auth.js doesn't yet support placing its API handler in the app directory. This is the only case where we will be using pages, though. In your project root, create a .env.local file with the following contents: ` All the above environment variables except NEXTAUTH_URL are considered secret, and you should avoid committing them in the repository. Now, moving on to the React components, we'll need to have a few components that will perform the following functionality: - Display the sign-in button if the user is not authenticated - Otherwise, display user name and a sign-out button The Home component that was auto-generated by Next.js is a server component and we can use getServerSession() from Auth.js to get the user's session. Based on that, we'll show either the sign-in component or the logged-in user information. authOptions provided to getServerSession() is the object that is defined in the API route. ` The SignIn component has the sign-in button. The sign-in button needs to open an URL on Facebook that will initiate the authentication process. Once the authentication process is completed, it will invoke a "callback"- a special URL on the app side that is handled by Auth.js. ` The UserInformation, on the other hand, is displayed after the authentication process is completed. Unlike other components, this needs to be a client component to utilize the *signOut* method from Auth.js, which only works client-side. ` And that's it! Now run the project using npm run dev and you should be able to authenticate to Facebook as shown below: Conclusion In conclusion, implementing OAuth-based authentication in Next.js is relatively straightforward thanks to Auth.js. This library not only comes with built-in Facebook support, but it also comes with 60+ other popular services, such as Google, Auth0, and more. We hope this blog post was useful, and you can always refer to the CodeSandbox project if you want to view the full source code. For other Next.js demo projects, be sure to check out starter.dev, where we already have a Next.js starter kit that can give you the best-practices in integrating Next.js with other libraries....