Extend Supabase Apps with Nitric

What we'll be doing

In this guide we'll use the Nitric Framework with a Supabase project to build serverless services that can respond to Insert, Update or Delete operations in your Supabase tables.

This example sends welcome emails to new user profiles with SendGrid, but you could adapt the steps for other situations, like:

  • Securely processing payments with Stripe
  • Data aggregation
  • Fanout or event-based workflows with Nitric queues, topics, and schedules

You could even go the other way and build powerful SaaS APIs with Nitric, connected to your Supabase backend. Or, use Nitric schedules to clean up old data in batches.

Prerequisites

Create a Supabase project

We're assuming you're already using Supabase, but if not you can sign up for free.

Log into Supabase and create a new project. If you have an existing project you'd like to use, that'll be fine, just adapt the next few steps to match your existing project and table names.

Create a table

Next, let's create a profiles table to store basic profile information about our users such as their name and email address. You can add any other fields you'd like to this table as well.

In real scenario you'd probably relate this table to the auth.users table, but we'll keep things simple for the sake of the guide by creating a standalone profiles tables.

Navigate to database, then tables and click New

New table steps diagram

new table steps diagram

In the Name field enter profiles, then add the following columns to the table and click Save:

NameType
emailvarchar
namevarchar

create profiles table steps diagram

That's all we need to do in Supabase for now. We'll come back to the project when it's time to link everything together.

Sign up to SendGrid

Since this tutorial uses SendGrid to send user welcome emails, let's setup an account with SendGrid

Once you have an account an easy way to get started is with their Email API Guide. We'll walk through a few of the steps from that guide here, but check it out for yourself for more detail.

To send emails with SendGrid you need to setup a verified "sender", which is the email address the messages will be sent from. We'll use Single Sender Verification for simplicity.

If you see the Create a Single Sender button already, go ahead and click it. Otherwise, navigate to the Sender Authentication page and click Verify a Single Sender. A modal will be displayed to capture the sender's details.

Complete the sender's information and click Create. You'll receive a link in a confirmation email to the sender From address which you'll need to click.

SendGrid create new sender dialog screenshot

Now that you have a verified sender setup, let's generate a SendGrid API key for use in the app. Navigate to the API Keys page and click Create API Key.

In the modal enter a name for your API Key e.g. "Supabase Tutorial", select Full Access and click Create & View.

create API key dialog screenshot

The API Key will be displayed on screen starting with SG., take note of it since we'll need it later.

Create .env file and put the key in it.

Create a new Nitric project

Now that Supabase and SendGrid are both setup, let's create a new Nitric project to build the welcome email function.

Create a Nitric JavaScript project using the new command:

nitric new welcome-guide js-starter

Next, let's navigate to the project directory and install the npm dependencies:

cd welcome-guide

npm install

For this project we'll also want to install the @sendgrid/mail and dotenv packages to work with SendGrid and .env files respectively.

npm install @sendgrid/mail dotenv

The starter template comes with an example service called services/hello.js, let's rename that file to services/welcome.js so it matches what we're going to build.

mv services/hello.js services/welcome.js

With those steps complete, your project should look like this:

example project structure

Update the welcome service

Open services/welcome.js in your editor and replace the file contents with this:

services/welcome.js
import 'dotenv/config'
import sendgrid from '@sendgrid/mail'
import { api } from '@nitric/sdk'

sendgrid.setApiKey(process.env.SENDGRID_API_KEY)
const sender = process.env.SENDGRID_SENDER

const payApi = api('notifications')

payApi.post('/welcome', async ({ req, res }) => {
  if (req.headers['x-api-key'] !== process.env.API_KEY) {
    res.status = '401'
    res.body = 'Unauthorized'
    return
  }

  const { email, name } = req.json().record

  const msg = {
    to: email,
    from: sender,
    subject: 'Welcome to Nitric!',
    text: `Hi ${name}, thanks for joining, we're so glad you're here!`,
    html: `
      <h1>
        Welcome!
      </h1>
      <br />
      <p>
        Hi ${name},<br />
        Thanks for joining, we're so glad you're here!
      </p>
    `,
  }
  await sendgrid.send(msg)
  console.log(`welcome sent to: ${email}`)
})

Let's breakdown what the code above is doing.

First, we import dotenv/config so that environment variables are automatically loaded from .env files.

services/welcome.js
import 'dotenv/config'

Next, we setup the SendGrid client by providing it with an API key stored in the SENDGRID_API_KEY environment variable, which we'll create later. We also retrieve the sender email address from the SENDGRID_SENDER variable, which is used as the from email address.

services/welcome.js
import sendgrid from '@sendgrid/mail'

sendgrid.setApiKey(process.env.SENDGRID_API_KEY)
const sender = process.env.SENDGRID_SENDER

After that, we create a new Nitric API and set it up with handler for POST requests to /welcome. This handler checks for an API key in the request headers, which helps make sure that only our Supabase project can make these requests. Then, it pulls the user emails address and name from the record object in the POST request body and uses those values to send the user an email.

services/welcome.js
import { api } from '@nitric/sdk'

const payApi = api('notifications')

payApi.post('/welcome', async ({ req, res }) => {
  if (req.headers['x-api-key'] !== process.env.API_KEY) {
    res.status = '401'
    res.body = 'Unauthorized'
    return
  }

  const { email, name } = req.json().record

  const msg = {
    to: email,
    from: sender,
    subject: 'Welcome to Nitric!',
    text: `Hi ${name}, thanks for joining, we're so glad you're here!`,
    html: `
      <h1>
        Welcome!
      </h1>
      <br />
      <p>
        Hi ${name},<br />
        Thanks for joining, we're so glad you're here!
      </p>
    `,
  }
  await sendgrid.send(msg)
  console.log(`welcome sent to: ${email}`)
})

Create the .env file

There are plenty of ways to setup environment variables, but we'll keep it simple here with a .env file.

In the root of your Nitric project create a new file named .env, then copy the following into the file:

# SendGrid Details
SENDGRID_API_KEY=
SENDGRID_SENDER=

# API Key shared between Nitric and Supabase
API_KEY=

Update these variables in this file with your own values.

VariableDescription
SENDGRID_API_KEYThis is the API Key you created with SendGrid earlier, starting with SG.
SENDGRID_SENDERThis is the verified send email address you setup earlier, e.g. you@example.com
API_KEYThis is shared secret with your Supabase app, for the purposes of this guide you can use any string (just make one up or use a UUID).

⚠️ In production this value should be something cryptographically secure, so it's hard to guess or brute force.

Run the API locally

At this point everything in your Nitric services should be ready to go. You can test that it's all working by running the services locally and making POST requests to the API route.

Start the services:

nitric start

In another terminal or HTTP client, send POST requests to the API:

# Note: update the email address and x-api-key header with your own values
curl -X POST http://localhost:4001/welcome \
   -H 'Content-Type: application/json' \
   -H 'x-api-key: YOUR_API_KEY' \
   -d '{"record":{"email":"you@example.com","name":"Your Name"}}'

Sending this request should result in an email being sent to your inbox.

Bringing it all together

Here we are in the home stretch! For this last section we'll get your Supabase app connected to your Nitric services, so that every new record in the profiles table results in a welcome email being sent to the user.

You could deploy your app to a cloud provider like AWS, but for development, let's just connect your Supabase project to your local development server. One neat tool for doing this is called Ngrok. Ngrok can forward requests from a public URL to a port on your local machine.

You can install ngrok with npm like so:

npm install --save-dev ngrok

Next, let's connect it to your local Nitric api server, which should already running on port 4001:

npm run ngrok http 4001

The output from ngrok will look something like this:

ngrok by @inconshreveable    (Ctrl+C to quit)

Session Status                online
Session Expires               1 hour, 59 minutes
Version                       2.3.40
Region                        United States (us)
Web Interface                 http://127.0.0.1:4040
Forwarding                    http://61f5-194-193-39-11.ngrok.io -> http://localhost:9001
Forwarding                    https://61f5-194-193-39-11.ngrok.io -> http://localhost:9001

Connections                   ttl     opn     rt1     rt5     p50     p90
                              0       0       0.00    0.00    0.00    0.00

You can see in this example that the URL http://61f5-194-193-39-11.ngrok.io is being forwarded to port 4001 on my local machine. When you run it, the URL will be different, so take note of that value.

In Supabase, navigate to database, Function Hooks, then click Create Function Hook

create function hook screenshot

Give the function hook a new, such as welcome_customers, then select the profiles table and check Insert as the type of event to trigger your function hook:

create function hook screenshot - step 1

For Type of hook select HTTP Request:

create function hook screenshot - step 2

Finally, for HTTP Request choose the POST method, enter your ngrok URL followed by /welcome, and under HTTP Headers add a new header named x-api-key, setting it's value to match the API_KEY environment variable you created earlier:

create function hook screenshot - step 3

Click Confirm to save the hook and you're done!

Test your Function Hook

You can now test that your Function Hook is working by adding a new record to the profiles table. An easy way to do that is with the Supabase Table Editor. Navigate to the Table Editor, select the profiles table and click Insert row:

Supabase editor screenshot

That's it!