Back

Deploying a NextJS app using StatelyDB on Netlify

StatelyDB is a friendlier way to use DynamoDB! If you’ve wanted the scalability of DynamoDB but found the developer experience frustrating, we’re building a better path. Our elastic schema combines the best of NoSQL and relational databases so you can build faster and stop worrying about every little decision.

We recently published an open source starter template that helps developers get started quickly building with StatelyDB on the Netlify platform. This tutorial will walk you through the example application the starter template uses and how to get your own copy deployed to Netlify.

What We’re Building

Our example app is a simple “Link in Bio” profile page, similar to Linktree or about.me, which displays a name, photo and a collection of links. Here’s what our sample site looks like:

Live demo: https://statelydb-demo.netlify.app/.

Github Source: https://github.com/StatelyCloud/netlify-starter-template

You’re going to need a Store

The very first thing we need to do is get our own Stately Cloud account so we can set up a StatelyDB Store. We’ll do that by visiting the console. If you don’t have an account yet, go through the sign-up process and follow the instructions in the console to get a new Store created.

You’ll want to grab the Store ID listed in the console:

You will also need your Client ID and Client Secret, which should be provided by the Stately team.

Defining a Schema

Our app defines a basic Schema in the schema/schema.ts file, which looks like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import { itemType, string, uint } from "@stately-cloud/schema";

export const Profile = itemType("Profile", {
  keyPath: "/p-:id",
  fields: {
    id: { type: string, fieldNum: 1 },
    fullName: { type: string, fieldNum: 2 },
  },
});

export const Link = itemType("Link", {
  keyPath: "/p-:profile_id/l-:id",
  fields: {
    id: { type: uint, fieldNum: 1, initialValue: "sequence" },
    profile_id: { type: string, fieldNum: 2 },
    title: { type: string, fieldNum: 3 },
    url: { type: string, fieldNum: 4 },
    emoji: { type: string, fieldNum: 5, required: false },
  },
});

We have two Item Types: Profile and Link.

A Profile contains a unique identifier and a full name, both of which are strings. Our app isn’t used by multiple users, so we use a default value for the identifier (default). The Profile has a Key Path like /p-default.

Every Profile has a collection of Links. A Link contains a field that references the Profile identifier, as well as a title, url and emoji. Note that the structure of the Key Path for a Link looks like /p-default/l-1, which means each link is nested under a Profile and can be efficiently retrieved using the List operation with a prefix.

Here’s an example of visualizing this structure:

We’ve already done the work of generating Typescript client code that lets us use these Item Types, which you can view in the src/lib/generated folder if you’re curious.

Using the Schema types

Our app defines a set of helper functions for interacting with our StatelyDB Items at src/lib/actions.ts:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
"use server";

import { keyPath } from "@stately-cloud/client";
import { statelyClient } from "./stately";

const profileSlug = process.env.PROFILE_SLUG || "default";

export async function fetchProfileWithLinks() {
  const links = [];
  let profile = null;
  const iter = statelyClient.beginList(
    keyPath`/p-${profileSlug}`
  );
  for await (const item of iter) {
    if (statelyClient.isType(item, "Link")) {
      links.push(item);
    } else if (statelyClient.isType(item, "Profile")) {
      profile = item;
    }
  }
  return { profile, links };
}

export async function createLink(formData: FormData) {
  const title = formData.get("title") as string;
  const url = formData.get("url") as string;
  const emoji = formData.get("emoji") as string;
  const link = statelyClient.create("Link", {
    title,
    url,
    profileId: profileSlug,
    emoji,
  });
  await statelyClient.put(link);
}

export async function deleteLink(id: bigint) {
  await statelyClient.del(keyPath`/p-${profileSlug}/l-${id}`);
}

export async function renameProfile(newFullName: string) {
  const profile = statelyClient.create("Profile", {
    id: profileSlug,
    fullName: newFullName,
  });
  await statelyClient.put(profile)
}

This single file handles all of our database modifications — the rest of the app code is UI! You’ll notice that the fetchProfileWithLinks function uses the beginList operation and supplies a Key Path prefix that will match both the Link and Profile Items. This means we’re able to query multiple records, of different Item types, by Key Path prefix. The other functions show how easy it is to use the types from our Schema to create, edit and delete Items without needing SQL or other boilerplate.

Deploying to Netlify

First we’re going to check out the starter repo:

1
git clone https://github.com/StatelyCloud/netlify-starter-template

Next we’re going to create a new Netlify site. You will need to be logged in to the Netlify CLI first:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
❯ netlify sites:create
? Team: Stately
? Site name (leave blank for a random name; you can change it later):

Site Created

Admin URL: https://app.netlify.com/sites/delicate-yeot-198b9f
URL:       https://delicate-yeot-198b9f.netlify.app
Site ID:   3b6284e4-4c34-4cd2-9d0d-09c910078fdd

Linked to delicate-yeot-198b9f

Now we have a site, but it needs to be configured before trying to deploy. Change the environment variables here to match the values from your Stately Cloud account:

1
2
3
4
5
netlify env:set NEXT_PUBLIC_EDITABLE true
netlify env:set PROFILE_SLUG default
netlify env:set STATELY_STORE_ID your_store_id
netlify env:set STATELY_CLIENT_ID your_client_id
netlify env:set STATELY_CLIENT_SECRET your_client_secret

…and now install the npm dependencies and run a local server:

1
2
npm install
netlify dev

Since we set the environment variable NEXT_PUBLIC_EDITABLE to true we should be able to open up the edit page at http://localhost:8888/edit and add a few test links! Once you’ve had a chance to make some changes you like, let’s make the site read-only again and deploy it to Netlify.

1
2
netlify env:set NEXT_PUBLIC_EDITABLE true
netlify deploy --build

And that’s it!

Takeaway

If you’ve followed the steps above you’re well on your way to getting started using StatelyDB with NextJS on Netlify. We know that StatelyDB can handle high scale, but it’s also great for smaller sites because of the flexibility of Elastic Schema. But even better, with StatelyDB you won’t have to worry about planning for the future because you can change your mind later about your data model.

Ready to get started with StatelyDB?

🚀 Try us out! Visit our console to create a new Store and start building your application with StatelyDB.

Have more questions? We'd love to hear from you! Book a demo with our team to learn more about how you can iterate faster using StatelyDB with an elastic schema.

Our blog

Latest from our blog

/images/posts/dynamodb-is-the-kerbal-space-program-of-databases.jpg
DynamoDB is the Kerbal Space Program of Databases
The reward is worth it, but the grind to get to a good place is rough.
/images/posts/deploying-a-nextjs-app-using-statelydb-on-netlify.png
Deploying a NextJS app using StatelyDB on Netlify
We walk through deploying an example application on Netlify.
/images/posts/getting-bounced-for-a-bad-id.jpg
Getting Bounced for a Bad ID
A cautionary tale about choosing the wrong identifier.

Let's stay in touch.

Join our mailing list to get early access to stay up to date on the future of data management with no regrets.