If you're building a project with Next.js, chances are that you'd like to have some kind of authentication at some point. Giving your users the capability of simply logging in to your app opens many doors; establishing a user base, restricting access to certain areas of your app, and so on.

There are many ways of doing that - one of them is using NextAuth (or just Auth.js if you prefer the new name). For my projects, I've mostly used NextAuth and have been pretty happy with it so far. But especially since version 5 lingers around the corner, the docs can get a bit confusing sometimes - in this series, I'd like to show you how to add it to your project, what caveats to expect, how to overcome them, and how to generally make use of a powerful authentication library like NextAuth.

Series content

We're going to cover common use cases for NextAuth, including:

  • Part 1: Setup & Logging in
    How to properly add NextAuth to Next.js and configure different providers, including OAuth, login via email and login via credentials
  • Part 2: Basic- and role-based authorization [UNRELEASED]
    How to prevent users to access certain content on your app, including adding roles to add even more control
  • Part 3: Deeper dive: customization, session strategies, callbacks and events [UNRELEASED]
    Exploring further configurations like adding callbacks to register your users to any other app (e.g. Stripe) whenever they sign up to your app, customizing predefined components (like the login form), and alike
  • Part 4: Profiles [UNRELEASED]
    How to add user profiles to your app, so that your users can update their profile.

I'll cover these topics to the extent I have used and found useful so far.

Tech Stack

This guide was initially written using the following versions:

  • Next.js 14 with app directory
  • NextAuth 4
  • TypeScript 5
  • For our ORM and database we're going to cover Prisma 5 with SQLite, and briefly talk about a different approach with Drizzle 0.31 and PostgreSQL which is more serverless-friendly.

Check the post footer to see when this guide was last updated. The link to the source code is available at the end.

Prerequisites

If you haven't already, let's start by creating a new Next.js application:

npx create-next-app@latest

I prefer to use the src directory and TailwindCSS - but the only required option for this guide is that you use TypeScript.

Setting up our database

While it's possible to integrate NextAuth without using a database with OAuth providers and the jwt strategy, some other providers - like the ones used for this guide (emails and credentials) - require a database. So let's get our database working first!

💡
My personal recommendation is to always use a database. Chances are you're going to have other tables in your database that you'll likely going to connect with your users via foreign keys - without a user table this can get pretty uncomfortable.

There are many options and combinations to choose from when it comes to database setups.

For the sake of simplicity, we'll just use Prisma with SQLite. As a bonus, we'll briefly cover how to use Prisma with PostgreSQL which is also available as a dedicated repository branch.

Prisma with SQLite

First, let's install Prisma and its NextAuth adapter:

npm install @prisma/client @auth/prisma-adapter
npm install prisma --save-dev

After that, we can initialize our schema with:

npx prisma init --datasource-provider sqlite

This command will create a .env file which includes our DATABASE_URL (file:./dev.db by default). In order to follow good practices, duplicate this file and rename it to .env.local - Next.js will automatically prefer this file to the .env file.

⚠️
Never put critical environment variables like secrets or credentials in the .env file and always put it in .env.local which is ignored from versioning! The .env (which is also a git versioned file) usually just provides a list of available environment variables without any values or just placeholders.

The prisma init command also created a Prisma schema file at prisma/schema.prisma, which we now need to adjust our schema to include the models required for NextAuth:

datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")
}
 
generator client {
  provider = "prisma-client-js"
}
 
model User {
  id            String          @id @default(cuid())
  name          String?
  email         String?         @unique
  emailVerified DateTime?
  image         String?
  accounts      Account[]
  sessions      Session[]
 
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}
 
model Account {
  id                String  @id @default(cuid())
  userId            String
  type              String
  provider          String
  providerAccountId String
  refresh_token     String?
  access_token      String?
  expires_at        Int?
  token_type        String?
  scope             String?
  id_token          String?
  session_state     String?
 
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
 
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
 
  @@unique([provider, providerAccountId])
}

// This table can be deleted if you're not using the `database` session strategy,
// but be careful: using an adapter automatically sets the session strategy to `database`!
model Session {
  id           String   @id @default(cuid())
  sessionToken String   @unique
  userId       String
  expires      DateTime
  user         User     @relation(fields: [userId], references: [id], onDelete: Cascade)
 
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}
 
model VerificationToken {
  identifier String
  token      String
  expires    DateTime
 
  @@unique([identifier, token])
}

From the docs

In order to follow Prisma best practices (so that we don't run into some weird "There are already 10 instances of Prisma Client actively running." warnings), we can define a single instance of Prisma that we're going to use in our applications:

import { PrismaClient } from "@prisma/client";

const prismaClientSingleton = () => {
  return new PrismaClient();
};

declare const globalThis: {
  prismaGlobal: ReturnType<typeof prismaClientSingleton>;
} & typeof global;

const prisma = globalThis.prismaGlobal ?? prismaClientSingleton();

export default prisma;

if (process.env.NODE_ENV !== "production") globalThis.prismaGlobal = prisma;

From the Best Practice docs

Last but not least we need to actually create our schema in our database. Run the following command:

npx prisma db push

Read more about the push command here

This will create a dev.db file in our prisma directory which is our SQLite database with the defined schema.

💡
Remember that SQLite databases can't be deployed on Vercel (or any other serverless environment).

Bonus: Drizzle with PostgreSQL

One approach I'd also like to show is how to set up using Drizzle with PostgreSQL. Considering SQLite doesn't work on serverless environments, this might be a more suitable solution for your app. Of course, you can also interchange these technologies and use Prisma with PostgreSQL or Drizzle with SQLite.

For the rest of the guide, we'll continue under the assumption you're using Prisma and SQLite - but the guide repository does contain the entire code for doing the exact same thing in Drizzle and PostgreSQL.

For using Drizzle with PostgreSQL, we need to install our dependencies first:

npm install drizzle-orm @auth/drizzle-adapter postgres dotenv
npm install drizzle-kit --save-dev

Next, we need to add an environment variable that is used by Drizzle to connect to our database.

DATABASE_URL=postgres://user:password@127.0.0.1:5432/app

Create this file if you haven't already

In order to quickly bootstrap a local PostgreSQL database we can make use of Docker. This one-liner should be sufficient:

docker run -d \
--name pgdb \
-e POSTGRES_DB=app \
-e POSTGRES_USER=user \
-e POSTGRES_PASSWORD=password \
-p 5432:5432 \
postgres

Next, we need to provide a drizzle.config.ts that has to be put in the root of your project:

import { defineConfig } from "drizzle-kit";

require("dotenv").config();

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema.ts",
  out: "./drizzle",
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
});

And our schema:

import {
  boolean,
  integer,
  pgTable,
  primaryKey,
  text,
  timestamp,
} from "drizzle-orm/pg-core";
import type { AdapterAccount } from "next-auth/adapters";

export const users = pgTable("user", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => crypto.randomUUID()),
  name: text("name"),
  email: text("email"),
  password: text("password"),
  emailVerified: timestamp("emailVerified", { mode: "date" }),
  image: text("image"),
});

export const accounts = pgTable(
  "account",
  {
    userId: text("userId")
      .notNull()
      .references(() => users.id, { onDelete: "cascade" }),
    type: text("type").$type<AdapterAccount>().notNull(),
    provider: text("provider").notNull(),
    providerAccountId: text("providerAccountId").notNull(),
    refresh_token: text("refresh_token"),
    access_token: text("access_token"),
    expires_at: integer("expires_at"),
    token_type: text("token_type"),
    scope: text("scope"),
    id_token: text("id_token"),
    session_state: text("session_state"),
  },
  account => ({
    compoundKey: primaryKey({
      columns: [account.provider, account.providerAccountId],
    }),
  }),
);

// This table can be deleted if you're not using the `database` session strategy,
// but be careful: using an adapter automatically sets the session strategy to `database`!
export const sessions = pgTable("session", {
  sessionToken: text("sessionToken").primaryKey(),
  userId: text("userId")
    .notNull()
    .references(() => users.id, { onDelete: "cascade" }),
  expires: timestamp("expires", { mode: "date" }).notNull(),
});

export const verificationTokens = pgTable(
  "verificationToken",
  {
    identifier: text("identifier").notNull(),
    token: text("token").notNull(),
    expires: timestamp("expires", { mode: "date" }).notNull(),
  },
  verificationToken => ({
    compositePk: primaryKey({
      columns: [verificationToken.identifier, verificationToken.token],
    }),
  }),
);

export const authenticators = pgTable(
  "authenticator",
  {
    credentialID: text("credentialID").notNull().unique(),
    userId: text("userId")
      .notNull()
      .references(() => users.id, { onDelete: "cascade" }),
    providerAccountId: text("providerAccountId").notNull(),
    credentialPublicKey: text("credentialPublicKey").notNull(),
    counter: integer("counter").notNull(),
    credentialDeviceType: text("credentialDeviceType").notNull(),
    credentialBackedUp: boolean("credentialBackedUp").notNull(),
    transports: text("transports"),
  },
  authenticator => ({
    compositePK: primaryKey({
      columns: [authenticator.userId, authenticator.credentialID],
    }),
  }),
);

Just like with Prisma, we should make a global instance of our drizzle db client:

import "dotenv/config";
import { drizzle, PostgresJsDatabase } from "drizzle-orm/postgres-js";
import postgres from "postgres";
import * as schema from "../schema";

declare global {
  var db: PostgresJsDatabase<typeof schema> | undefined;
}

let db: PostgresJsDatabase<typeof schema>;

export const client = postgres(`${process.env.DATABASE_URL}`);

if (process.env.NODE_ENV === "production") {
  db = drizzle(client, { schema });
} else {
  if (!global.db) {
    global.db = drizzle(client, { schema });
  }

  db = global.db;
}

export { db };

Lastly, push our schema to our database:

./node_modules/.bin/drizzle-kit push

With this, we can now use Drizzle and PostgreSQL for NextAuth. Check out the repository branch for the full source code. As mentioned before, for the rest of the guide we'll assume you've chosen Prisma and SQLite.

Setting up NextAuth

With all of this being done, we're now ready to add NextAuth to our application. First, let's install the dependency. Since we're using Prisma we can also already install the proper adapter for that:

npm install next-auth @auth/prisma-adapter

Check the docs for other adapters like Supabase, etc.

Auth page

For convenience, we can refactor our home page to show auth-related information and provide some buttons, so that we don't have to manually navigate between pages:

import { authOptions } from "@/lib/auth";
import { getServerSession } from "next-auth";
import Link from "next/link";

export default async function Home() {
  const session = await getServerSession(authOptions);

  return (
    <div className="mx-auto border w-96 rounded p-6 my-6 border-gray-700">
      <div>Status: {session ? "authenticated" : "unauthenticated"}</div>
      {session ? (
        <>
          <pre className="overflow-y-auto">
            {JSON.stringify(session, null, 2)}
          </pre>
          <Link
            href="/api/auth/signout"
            className="mt-3 inline-block rounded bg-blue-600 font-semibold px-2 py-1"
          >
            Logout
          </Link>
        </>
      ) : (
        <>
          <Link
            href="/api/auth/signin"
            className="mt-3 inline-block rounded bg-blue-600 font-semibold px-2 py-1"
          >
            Login
          </Link>
        </>
      )}
    </div>
  );
}

Which will look something like this:

Isn't it beautiful?

Basic configuration

The next thing we want to take care of is configuring NextAuth. My preferred way to do that is to create a lib/auth.ts file that holds our configuration and is used everywhere needed:

import prisma from "@/lib/db";
import { PrismaAdapter } from "@auth/prisma-adapter";
import { AuthOptions } from "next-auth";
import { Adapter } from "next-auth/adapters";

export const authOptions: AuthOptions = {
  adapter: PrismaAdapter(prisma) as Adapter, // this cast is required to prevent type errors, see https://github.com/nextauthjs/next-auth/issues/6106
  providers: [
    // we'll add providers in a moment
  ],
  debug: process.env.NODE_ENV === "development",
};

The debug option allows us to see a more detailed logging regarding authentication in the console

We additionally need some environment variables that NextAuth is going to consume inside our .env.local file:

NEXTAUTH_SECRET=somedecentsecret
NEXTAUTH_URL=http://localhost:3000

Create a .env.local file if you don't have one

NEXTAUTH_SECRET is simply a random string that's used for encryption of our JWT token; an easy way to generate this token is the following command:

openssl rand -base64 32

NEXTAUTH_URL refers to our URL - which is simply localhost:3000 for local development. If your site is deployed anywhere and you do have a domain, make sure to adjust this value properly.

Route handler

Next, we have to create a route handler that NextAuth is going to use. The recommended way of doing so is:

import { authOptions } from "@/lib/auth";
import NextAuth from "next-auth";

const handler = NextAuth(authOptions);

export { handler as GET, handler as POST };

This causes the GET and POST route at /api/auth/* to be handled by NextAuth. For example, if you navigate to /api/auth/signin the sign in handler of NextAuth will take care of everything and render the default login page.

Logging in

There are a bunch of different methods on how to log in - let's look at the most popular ones and how to implement them in NextAuth.

Login via email

In recent years login via "magic links" has become quite popular, especially since you get rid of the unpleasant experience of remembering (and storing) passwords. Adding this kind of login in NextAuth is rather easy:

⚠️
If you do plan to go for this approach, keep in mind that this requires a mail provider service for sending emails, like Amazon SES, Mailgun or similar. Sooner or later all these services will cost some money, which should certainly be considered when deciding to go for magic link logins.

The first thing we need to do is to install nodemailer which is used by NextAuth for sending emails:

npm i nodemailer

After that, we can add our first provider:

import prisma from "@/lib/db";
import { PrismaAdapter } from "@auth/prisma-adapter";
import { AuthOptions } from "next-auth";
import { Adapter } from "next-auth/adapters";
import EmailProvider from "next-auth/providers/email";

export const authOptions: AuthOptions = {
  adapter: PrismaAdapter(prisma) as Adapter, // this cast is required to prevent type errors, see https://github.com/nextauthjs/next-auth/issues/6106
  providers: [
    EmailProvider({
      server: process.env.EMAIL_SERVER,
      from: process.env.EMAIL_FROM,
    }),
  ],
  debug: process.env.NODE_ENV === "development",
};

In order to provide a more detailed configuration (e.g. with port, etc.) check out the docs!

We now need some additional environment variables in our .env file:

EMAIL_SERVER=smtp://localhost:1025
EMAIL_FROM=noreply@nehalist.io

For rapid local development, I always like to use Docker. Check out my guide for using Docker for web development or use this command to quickly bootstrap a mail server on your local machine:

docker run -d \
--restart unless-stopped \
--name=mailpit \
-p 8025:8025 \
-p 1025:1025 \
axllent/mailpit

This command will start an SMTP server on port 1025 and a very handy UI at localhost:8025.

If we now head to localhost:3000/api/auth/signin we should see a button to login via email:

After you've entered any email, check out localhost:8025 to receive your magic link:

Open the email, click on the "Sign in" link and you should be redirected to your app - where you now are logged in!

Login via OAuth

If you want to give your users the option to log in via a third-party provider, like Google or GitHub, NextAuth makes it fairly easy to set up that. For this guide we'll take a closer look at how to set up login via GitHub - but the principle applies to pretty much all providers.

👍
I personally do recommend this method the most - there's no need for a mail service that takes care of sending emails nor do we have to mess around with credentials. It's easy for your users, easy to integrate for you - and it's completely free.

The provider itself is quickly added by using the GitHubProvider from NextAuth for our auth.ts configuration file:

import prisma from "@/lib/db";
import { PrismaAdapter } from "@auth/prisma-adapter";
import { AuthOptions } from "next-auth";
import { Adapter } from "next-auth/adapters";
import GitHubProvider from "next-auth/providers/github";

export const authOptions: AuthOptions = {
  adapter: PrismaAdapter(prisma) as Adapter, // this cast is required to prevent type errors, see https://github.com/nextauthjs/next-auth/issues/6106
  providers: [
    GitHubProvider({
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_SECRET!,
    })
  ],
  debug: process.env.NODE_ENV === "development",
};

As with most login providers we require additional environment variables; GITHUB_CLIENT_ID and GITHUB_SECRET this time.

To get these values head over to the GitHub Developer Settings OAuth Apps. Click on "New OAuth App" and fill out your form like this:

The important part here is the "Authorization callback URL" which equals to http://localhost:3000/api/auth/callback/github, which should be adjusted accordingly if you've deployed your app with a proper domain. The /api/auth/callback/github part stays the same, regardless the domain.

After clicking on "Register application" our app should be successfully registered and we should see the details of it:

Since we need a client ID and a client secret, click on "Generate a new client secret". GitHub will create a new secret for you which is only visible once, so be sure to copy it;

Copy your client ID and client secret and put them into your .env.local file:

GITHUB_CLIENT_ID=<your client id>
GITHUB_SECRET=<your client secret>

Heading back to our login at localhost:3000/api/auth/signin we should now have the option to log in via GitHub:

Clicking on that button will redirect you to GitHub where you're asked for permission to log in to your newly created app - if you authorize your app you should be redirected to your app and be logged in!

Login via credentials

If you like a more old-fashioned login method you can also implement login via username and passwods. Unfortunately, NextAuth doesn't want you to use credentials for various reasons hence making it really uncomfortable to set up - but we can still do it.

⚠️
Disclaimer: I haven't used this approach in any real-world application so far. I also wouldn't recommend it, regardless of what NextAuth is saying. Storing and managing credentials yourself brings some serious security considerations you'll likely want to avoid. Additionally, many users likely prefer using existing accounts like their Google Account or similar and not having to worry about yet another login.

Let's alter our Prisma schema so that users do have passwords in our database. Add an optional password field to our User model:

model User {
  id            String          @id @default(cuid())
  name          String?
  email         String?         @unique
  emailVerified DateTime?
  image         String?
  accounts      Account[]
  sessions      Session[]
  password      String?

  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

The password field needs to be optional so that we can still use providers that don't use passwords.

Don't forget to update your database accordingly with:

npx prisma db push

With that being done, we can finally come to the fun part: adding our credentials provider. Unlike our previous providers this is unfortunately more work than just some configurations, but let's go through it step by step:

First, let's add our provider:

import prisma from "@/lib/db";
import { PrismaClient } from "@prisma/client";
import { AuthOptions } from "next-auth";
import { Adapter } from "next-auth/adapters";
import CredentialsProvider from "next-auth/providers/credentials";

export const authOptions: AuthOptions = {
  adapter: PrismaAdapter(prisma) as Adapter, // this cast is required to prevent type errors, see https://github.com/nextauthjs/next-auth/issues/6106
  providers: [
    CredentialsProvider({
      name: "Credentials",
      credentials: {
        username: { label: "Username", type: "text" },
        password: { label: "Password", type: "password" },
      },
      async authorize(credentials, req) {
        // we'll come to this in a moment
      }
    })
  ],
  debug: process.env.NODE_ENV === "development",
};

For this guide, we'll keep the authorize the method as simple as possible: create a user if it doesn't exist, compare the hashed and salted password, and return a user object if everything succeeded. In the real world you'd likely have a dedicated signup page and not just create the user if it doesn't exist - but that's something for another day.

For hashing and salting passwords we're going to use bcrypt - let's install that really quick:

npm i bcrypt

Let's implement our authorize method:

import prisma from "@/lib/db";
import { PrismaAdapter } from "@auth/prisma-adapter";
import { compare, genSalt, hash } from "bcrypt";
import { NextAuthOptions } from "next-auth";
import { Adapter } from "next-auth/adapters";
import CredentialsProvider from "next-auth/providers/credentials";

// A simple helper to hash and salt passwords
async function hashAndSaltPassword(password: string, saltRounds = 10) {
  const salt = await genSalt(saltRounds);
  return hash(password, salt);
}

export const authOptions: NextAuthOptions = {
  adapter: PrismaAdapter(prisma) as Adapter, // this cast is required to prevent type errors, see https://github.com/nextauthjs/next-auth/issues/6106
  providers: [
    CredentialsProvider({
      name: "Credentials",
      credentials: {
        username: { label: "Username", type: "text" },
        password: { label: "Password", type: "password" },
      },
      async authorize(credentials) {
        // Return null if no credentials were given
        if (!credentials) {
          return null;
        }

        // Try to find our user by the entered username
        let user = await prisma.user.findFirst({
          where: {
            name: credentials.username,
          },
        });

        // If the user has not been found, create it using the entered credentials
        if (!user) {
          user = await prisma.user.create({
            data: {
              name: credentials.username,
              password: await hashAndSaltPassword(credentials.password),
            },
          });
        }

        // If the user has no password (for example because it's an OAuth user), return null
        if (!user.password) {
          return null;
        }

        // Compare our entered password with the user password from the database
        const comparison = await compare(credentials.password, user.password);
        if (comparison) {
          // If the comparison is true we can finally return a user object
          return {
            id: user.id,
            name: user.name,
            email: user.email,
          };
        }

        // Return null if the comparison didn't succeed
        return null;
      },
    }),
  ],
  debug: process.env.NODE_ENV === "development",
};

If at this point you're using the jwt session strategy, you should be able to log in. Otherwise, if you're using the database strategy (which is automatically used if you provide an adapter to Prisma!), you'll see that we still can't log in, since we don't get a session from NextAuth. You can still manually enforce the jwt strategy by specifying it explicitly - but if you want to use the database strategy, we need to take care of our session ourselves.

To do so, we need to use the signIn callback and create a session for our user manually:

import prisma from "@/lib/db";
import { PrismaAdapter } from "@auth/prisma-adapter";
import { compare, genSalt, hash } from "bcrypt";
import { NextAuthOptions } from "next-auth";
import { Adapter } from "next-auth/adapters";
import CredentialsProvider from "next-auth/providers/credentials";
import { cookies } from "next/headers";

async function hashAndSaltPassword(password: string, saltRounds = 10) {
  const salt = await genSalt(saltRounds);
  return hash(password, salt);
}

export const authOptions: NextAuthOptions = {
  adapter: PrismaAdapter(prisma) as Adapter, // this cast is required to prevent type errors, see https://github.com/nextauthjs/next-auth/issues/6106
  providers: [
    /* ... */
  ],
  callbacks: {
    async signIn({ user, account }) {
      // We only want to handle this for credentials provider
      if (account?.provider !== "credentials") {
        return true;
      }

      // Our session/cookie settings
      const tokenName =
        process.env.NODE_ENV === "development"
          ? "next-auth.session-token"
          : "__Secure-next-auth.session-token";
      const expireAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
      const token = require("crypto").randomBytes(32).toString("hex");

      // Create a session in our database
      await prisma.session.create({
        data: {
          sessionToken: token,
          userId: user.id,
          expires: expireAt,
        },
      });

      // Set our cookie
      cookies().set(tokenName, token, {
        expires: expireAt,
        secure: process.env.NODE_ENV !== "development",
        sameSite: "strict",
        path: "/",
      });

      // Return to "/" after sign in
      return "/";
    },
  },
  debug: process.env.NODE_ENV === "development",
};

Now we're finally able to login via credentials, regardless of the strategy:

After entering whatever credentials we'll be redirected to our home page and be logged in!

Source code

The source code for this project is available on GitHub. If you're interested in the Drizzle/PostgreSQL implementation, check out the "drizzle-pg" branch. Future changes within this series can also be found in this repository.

Conclusion & what's next

Hopefully, I could provide some help on how to add authentication to your application. Especially with NextAuth 5 around the corner, the official docs can become a bit confusing - and since NextAuth 5 is still beta, it's still completely reasonable to invest in NextAuth 4.

I have to admit publishing this post took way longer than I anticipated - mostly due to things like being sick, switching workspaces, and rewriting major parts of this guide multiple times because of many reasons that can be boiled down to "well planned is half done" - and I didn't plan very well at first 🥲

Authentication is a huge topic, even with libraries like NextAuth - which is why I ultimately went with a multi-part series approach this time. In the next part (which hopefully will be done a lot faster than this one) we'll start to cover more advanced topics like authorization and how to (dis-)allow users access to certain areas of our app, based on different criteria like their role, their status and alike.

While the table of contents of this series is outlined at the top, it's also subject to change. Feel free to leave a comment or write me a message if you think something is missing, on what topics you'd like to have additional guidance or if for any other questions or suggestions!