DEV Community

Cover image for Connect to MongoDB Atlas from SvelteKit
kvetoslavnovak
kvetoslavnovak

Posted on • Updated on

Connect to MongoDB Atlas from SvelteKit

MongoDB Atlas recently published new best practices how to connect to MongoDB Atlas database. 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

npm init svelte@next SvelteKit_MongoDB_Atlas
cd SvelteKit_MongoDB_Atlas
npm install
npm run dev -- --open
Enter fullscreen mode Exit fullscreen mode

To communicate with MongoDB database we will need Node driver mongodb. So install it.

npm install mongodb
Enter fullscreen mode Exit fullscreen mode

I assume you have set up your MongoDB Atlas database. Their Starter Cluster is free. They have a clear tutorial 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:

MONGODB_URI = "mongodb+srv://<username>:<password>@cluster0....."
Enter fullscreen mode Exit fullscreen mode

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 under the hood. Vite has its own implementation of environmental variables. But it may be considered a little bit tricky.

So our project will need some other tool. Let install good old dotenv.

npm install dotenv
Enter fullscreen mode Exit fullscreen mode

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.

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"
Enter fullscreen mode Exit fullscreen mode

Finally we have arrived to the implementation of 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 lid directory (which is in a scr directory) create a new file mongodb-client.js. Copy inside the code adviced by MongoDB Atlas best practices but with a slight modification.

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
Enter fullscreen mode Exit fullscreen mode

You may have noticed that we made one very important modification concerning how we are referencing environmental variables:

process.env['MONGODB_URI'] // this works
process.env.MONGODB_URI //this does not work!!!
Enter fullscreen mode Exit fullscreen mode

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.

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);
    const newTodo = await collection.insertOne(todo);
    return {
        status: 200,
        body: {
            newTodo
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

If you open the index page of the project the page should notify you that the insertion was successful, like this:

{"todos":{"acknowledged":true,"insertedId":"617fd886f......."}}
Enter fullscreen mode Exit fullscreen mode

I hope this was helpful.

Discussion (4)

Collapse
kolosseo profile image
kolosseo

Thank you for the post. Anyway, I need to show two errors in the code:

  • I had to add async before client.connect() otherwise it didn't work.
  • dbConnection is undeclared. It has to be substituted with clientPromise (probably a typo).
Collapse
kvetoslavnovak profile image
kvetoslavnovak Author • Edited on

Thank you for your comment on typo. I have corrected it.
I did not need the async to have a working code but I guess it depends, the official documentation does not mention it.

Collapse
mawoka profile image
Mawoka

I am getting the error that global is not defined. Any idea why?

Collapse
kvetoslavnovak profile image
kvetoslavnovak Author • Edited on

I am not sure. When exactly are you getting this error?