NextGate

Start project in 3 steps

All steps are mandatory

All steps in this guide are mandatory for the project to work correctly. If you skip any of the steps, the project may not work as expected.

Of course if you don't want a specific service, you can skip the step related to this service. But in this case keep in mind that some features may not work correctly and you should remove or comment out the code related to this service.

1. Fill all API keys

Depends on the services you want to use, you need to prepare the API keys for each service. Here is the list of services that you need to prepare the API keys.

Check out how generate all keys: tutorial.

If you need your all keys in one place, please use the .env file.

.env
NODE_ENV=test
 
NEXT_PUBLIC_BASE_URL=http://localhost:3000/
NEXT_PUBLIC_API_BASE_URL=http://localhost:3000/api
NEXTAUTH_URL=http://localhost:3000
 
AUTH_SECRET=
 
DATABASE_URL=
 
AUTH_SECRET=
 
AUTH_GITHUB_ID=
AUTH_GITHUB_SECRET=
 
AUTH_GOOGLE_ID=
AUTH_GOOGLE_SECRET=
 
AUTH_RESEND_KEY=
RESEND_FROM_EMAIL="no-replay@example.com"
 
STRIPE_SECRET_KEY=
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=
STRIPE_WEBHOOK_SECRET=
 
NEXT_PUBLIC_APP_NAME="AppName"
 
NEXT_PUBLIC_GOOGLE_ANALYTICS_ID=
NEXT_PUBLIC_POSTHOG_API_KEY=
NEXT_PUBLIC_POSTHOG_HOST=
SIMPLE_ANALYTICS=
PLAUSIBLE_ANALYTICS_DOMAIN=

AUTH_SECRET

Fill AUTH_SECRET with a random string of characters. You can generate one using the following command or just type random string:

openssl rand -base64 32
.env
AUTH_SECRET=J9madM5i+D8TIoTeTj8v7qMeWioSijpKfl90nnM7cNQ=

DATABASE_URL

Fill DATABASE_URL with your database connection string. In my configuration I'm using Supabase DB and the link looks similar to this:

.env
DATABASE_URL=postgresql://postgres.[YOUR-NAME]:[YOUR-PASSWORD]@aws-0-eu-central-1.pooler.supabase.com:6543/postgres

Now if you have database configured you can run the following command to generate and push the database schema:

Sometimes drizzle will ask you about creating enum or something else. Just click enter to accept the default value.

yarn db:generate
# then
yarn db:push

Image

You have also access to drop all tables in the database (helpful if you're working locally):

yarn db:drop-tables

GITHUB OAuth

Fill AUTH_GITHUB_ID and AUTH_GITHUB_SECRET with your Github OAuth keys. You can generate them Github if you have any problems with that, please check the tutorial.

GOOGLE OAuth

Fill AUTH_GOOGLE_ID and AUTH_GOOGLE_SECRET with your Google OAuth keys. You can generate them Google Cloud Console if you have any problems with that, please check the tutorial.

RESEND

Fill AUTH_RESEND_KEY and RESEND_FROM_EMAIL with your Resend API key. You can generate them Resend dashboard if you have any problems with that, please check the tutorial.

RESEND_FROM_EMAIL is actually fake email, from my point of view this email works as a sender email. Actually in my domain there is no no-replay@lukcode.com email, but if I'm sending emails users see that email as a sender email. For example if you want to send an email to the user with the activation link for magic link. The email must be in the same domain which you have in the Resend dashboard as a verified domain.

STRIPE

To configure Stripe, fill in the following environment variables:

  • STRIPE_SECRET_KEY
  • NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY
  • STRIPE_WEBHOOK_SECRET

You can easily obtain these keys from your Stripe dashboard api keys. For the webhook secret, create a webhook in the Stripe dashboard, then copy the secret key from the webhooks section.

When setting up the webhook, you'll need to provide a URL for your API endpoint. For your production environment, it should be:

https://www.your_domain.com/api/stripe/webhooks

For local development, the endpoint will be:

http://localhost:3000/api/stripe/webhooks

However, you can't use localhost in the Stripe dashboard. To work around this, you can use a service like ngrok to create a secure tunnel to your local environment or use Stripe CLI.

Image

/api/stripe/webhooks/route.ts
  switch (event.type) {
    case 'product.created':
    case 'product.updated':
      await upsertProductRecord(event.data.object as Stripe.Product);
      break;
    case 'price.created':
    case 'price.updated':
      await upsertPriceRecord(event.data.object as Stripe.Price);
      break;
    case 'price.deleted':
      await deletePriceRecord(event.data.object as Stripe.Price);
      break;
    case 'product.deleted':
      await deleteProductRecord(event.data.object as Stripe.Product);
      break;
    case 'customer.subscription.created':
    case 'customer.subscription.updated':
    case 'customer.subscription.deleted': {
      const subscription = event.data.object as Stripe.Subscription;
      await manageSubscriptionStatusChange(
        subscription.id,
        subscription.customer as string,
        event.type === 'customer.subscription.created',
      );
      break;
    }
    case 'checkout.session.completed': {
      const checkoutSession = event.data.object as Stripe.Checkout.Session;
      if (checkoutSession.mode === 'subscription') {
        const subscriptionId = checkoutSession.subscription;
        await manageSubscriptionStatusChange(
          subscriptionId as string,
          checkoutSession.customer as string,
          true,
        );
      }
      if (checkoutSession.mode === 'payment') {
        await grantingAccessPermanently(checkoutSession.customer);
      }
      break;
    }
    default:
      throw new Error('Unhandled relevant event!');
  }

APP_NAME

It's the name of your application. It's used in many places like the title of the page, the title of the email, etc.

ANALYTICS

For analytics actually you have few different options what you can use, just fill variable with the key of the service you want:

  • Google Analytics
    • NEXT_PUBLIC_GOOGLE_ANALYTICS_ID
  • Posthog
    • NEXT_PUBLIC_POSTHOG_KEY
    • NEXT_PUBLIC_POSTHOG_HOST
  • Simple Analytics (remember to set up the domain in the Simple Analytics dashboard)
    • SIMPLE_ANALYTICS=true/false
  • Plausible (remember to set up the domain in the Plausible dashboard)
    • PLAUSIBLE_ANALYTICS_DOMAIN -> this variable HAVE TO be the same as the domain in the Plausible dashboard (without https:// and www)

I hope I don't have to explain how important analytics are, you have to know what your users are doing on your website.

2. Deploy

After committing your code, push it to a private repository on GitHub. Choose your preferred hosting platform, such as Vercel (my go-to choice), and create a new project linked to your GitHub repo. You can deploy your app on any platform that supports Next.js, including Vercel, Netlify, and Render.

Ensure all necessary environment variables are set to keep your application running smoothly.

3. Create Stripe products

Example stripe dashboard view with product I already created for this project:

Image

4. Done

That's it! You've successfully set up your project. Now you can start developing your application.

On this page