Engage your site visitors with live updates using Ably, Next.js, Prisma, and PlanetScale
Tags: javascript, webdev, programming, database
Published: 2022-06-28 11:54:46

---
title: Engage your site visitors with live updates using Ably, Next.js, Prisma, and PlanetScale
published: true
canonical_url: https://ably.com/blog/liveapp-with-nextjs-prisma-planetscale
description: This tutorial shows how to add live blog commenting using Ably and Next.js, PlanetScale, Prisma, and Vercel.
tags: javascript, webdev, programming, database
# cover_image: https://ik.imagekit.io/ably/ghost/prod/2022/05/realtime-app-with-next.js-prisma-and-planetscale.png?tr=w-800
# Use a ratio of 100:42 for best results.
---

Not so long ago, email was considered revolutionary. Being able to send a message to someone on the other side of the world and receive a reply in a matter of minutes was a game-changer.

Today, however, email is the slow-moving dinosaur of the Internet. Now, users expect instantaneous feedback from their online interactions and to communicate with people and machines instantly. If your app requires them to constantly refresh a web page to see the latest updates, they’ll soon be looking elsewhere. 

But how has technology kept pace with these increasing demands?

One approach is the [publish/subscribe](https://ably.com/topic/pub-sub) architectural pattern (pub/sub for short). It’s a method of asynchronous communication that enables applications to publish messages to a channel, and any clients subscribed to that channel to receive them.

This tutorial will show you how to use pub/sub to implement live commenting in a blog. As soon as someone adds a comment to a blog article, anyone reading that article will see it immediately: no page refresh required. [See it in action!](https://ably-next-prisma-planetscale.vercel.app/)

The ability to comment immediately on a blog article might not be something you’ve missed in the past, but it’s a simple, self-contained example of an application that uses a live experience to engage its audience. You can build upon what you learn here to implement other audience engagement features to add to your own applications.


## The tech stack

To achieve this, we’re going to be using the following technologies:


### Next.js

[Next.js](https://nextjs.org/) is a React framework that makes it easy to build fast and scalable web applications. React is an incredibly popular and powerful UI library, but requires extensive configuration. Next.js eliminates much of that work, and also provides developers with options on whether to render content on the client, server, or using a mixture of both.

It would be handy if you knew a little bit about Next.js before you start this tutorial, but it’s not strictly necessary because we’ll provide a good starting point for building your application and guide you through the rest. But the Next.js website has a great [mini-course](https://nextjs.org/learn/foundations/about-nextjs) that will get you up to speed quickly and their [docs](https://nextjs.org/docs/getting-started) are awesome.


### PlanetScale

[PlanetScale](https://planetscale.com/) is a database-as-a-service platform. It allows developers to quickly create highly-scalable databases and work with those databases as if they were code in a Git repository. Developers can create branches for development and push those to production when they are working as intended. You’ll be using PlanetScale to store blog comments.


### Prisma

[Prisma](https://www.prisma.io/) is a Node.js and TypeScript ORM. It is a server library which helps developers write queries to work with databases using a familiar object-oriented approach. You will be using it to work with your PlanetScale database.


### Ably

Ably is a feature-rich pub/sub messaging platform that empowers developers to create engaging digital experiences in realtime. It guarantees message delivery to all manner of devices at huge scales while preserving the order and integrity of messages. You will use it to publish blog comments to a channel and to subscribe to that channel.


### Vercel

Finally, you’ll be using [Vercel](https://vercel.com/) to host your application and make it available to the world. The nice folks at Vercel are the same people who brought you Next.js, making deployment of your application a breeze.

Now that we know what we’re going to build and what we’re going to build it with, let’s get started!


## Tutorial Steps


### Step 1: Create the Next.js application

There’s a lot of boilerplate code in this application, which we’ve created for you so that you can focus on incorporating the realtime elements. Start off by forking the Github repository for this tutorial.

clicking on the Fork button on the repository’s home page. A forked copy of that Git repository will be added to your personal GitHub or GitLab repo. That’s it. 


```bash
git clone https://github.com/ably/ably-next-prisma-planetscale.git
```


This repo contain two branches:



* `main` - which contains the solution code for this tutorial
* `starter-project` - which is the starting point for this tutorial

Check out the `starter-project` branch: you’ll be working with this branch for the whole of this tutorial. Use the `main` branch to compare your code with the solution code if you get stuck.


```bash
git checkout starter-project
```


The starter project gives you all the base components necessary to start implementing realtime communication and data persistence. It was built using [MUI](https://mui.com/), previously known as Material-UI.

Take a look at the `components` folder and get a feel for which component does what.

Execute the following `npm` commands at your project’s root directory  to install the core dependencies and launch the project:


```bash
npm install
npm run dev
```


Visit [http://localhost:3000](http://localhost:3000) in your browser and you’ll see your sample blog app, with some dummy content and a section for commenting:



![Starter project: a simple article with comments](https://ik.imagekit.io/ably/ghost/prod/2022/05/graphic1.png?tr=w-800)


Next.js will continue to hot-reload the project as you develop, so as a general rule you can see it taking shape as you work through the remaining steps without having to restart the server. When you update certain configuration files you _will_ have to restart the server, but we’ll let you know when that’s the case.


### Step 2: Install the Ably React Hooks package

The realtime commenting that you will implement in this app is provided by Ably.

Next.js is powered by React and React can be a bit fussy about where and when you use code from libraries such as Ably’s. To make life simpler for React developers, Ably has developed the [Ably React Hooks](https://www.npmjs.com/package/@ably-labs/react-hooks) NPM module. Install it into your project now:


```bash
npm install ably @ably-labs/react-hooks
```



### Step 3: Register for Ably

To use Ably’s service, you need to [sign up for a free account](https://ably.com/signup) and obtain an API key.

Your new Ably account comes with a pre-created project called **Default**, and your API key for that project will be displayed on your screen.

If, for any reason, you don’t see it, click the **Default** project in the dashboard and then select the API Keys tab at the top. Click the **Show** button to display the root API key (not to be confused with the Subscribe only API key, which will only let you read messages from a channel, and not publish to it). So make sure you get the right one.



![Ably UI displaying the root API key](https://ik.imagekit.io/ably/ghost/prod/2022/05/graphic2.png?tr=w-800)



### Step 4: Configure Ably React Hooks

In this step you will instantiate the Ably client and authenticate with the Ably platform.

First, create a file called `.env` in your project’s root directory and create a configuration key called `ABLY_API_KEY` which stores the API key you retrieved in the preceding step. Note that, even though this API key is an alphanumeric string, you don’t need to surround it with quotes.


```bash
ABLY_API_KEY=<paste your api key here>
```


One of the many great things about Next.js is that it supports API routes. These enable you to build API endpoints as Node.js serverless functions. This is really useful for us, because we can create an API endpoint that authenticates with the Ably service without having to expose our API key to the browser.

Implement an API endpoint called `/createTokenRequest` which will generate a token for you to authenticate with Ably on the client-side. Next.js makes it really easy to include API routes in your application. All you need to do is create the route handler in the `pages/api` directory, in a file of the same name.

In your Next.js application, create a `createTokenRequest.js` file in your `pages/api` folder. This route is then available as the `/createTokenRequest` endpoint.

Inside that file, create a new Ably client and use it to generate a new token:


```javascript
import Ably from "ably/promises";

export default async function handler(req, res) {
  const client = new Ably.Realtime(process.env.ABLY_API_KEY);
  const tokenRequestData = await client.auth.createTokenRequest({
    clientId: "ably-blog-app",
  });
  res.status(200).json(tokenRequestData);
}
```


You can then use this endpoint to configure Ably on the client-side. But, if you were to do so using a relative, rather than absolute URL, this would generate an error due to a bug in one of its dependencies. It wouldn’t stop the Ably service from working, but it would soon clutter up your console. So let’s fix that now by creating an environment variable for the URL. This URL will change when we deploy to Vercel in a later step.

It also needs to be available to the browser, which it isn’t by default. Luckily, Next.js can help with that. Any environment variables prefixed by `NEXT_PUBLIC_` are accessible on the client. So don’t ever put anything sensitive in there (such as your API key), but it’s a good place to configure your application’s host URL. Enter the following in your `.env` file:


```bash
NEXT_PUBLIC_HOSTNAME=http://localhost:3000
```


Now, head to your `_app.js` file and use `configureAbly` from `@ably-labs/react-hooks` to call your new authentication endpoint:


```javascript
import { configureAbly } from "@ably-labs/react-hooks";
import "../styles/globals.css";

configureAbly({
  authUrl: `${process.env.NEXT_PUBLIC_HOSTNAME}/api/createTokenRequest`,
});

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />;
}

export default MyApp;
```


Your authentication is in place. Unfortunately, if your server is running, you might see a `SyntaxError: Unexpected token 'export' issue in your browser`. The reason for that is because the `@ably-labs/react-hooks package` exports as a ES6 module and Next.js doesn’t transpile functions imported from `node_modules`.

Thankfully, there is an easy fix. First, install the `next-transpile-modules` library:


```bash
npm install --save next-transpile-modules
```


Then, head to the `next.config.js` file in your root folder and specify which library should be transpiled:


```javascript
const withTM = require('next-transpile-modules')(['@ably-labs/react-hooks']);

module.exports = withTM({
  reactStrictMode: true,
})
```


You’ll need to restart your server by hitting CTRL+C in your terminal and re-running `npm run dev`. But the error should be gone.


### Step 5: Implement Pub/Sub

Now that you have the Ably library installed, you can work on the realtime elements. 

Ably pub/sub is based on the concept of [channels](https://ably.com/docs/core-features/channels). Publishers send messages to a named channel and subscribers consume messages sent to that channel.

![Ably pub/sub for comment updates](https://ik.imagekit.io/ably/ghost/prod/2022/06/pubsub-live-blog-post-comments@2x.png?tr=w-800)

The Ably React Hooks NPM module provides a hook called `useChannel`. This hook subscribes to a specified channel when the component mounts and unsubscribes from it when the component unmounts.

The `useChannel` hook takes a callback function. This function is called every time a new message arrives on the channel so you can process it and make any necessary updates:


```javascript
import { useChannel } from "@ably-labs/react-hooks";

const [channel] = useChannel("your-channel-name", (message) => {
    //Process the incoming message
});
```


Let’s talk about how you’ll use this in your application.

When a user submits a new comment on a blog post, your application will publish a message containing this comment to a channel called `comment-channel`.

Anyone else reading that blog post will see the new comment immediately, because they are subscribed to the channel and have therefore received and processed this new comment.

To do this, head to your `Comments` component and note that there is a state variable called `comments`. This will store your list of comments. This variable gets passed to the `CommentsList` component.

Create a `submitComment()` function and use `channel.publish()` to publish a new message to the channel. In Ably, a message has two parameters: `name` and `data`. For the data, you only need the commenter’s `username` and the `text` of the comment itself. Pass this  `submitComment()` function to your `AddCommentSection` component.

Once this message is pushed, everyone subscribed to this channel, including the person creating the comment, will receive it, and it will be added to the list of comments in your state variable, thanks to the callback in `useChannel`.

Here is the code for `Comments.js`:


```javascript
import React, { useState } from "react";
import { useChannel } from "@ably-labs/react-hooks";

import Typography from "@mui/material/Typography";

import CommentsList from "./CommentsList";
import AddCommentSection from "./AddCommentSection";

export default function Comments({ initialComments = [] }) {
  const [comments, setComments] = useState(initialComments);

  const [channel] = useChannel("comment-channel", (message) => {
    // Add new incoming comment to the list of comments
    setComments((comments) => {
      return [...comments, message.data];
    });
  });

  const submitComment = async (username, comment) => {
    try {
      const body = { username, comment };
      await fetch(`${process.env.NEXT_PUBLIC_HOSTNAME}/api/comment`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(body),
      });

      channel.publish({
        name: "comment",
        data: {
          username,
          comment,
        },
      });
    } catch (error) {
      console.error("An error occurred when creating a comment: ", error);
    }
  };

  return (
    <React.Fragment>
      <Typography variant="h6" gutterBottom>
        Comments ({comments.length})
      </Typography>
      <CommentsList comments={comments} />
      <AddCommentSection submitComment={submitComment} />
    </React.Fragment>
  );
}
```

**Note**: In this example, we're using Ably's React Hooks on the client to both publish and subscribe to a channel. In a production application, you would typically want publishing to be handled by the server. This would enable you to perform any required validation before a message is distributed to other users and persisted. For example, you might want to run the message through a profanity filter. You can use our [REST SDK](https://ably.com/docs/best-practice-guide#rest-or-realtime) for server-side publishing.


### Step 6: Connect the comment form

In your `AddCommentSection` component, first receive the `Comment` components `submitComment` function as props.

Create two new state variables: `username` and `comment`. Then, replace the calls to `console.log()`s in the component’s JSX markup with calls to the functions that set the username and state variables: `setUsername()` and `setComment()`, respectively. Also, set the corresponding `TextField` `value` attributes to `{username}` and `{comment}`

Finally, create an `addComment()` function that will use your new `submitComment()` function to publish the message and reset your form:

Here is the code for `AddCommentSection.js`:


```javascript
import React, { useState } from "react";

import Grid from "@mui/material/Grid";
import TextField from "@mui/material/TextField";
import FormControl from "@mui/material/FormControl";
import Button from "@mui/material/Button";

export default function AddCommentSection({ submitComment }) {
  const [username, setUsername] = useState("");
  const [comment, setComment] = useState("");

  const addComment = () => {
    //Publish message
    submitComment(username, comment);
    //Reset form
    setUsername("");
    setComment("");
  };

  return (
    <FormControl>
      <Grid container spacing={2}>
        <Grid item xs={12}>
          <TextField
            required
            id="username"
            name="username"
            label="Username"
            variant="outlined"
            value={username}
            onChange={(event) => setUsername(event.target.value)}
          />
        </Grid>
        <Grid item xs={12}>
          <TextField
            required
            id="comment"
            name="comment"
            label="Comment"
            variant="outlined"
            multiline
            rows={4}
            value={comment}
            onChange={(event) => setComment(event.target.value)}
          />
        </Grid>
        <Grid item xs={12}>
          <Button variant="contained" onClick={addComment}>
            Submit
          </Button>
        </Grid>
      </Grid>
    </FormControl>
  );
}
```



### Step 7: Try it out!

If your server isn’t already running, start it with `npm run dev`. 

Open [http://localhost:3000](http://localhost:3000) in two separate browser tabs and try submitting comments from each. If everything is working correctly, then you should see new comments appearing instantly in both tabs.

The only issue is that if you refresh the page, you will lose all your comments. This is because your app is missing the last piece of the puzzle: data persistence. That’s what you’ll implement next.


### Step 8: Create your PlanetScale database

In this tutorial, you will be using PlanetScale for a hosted database in which to store blog comments. To start with, head to [https://planetscale.com/](https://planetscale.com/) and create a free account. Once you’re logged in, click the **New Database** button to create a database.

In the dialog that appears, name the database `ably-realtime-db` and choose the region closest to you to minimise latency.

Click the **Create Database** button and your database is ready to use:

![UI of PlanetScale database creation](https://files.ably.io/ghost/prod/2022/06/db-creation-a.png?tr=w-600)

Once you’re done, go back to your terminal and install the [PlanetScale CLI](https://github.com/planetscale/cli). This will enable you to run many helpful commands, such as opening a shell to query your database.


### Step 9: Install and configure the Prisma ORM

In your application’s root directory, run the following command:


```bash
npx prisma init
```


This command does three things:



* Adds a `DATABASE_URL` environment variable to your `.env` file with a dummy URL
* Creates a `prisma` folder within your application
* Add a `schema.prisma` file inside the `prisma` folder

The `schema.prisma` file configures your database URL and provider. You will also define your comment data model in here in a future step.

Right now, however, the `DATABASE_URL` in `.env` is a dummy one. So head back to the PlanetScale webpage. On the right side of your page, you should see a **Connect** button. Click on it and then on **Generate Password**. Select the _Prisma_ format and you should see something like this:


```javascript
datasource db { provider = "mysql" url = "mysql://******:************@******.region.psdb.cloud/database-name?sslaccept=strict" }
```


Copy this URL and add it to your .env file, but _remove the double quotes_, as this can cause problems with Vercel when you deploy your app in a later step:


```javascript
DATABASE_URL=mysql://****:****@***.region.psdb.cloud/ably-realtime-db?sslaccept=strict
```


In your `schema.prisma` file, change the provider to `mysql` and enforce referential integrity as shown below. This step is necessary due to incompatibilities between Prisma and PlanetScale, because the latter doesn’t support foreign key constraints. To overcome this, we have to set the `referentialIntegrity` property:


```javascript
generator client {
  provider = "prisma-client-js"
  previewFeatures = ["referentialIntegrity"]
}

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
  referentialIntegrity = "prisma"
}
```


In this same file, define a data model for blog comments. It will be a very straightforward one with an autogenerated ID, a user name, and a comment:


```javascript
model Comment { 
  id Int @default(autoincrement()) @id 
  username String
  comment String
}
```


Once your model is in place, sync your schema to your PlanetScale database. To start, connect to your database by opening a new tab in the terminal and running the following command:


```bash
npx prisma db push
```


If all goes well, you should see the following message:


```javascript
?  Your database is now in sync with your schema. Done in 996ms
    ...
    ✔ Generated Prisma Client (3.9.1 | library) to ./node_modules/@prisma/client in 122ms
```


Check that your schema is working correctly by connecting to your database using the PlanetScale CLI. Specify the database name and the branch you are working on, as follows:


```bash
pscale shell ably-realtime-db starter-project
```


This will open a shell into your database where you can execute `describe Comment;` and see the following table definition:


```bash
ably-realtime-db/| starter-project |> describe Comment;
+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| id       | int          | NO   | PRI | NULL    | auto_increment |
| username | varchar(191) | NO   |     | NULL    |                |
| comment  | varchar(191) | NO   |     | NULL    |                |
+----------+--------------+------+-----+---------+----------------+
```


Type `exit;` to quit the shell.

Great! Your Prisma schema is now in sync with PlanetScale. The last step is to promote your current PlanetScale branch to be the production branch. To do this, execute the following:


```bash
pscale branch promote ably-realtime-db starter-project
```



### Step 10: Install the Prisma client package

You have defined the connection details and data model in `prisma.schema`. The next step is to get your app to use this information to persist comment data.

First, stop your server if it’s still running, and install the Prisma client package:


```bash
npm install @prisma/client
```


Then, instantiate the Prisma client. Create a folder called `lib` and a file inside the folder called `prisma.js` for this:


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

const prisma = new PrismaClient();
export default prisma;
```



### Step 11: Create API routes for reading and writing comments to the database

In the same way that you built the `/api/createTokenRequest` route, create another route called `/api/comment` that your application can make GET and POST requests to. GET reads the existing comments from the database and POST writes a new comment to the database.

At the moment, the only methods you need to pay attention to are GET and POST. Anything else should return a 405 HTTP status.

Your GET endpoint should return a list of all your comments using a simple Prisma query. For the POST endpoint, your username and comment are contained within the body of the request, which you will use to create a new comment in your table.

In `/pages/api/comment.js`, enter the following code:


```javascript
import prisma from "../../lib/prisma";

export default function handler(req, res) {
  switch (req.method) {
    case "GET":
      return handleGET(req, res);
    case "POST":
      return handlePOST(req, res);
    case "OPTIONS":
      return res.status(200).send("ok");
    default:
      return res.status(405).end();
  }
}

// GET /api/comment - retrieves all the comments
async function handleGET(req, res) {
  try {
    const comments = await prisma.comment.findMany();
    res.json(comments);
    res.status(200).end();
  } catch (err) {
    res.status(err).json({});
  }
}

// POST /api/comment - creates a new comment
async function handlePOST(req, res) {
  try {
    const comment = await prisma.comment.create({
      data: {
        ...req.body,
      },
    });
    res.json(comment);
    res.status(200).end();
  } catch (err) {
    res.status(err).json({});
  }
}
```



### Step 12: Read existing comments from the database

You can now make a GET request to your `/api/comment` endpoint to fetch all the comments from your database. You can do that with getServerSideProps. This function is a really handy feature of Next.js that enables you to make an API call when the page is requested by the user. When the user first loads the page, the client will make an API call, fetch the saved comments, and pass them to props.

In `pages/index.js`, retrieve the comments from props and pass them to the `Comments` component to populate your list:


```javascript
import Container from "@mui/material/Container";
import Grid from "@mui/material/Grid";
import CssBaseline from "@mui/material/CssBaseline";
import Divider from "@mui/material/Divider";

import Header from "../components/Header";
import Footer from "../components/Footer";
import Content from "../components/Content";
import Comments from "../components/Comments";

const Home = ({ comments = [] }) => {
  return (
    <div>
      <CssBaseline />
      <Container maxWidth="lg">
        <Header />
        <Grid container spacing={5} sx={{ mt: 3 }}>
          <Grid
            item
            xs={12}
            sx={{
              py: 3,
            }}
          >
            <Content />
            <Divider
              variant="middle"
              sx={{
                my: 3,
              }}
            />
            <Comments initialComments={comments} />
          </Grid>
        </Grid>
        <Footer />
      </Container>
    </div>
  );
};

export const getServerSideProps = async () => {
  const res = await fetch(`${process.env.NEXT_PUBLIC_HOSTNAME}/api/comment`);
  const comments = await res.json();
  return {
    props: { comments },
  };
};

export default Home;
```



### Step 13: Write new comments to the database

In your `Comments` component, you can now save a new comment from your `submitComment` function. All you have to do is make a POST request with the `username` and `comment` in the request body.

Then, when you publish the message, all the subscribers can be notified and updated accordingly:


```javascript
import React, { useState } from "react";
import { useChannel } from "@ably-labs/react-hooks";

import Typography from "@mui/material/Typography";

import CommentsList from "./CommentsList";
import AddCommentSection from "./AddCommentSection";

export default function Comments({ initialComments = [] }) {
  const [comments, setComments] = useState(initialComments);

  const [channel] = useChannel("comment-channel", (message) => {
    // Add new incoming comment to the list of comments
    setComments((comments) => {
      return [...comments, message.data];
    });
  });

  const submitComment = async (username, comment) => {
    try {
      const body = { username, comment };
      await fetch(`${process.env.NEXT_PUBLIC_HOSTNAME}/api/comment`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(body),
      });

      channel.publish({
        name: "comment",
        data: {
          username,
          comment,
        },
      });
    } catch (error) {
      console.error("An error occurred when creating a comment: ", error);
    }
  };

  return (
    <React.Fragment>
      <Typography variant="h6" gutterBottom>
        Comments ({comments.length})
      </Typography>
      <CommentsList comments={comments} />
      <AddCommentSection submitComment={submitComment} />
    </React.Fragment>
  );
}
```


Run your server again using `npm run dev` and try adding some comments.

Then, open another terminal window and execute the following command:


```bash
npx prisma studio
```


This will open http://localhost:5555/ in a new browser tab where you can see and manipulate the contents of your Comment table:




![Prisma Studio showing some data in the comments table](https://ik.imagekit.io/ably/ghost/prod/2022/05/graphic5.png?tr=w-800)



That’s it! You are now ready to share the results of your work with the world. You’ll do that in the final step, by deploying your application to Vercel.


### Step 14: Deploy your app to Vercel

Before you deploy your app, you’ll have to do a bit of tidy up to deal with the inevitable CORS issues that arise when you host any web application.

In `next.config.js`, add the following HTTP headers. These specify which origins, methods, and other features your requests will support:


```javascript
const withTM = require("next-transpile-modules")(["@ably-labs/react-hooks"]);

module.exports = withTM({
  reactStrictMode: true,
  async headers() {
    return [
      {
        // match all API routes
        source: "/api/:path*",
        headers: [
          { key: "Access-Control-Allow-Credentials", value: "true" },
          { key: "Access-Control-Allow-Origin", value: "*" },
          {
            key: "Access-Control-Allow-Methods",
            value: "GET,OPTIONS,PATCH,DELETE,POST,PUT",
          },
          {
            key: "Access-Control-Allow-Headers",
            value:
              "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version",
          },
        ],
      },
    ];
  },
});
```


You also need to support the OPTIONS method, which is used as a preflight check in API requests. In your `pages/api/comment.js` file, add handling for OPTIONS by returning HTTP status 200:


```javascript
export default function handler(req, res) {
  switch (req.method) {
    case "GET":
      return handleGET(req, res);
    case "POST":
      return handlePOST(req, res);
    case "OPTIONS":
      return res.status(200).send("ok");
    default:
      return res.status(405).end();
  }
}
```


Once you’re happy that your application is working correctly, commit and push your `starter-project` branch.


```bash
git checkout starter-project
git add .
git commit -m "Final code"
git push
```


If you don’t already have one, [create an account with Vercel](https://vercel.com/signup).

Once you’re logged in, click on New Project, and import the Git repository where your code lives. Copy the URL that Vercel has generated for you, which should be something like [https://[project-name].vercel.app/](https://[project-name].vercel.app/).

Edit your `.env` file `NEXT_PUBLIC_HOSTNAME` setting to point to the Vercel URL instead of [http://localhost:3000](http://localhost:3000). Commit and push the change:


```bash
git add .
git commit -m "Configure deployment URL"
git push
```


You’re currently still working on the `starter-project` branch, so for now set that as the Production branch in Vercel.

To do this, click your Github project in the Overview page, select the **Settings** tab and then the **Git** page from the left-hand navigation menu. Change the Production Branch to `starter-project`, then click **Save**.

Then, visit the Deployments tab, click the three little dots to the right of your deployment and select **Redeploy**.

Once the deployment is complete, your app should be up and running!


![Displaying realtime communication in a live environment](https://ik.imagekit.io/ably/ghost/prod/2022/05/graphic6.gif?tr=w-800)


## Conclusion

In this tutorial, you learned how to implement pub/sub messaging in realtime using the Ably platform within a Next.js application. You also learned how to create a database with PlanetScale and how to fetch and write data to it with the Prisma ORM. Finally, you used Vercel to deploy your application in a live environment.

Realtime communication might still be new for some developers, but the public is increasingly demanding instant feedback on all interactions they have online. You’re now in a great position to give them what they want, whatever the nature of your application or service.

We’d like to acknowledge the significant contribution to this article by [Mark Lewin](https://www.linkedin.com/in/devtechwriter/), who is a Senior Developer Educator here at Ably.