Build a Next.js App with Appwrite and Multiple Databases
Tags: appwrite, database, nextjs, fullstack
Published: 2022-09-05 19:58:37

---
title: Build a Next.js App with Appwrite and Multiple Databases
published: true
description: Learn how to build a file storage application using Appwrite’s Storage service to save files and multiple databases (PostgreSQL and SQLite) to save the metadata
tags: #Appwrite #database #Nextjs #fullstack
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t0y4dgcpgqdzij3ta5fg.png
# Use a ratio of 100:42 for best results.
---
The primary purpose of a database is to store and retrieve data. In computing and application development, databases are used to efficiently organize and manage data collection and make that data accessible to users in various ways. Databases can be categorized into [Flat Files Databases](https://en.wikipedia.org/wiki/Flat-file_database), [Relational Databases](https://en.wikipedia.org/wiki/Relational_database), and [NoSQL Databases](https://en.wikipedia.org/wiki/NoSQL). 

In this post, we will learn how to build a file storage application using Appwrite’s Storage service to save files and multiple databases (PostgreSQL and SQLite) to save the metadata. Our project’s GitHub repository can be found [here](https://github.com/Mr-Malomz/next-appwrite-dbs).

## Prerequisites

To fully grasp the concepts presented in this tutorial, the following requirements apply:

- Basic understanding of JavaScript and React
- Docker [installation](https://www.docker.com/get-started/)
- An Appwrite instance; check out this [article](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9?utm_source=hackmamba&utm_medium=hackmamba) on how to set up an instance
- PostgreSQL [installation](https://www.postgresql.org/download/)
- DBeaver [installation](https://dbeaver.com/download/) or any Database GUI viewer supported by PostgreSQL


## Getting started

We need to create a Next.js starter project by navigating to the desired directory and running the command below in our terminal.

```bash
    npx create-next-app next-appwrite-dbs && cd next-appwrite-dbs
```

The command creates a Next.js project called `next-appwrite-dbs` and navigates into the project directory.

We proceed to install the required dependencies by running the command below:
```bash
    npm install appwrite prisma
```

`appwrite` is a development platform that provides a powerful API and management console for building backend servers for web and mobile applications.

`prisma` is an Object Relational Mapper that reduces the friction of working with a database by providing required features and functionality.

With that done, we can leverage Next.js [CSS Module](https://github.com/css-modules/css-modules) support to style our page by replacing the content in `Home.module.css` in the `styles` folder with the code snippet below:

```css
.container {
  padding: 0 2rem;
}

.main {
  min-height: 100vh;
  padding: 4rem 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.fieldset {
  border: none;
  margin-bottom: .2rem;
  padding: 0;
}

.label {
  display: block;
  margin-bottom: 0.6rem;
  font-size: 0.75rem;
}

.inputText {
  border: 1px solid #ccc;
  display: inline-block;
  padding: 6px 12px;
  margin-bottom: 0.6rem;
  width: 100%;
}

.fileUpload {
  border: 1px solid #ccc;
  display: inline-block;
  padding: 6px 12px;
  margin-bottom: 0.6rem;
}

.description {
  text-align: center;
}

.description {
  margin: 2rem 0;
  line-height: 1.5;
  font-size: 1.5rem;
}

.button {
  display: block;
  border: none;
  padding: 0.6rem 2rem;
  margin-top: 1rem;
  background-color: blue;
  color: white;
  cursor: pointer;
}
```


## Creating a new Appwrite Project

To create a new project,  start the Appwrite instance and navigate to the specified hostname and port `http://localhost:80`. Next, we need to log in to our account or create an account if we don’t have one. 


![Appwrite running](https://paper-attachments.dropbox.com/s_9C6F95223612512F2BFCBBAA719BAF62E5E51518F8EC1B3A16905A2D91336244_1650158621491_screencapture-localhost-auth-signup-2022-04-17-02_22_56.png)


On the console, click on the **Create Project** button, input `appwrite_dbs` as the name, and click **Create**.

![Create project](https://paper-attachments.dropbox.com/s_9C6F95223612512F2BFCBBAA719BAF62E5E51518F8EC1B3A16905A2D91336244_1650159125946_Screenshot+2022-04-17+at+02.28.39.png)
![Enter project name](https://paper-attachments.dropbox.com/s_BDB4B2E9DEBC947CF21789BC4224D1B5D1E6999B18844A1ABC22F2142E2E2A61_1653953612228_Screenshot+2022-05-30+at+15.00.51.png)


The project dashboard will appear on the console. Next, click on the **S****ettings** tab and copy the **Project ID** and **API Endpoint**. 

![Copy  Project ID and API Endpoint](https://paper-attachments.dropbox.com/s_E154BF36CD64BB83A2A9DF0C7C4D28DBDE7A6E2B723616DA943515943189E3B3_1656624197633_Screenshot+2022-06-30+at+22.22.47.png)


Next, we’ll navigate to our project root directory and create a `helper` folder; here, create an `utils.js` file and add the snippet below:

```js
    import { Storage, Client, Account } from 'appwrite';
    
    const client = new Client();
    client.setEndpoint('http://localhost/v1').setProject('ADD YOUR PROJECTID HERE');
    
    export const appwriteSDK = () => {
      const storage = new Storage(client);
      return storage;
    };
    
    export const accountSDK = () => {
      const account = new Account(client);
      return account;
    };
```

The snippet above does the following:

- Imports the required dependencies
- Configures Appwrite `client` by setting up the endpoint and project **ID**
- Creates an `appwriteSDK` and `accountSDK` to access Appwrite Storage and Authentication services, respectively

**Create Storage**
To create a storage, navigate to the **Storage** tab, click on **Add Bucket**, input `uploadDB` as the name, and click **Create**.

![Add bucket](https://paper-attachments.dropbox.com/s_E154BF36CD64BB83A2A9DF0C7C4D28DBDE7A6E2B723616DA943515943189E3B3_1656624408195_Screenshot+2022-06-29+at+22.02.41.png)
![Create Bucket](https://paper-attachments.dropbox.com/s_E154BF36CD64BB83A2A9DF0C7C4D28DBDE7A6E2B723616DA943515943189E3B3_1656624500996_Screenshot+2022-06-29+at+22.05.40.png)


Click on the **Settings** tab on the storage page and copy the **Bucket ID** as this will come in handy when building the file upload functionality.

![Storage Bucket ID](https://paper-attachments.dropbox.com/s_E154BF36CD64BB83A2A9DF0C7C4D28DBDE7A6E2B723616DA943515943189E3B3_1656624784706_Screenshot+2022-06-30+at+22.32.46.png)

## Creating File Storage App with Appwrite and PostgreSQL Database

To get started, we need to open [DBeaver](https://dbeaver.com/) or any other database GUI, right-click on the **Database** menu, click on **Create New Database**, input `uploadDB` as the database name, and click **OK**.

![Create Database](https://paper-attachments.dropbox.com/s_E154BF36CD64BB83A2A9DF0C7C4D28DBDE7A6E2B723616DA943515943189E3B3_1656625812565_Screenshot+2022-06-29+at+11.11.23.png)
![Database Created](https://paper-attachments.dropbox.com/s_E154BF36CD64BB83A2A9DF0C7C4D28DBDE7A6E2B723616DA943515943189E3B3_1656625812586_Screenshot+2022-06-29+at+11.12.07.png)


**Setting up Prisma**
With that done, we need to set up Prisma by running the command below:

```bash
    npx prisma init
```

The command creates a `prisma` folder and a `.env` file in the project directory.

Next, we navigate into the `prisma` folder and modify the `schema.prisma` file as shown below:

```js
    generator client {
      provider = "prisma-client-js"
    }
    
    datasource db {
      provider = "postgresql"
      url      = env("DATABASE_URL")
    }
    
    //add below
    model Upload {
      id          Int    @id @default(autoincrement())
      name        String
      uploadID    String
    }
```

The snippet above specifies `PostgreSQL` (default) as the database and creates an `Upload` model with required properties. The model created represents entities of our application and will map as a table in our database.

Next, we need to navigate to the generated `.env` file and modify the **DATABASE_URL**. The structure is as shown below:

```bash
    DATABASE_URL="postgresql://<YOUR USERNAME>:<YOUR PASSWORD>@localhost:5432/<DATABASE NAME>"
```

Sample of properly filled connection url below:

```bash  
  DATABASE_URL="postgresql://demolamalomo:malomz@localhost:5432/uploadDB"

```

***PS:*** *When installing PostgreSQL for the first time, we will be required to provide a* ***Username*** *and a* ***Password****. It’s the exact details we need to include in our connection string.*

Next, we need to establish a connection between our application and the PostgreSQL database by running the command below:

```bash
    npx prisma migrate dev
```

The command will ask us some questions on how to establish our connection. We can answer the questions as shown below:

```bash
    Do you want to continue? All data will be lost (N/Y) < PRESS "y">
    Enter a name for the new migration: <first migration>
```

**Creating the File Storage** **A****pplication** 
With that done, we now need to navigate to the `api` folder inside the `pages` folder, create an `upload.js` file, and add the snippet below:

```js
    import { PrismaClient } from '@prisma/client';
    
    export default function upload(req, res) {
      const { name, upload } = req.body;
      const prisma = new PrismaClient();
    
      prisma.upload
        .create({
          data: {
            name,
            uploadID: upload,
          },
        })
        .then((result) => res.status(200).json(result))
        .catch((err) => {
          console.log(err);
          res.json(err);
        });
    }
```

The snippet above does the following:

- Imports the required dependency
- Creates an `upload` API that gets the request body, instantiates Prisma, and uses `create()` method attached to `upload` the model we created earlier to create a new File upload metadata (name and uploadID)

Finally, we modify the `index.js` file in the `pages` folder to the following:

```js
import Head from 'next/head';
import { useEffect, useState } from 'react';
import { appwriteSDK, accountSDK } from '../helper/utils';
import styles from '../styles/Home.module.css';

export default function Home() {
  const [file, setFile] = useState(null);
  const [name, setName] = useState('');

  const checkSession = () => {
    const validSession = accountSDK().get();
    if (!validSession) {
      accountSDK()
        .createAnonymousSession()
        .then((resp) => console.log(resp))
        .catch((err) => console.log(err));
    }
    return;
  };

  useEffect(() => {
    checkSession();
  }, []);

  const handleSubmit = async (e) => {
    e.preventDefault();

    const sdk = appwriteSDK().createFile(
      'YOUR BUCKET ID COMES HERE',
      'unique()',
      file
    );

    sdk
      .then((url) => {
        const data = { name, upload: url.$id };
        fetch('/api/upload', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(data),
        })
          .then((res) => {
            console.log(res);
            alert('File Upload successful!');
          })
          .catch((err) => console.log(err));
      })
      .catch((err) => {
        console.log(err);
      });
  };

  return (
    <div className={styles.container}>
      <Head>
        <title>Appwrite DBs</title>
        <meta name='description' content='Generated by create next app' />
        <link rel='icon' href='/favicon.ico' />
      </Head>

      <main className={styles.main}>
        <p className={styles.description}>Appwrite Multiple DBs</p>

        <form method='post' onSubmit={handleSubmit}>
          <fieldset className={styles.fieldset}>
            <label htmlFor='name' className={styles.label}>
              Name:
            </label>
            <input
              type='text'
              name='name'
              value={name}
              required
              className={styles.inputText}
              onChange={(e) => setName(e.target.value)}
            />
          </fieldset>
          <fieldset className={styles.fieldset}>
            <label htmlFor='file' className={styles.label}>
              Select image:
            </label>
            <input
              type='file'
              name='file'
              required
              className={styles.fileUpload}
              onChange={(e) => setFile(e.target.files[0])}
            />
          </fieldset>
          <button className={styles.button}>Submit</button>
        </form>
      </main>
    </div>
  );
}
```

The snippet above does the following:

- Imports the required dependencies
- Creates state to manage the uploaded metadata(`file` and `name`)
- Creates a `checkSession` function that checks if the current session is valid or creates an anonymous session if it isn’t and calls the function upon page load using the `useEffect` hook
- Creates an `handleSubmit` function for uploading the selected file and also does the following:
    - Uses the `appwriteSDK` function to access the Appwrite Storage by passing in the **Bucket ID** we copied earlier, `unique()` flag as the `documentId`; which tells Appwrite to auto-generate a unique ID, and the file to be uploaded
    - Checks if the file upload is successful and, if it is, calls the `/api/upload` API we created earlier to upload the file metadata to the PostgreSQL database
- Markup to show the upload form

With that done, we can start a development server using the command below:

```bash
    npm run dev
```

![working demo](https://paper-attachments.dropbox.com/s_E154BF36CD64BB83A2A9DF0C7C4D28DBDE7A6E2B723616DA943515943189E3B3_1656630921510_Screenshot+2022-06-30+at+12.40.55.png)


We can also validate the upload by checking Appwrite Storage and DBeaver.


![file uploaded to Appwrite](https://paper-attachments.dropbox.com/s_E154BF36CD64BB83A2A9DF0C7C4D28DBDE7A6E2B723616DA943515943189E3B3_1656631034093_Screenshot+2022-06-30+at+12.41.12.png)
![Metadata saved to PostgreSQL](https://paper-attachments.dropbox.com/s_E154BF36CD64BB83A2A9DF0C7C4D28DBDE7A6E2B723616DA943515943189E3B3_1656631034105_Screenshot+2022-06-30+at+12.42.02.png)



## Creating File Storage App with Appwrite and SQLite Database

To change the database, first, we need to delete the `prisma` folder generated earlier. Secondly, we need to set up Prisma again by running the command below:

```bash
    npx prisma init
```

The command creates another `prisma` folder in the project directory.

Next, we need to navigate into the `prisma` folder and modify the `schema.prisma` file as shown below:

```js
    generator client {
      provider = "prisma-client-js"
    }
    
    //modify below
    datasource db {
      provider = "sqlite"
      url      = "file:./dev.db"
    }
    
    //add below
    model Upload {
      id          Int    @id @default(autoincrement())
      name        String
      uploadID    String
    }
```

The snippet above specifies SQLite as the database and creates an `Upload` model with required properties.

Lastly, we need to establish a connection between our application and the SQLite database by running the command below:

```bash
    npx prisma migrate dev
```

The command will ask us some questions on how to establish our connection. We can answer the questions as shown below:

```bash
    Do you want to continue? All data will be lost (N/Y) < PRESS "y">
    Enter a name for the new migration: <first migration>
```

The command creates a `dev.db` SQLite database, a migration folder, and establishes a database connection.

![SQLite](https://paper-attachments.dropbox.com/s_E154BF36CD64BB83A2A9DF0C7C4D28DBDE7A6E2B723616DA943515943189E3B3_1656631868483_Screenshot+2022-06-30+at+16.01.57.png)


With that done, we can restart the development server using the command below:

```bash
    npm run dev
```

We can also test and validate the upload by checking the generated SQLite database.

![SQLite database](https://paper-attachments.dropbox.com/s_E154BF36CD64BB83A2A9DF0C7C4D28DBDE7A6E2B723616DA943515943189E3B3_1656632973170_Screenshot+2022-07-01+at+00.49.19.png)

# Conclusion

This post discussed how to build a file storage application using Appwrite’s Storage service to save files and multiple databases (PostgreSQL and SQLite) to save metadata. The Appwrite platform ships with a robust SDK and database for building applications. It also offers flexible features like Storage, Authentication, Functions, Webhooks, etc, that can be integrated with the existing tech stack.

These resources might be helpful:

- [Set](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9?utm_source=hackmamba&utm_medium=hackmamba) [](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9?utm_source=hackmamba&utm_medium=hackmamba)[up Appwrite instance locally](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9?utm_source=hackmamba&utm_medium=hackmamba)
- [Appwrite official documentation](https://appwrite.io/docs)
- [Appwrite web SDK](https://github.com/appwrite/sdk-for-web)
- [Prisma ORM](https://www.prisma.io/)