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
To communicate with MongoDB database we will need Node driver mongodb. So install it.
npm install mongodb
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....."
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
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"
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 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
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!!!
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.
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:
{"todos":{"acknowledged":true,"insertedId":"617fd886f......."}}
I hope this was helpful.
Top comments (10)
I am getting the error that
global is not defined
. Any idea why?I am not sure. When exactly are you getting this error?
I encountered the same problem. It turns out I was doing the mongodb import in a Svelte component, where
global
is not present. It works fine in a JS endpoint — which is where it would go in a real app.Sure thing, never connect directly to your database from the client. That would be really dangerous practice.
Thank you for the post. Anyway, I need to show two errors in the code:
async
beforeclient.connect()
otherwise it didn't work.dbConnection
is undeclared. It has to be substituted withclientPromise
(probably a typo).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.
Thanks for the tutorial,
where is the lid and scr directory ?
These folders are part of a default standard SvelteKit directories structure. You may check a documentation here:
kit.svelte.dev/docs/modules#$lib
Some comments may only be visible to logged-in visitors. Sign in to view all comments.