Connect to MongoDB Atlas from SvelteKit
Tags: sveltekit, svelte, mongodb, tutorial
Published: 2021-11-01 12:38:58

MongoDB Atlas recently published new [best practices how to connect to MongoDB Atlas database](https://docs.atlas.mongodb.com/best-practices-connecting-from-vercel/). If you would like to know how to apply this recommendations in SvelteKit using MongoDB Atlas database read on.

Start a new SvelteKit project in your console called for example SvelteKit_MongoDB_Atlas
```javascript
npm init svelte@next SvelteKit_MongoDB_Atlas
cd SvelteKit_MongoDB_Atlas
npm install
npm run dev -- --open
```


To communicate with MongoDB database we will need Node driver [mongodb](https://github.com/mongodb/node-mongodb-native). So install it.  
```javascript
npm install mongodb
```

I assume you have set up your MongoDB Atlas database. Their Starter Cluster is free. They have a clear [tutorial](https://docs.atlas.mongodb.com/getting-started/) how to do this. Or just follow the instructions after your sign up, it is pretty straightforward. You may create a new database, e.g. "Todos" with a new collection e.g. "sveltekit-todos".

To connect to MongoDB Atlas you need to use a so called MONGODB_URI. MongoDB Atlas gave you this link when you have set up your database there. It should look something like this:
```javascript
MONGODB_URI = "mongodb+srv://<username>:<password>@cluster0....."
```
As you see it contains some sensitive data (username, password). So our project needs features to keep it secret, keep it save. Best way is to use environmental variables. You usually store them in **.env** file in the root directory of your project. SvelteKit is using [Vite](https://vitejs.dev/) under the hood. Vite has its [own implementation of environmental variables](https://vitejs.dev/guide/env-and-mode.html#env-files). But it may be considered a little bit [tricky](https://dev.to/danawoodman/storing-environment-variables-in-sveltekit-2of3). 


So our project will need some other tool. Let install good old [dotenv](https://github.com/motdotla/dotenv#readme). 
```javascript
npm install dotenv
```

In the root directory of your project create a new file **.env** and insert your MONGODB_URI. Specify also database name (DB_NAME). Following recommendation from MongoDB Atlas specify that we use it in development (NODE_ENV) as well, etc.  
```javascript
MONGODB_URI = "mongodb+srv://<username>:<password>@cluster0....."
DB_NAME = "Todos"
NODE_ENV = "development" // "production", "testing"
DEV_URL = "http://localhost:3000"
PROD_URL = "https://<Vercel_Project_Name>.vercel.app"
```
Finally we have arrived to the implementation of the MongoDB Atlas best practices. One problem this tries to solve is not to open more connections to the database at the same time, especially in a serverless environment like Vercel, so it will not crash eventually.

In your *lib* directory (which is in a *src* directory) create a new file **mongodb-client.js**. Copy inside [the code adviced by MongoDB Atlas best practices](https://docs.atlas.mongodb.com/best-practices-connecting-from-vercel/#connection-example) but with a slight modification.
```javascript
import dotenv from 'dotenv';
dotenv.config();

import { MongoClient } from 'mongodb';

const uri = process.env['MONGODB_URI'];
const options = {
    useUnifiedTopology: true,
    useNewUrlParser: true,
}

let client
let clientPromise

if (!uri) {
    throw new Error('Please add your Mongo URI to .env.local')
}

if (process.env['NODE_ENV'] === 'development') {
    // In development mode, use a global variable 
    // so that the value is preserved across module reloads 
    // caused by HMR (Hot Module Replacement).
    if (!global._mongoClientPromise) {
        client = new MongoClient(uri, options)
        global._mongoClientPromise = client.connect()
    }
    clientPromise = global._mongoClientPromise
} else {
    // In production mode, it's best to 
    // not use a global variable.
    client = new MongoClient(uri, options)
    clientPromise = client.connect()
}

// Export a module-scoped MongoClient promise. 
// By doing this in a separate module, 
// the client can be shared across functions.
export default clientPromise
```
You may have noticed that we made **one very important modification** concerning how we are referencing environmental variables:
```javascript
process.env['MONGODB_URI'] // this works
process.env.MONGODB_URI //this does not work!!!
```
In your *routes* folder create **index.js** file. We are now ready to define an endpoint. To make it easy and keep this example rather simple we will insert one task "Walk the dog" to a collection "sveltekit-todos" in MongoDB Atlas using post method. I expect you to code the frontend index.svelte page sending the post request by yourself. 
```javascript
import clientPromise from '../../lib/mongodb-client'

export async function post (request) {
    const dbConnection = await clientPromise;
    const db = dbConnection.db();
    const collection = db.collection('sveltekit-todos');
    const todo = JSON.parse(request.body); // “Walk the dog”
    const newTodo = await collection.insertOne(todo);
    return {
        status: 200,
        body: {
            newTodo
        }
    }
}
```

If you open the index page of the project the developer’s tools console of the page should notify you that the  insertion was successful, like this:
```javascript
{"todos":{"acknowledged":true,"insertedId":"617fd886f......."}}
```

I hope this was helpful.