skip to Main Content

I am using Sequelize with Node.js and TypeScript to connect to a PostgreSQL database. I want to export and import a single Sequelize instance throughout my application, so that I have a single connection to the database.

I have seen many examples where the Sequelize instance is exported directly from a module, like this:

import { Sequelize } from "sequelize";
import { DB_HOST, DB_NAME, DB_PASSWORD, DB_PORT, DB_USERNAME } from ".";

export default new Sequelize(
  `postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}`
);

However, I am using a function to get the sequelize instance instead, like this:

import { Sequelize } from "sequelize";
import { DB_HOST, DB_NAME, DB_PASSWORD, DB_PORT, DB_USERNAME } from ".";
let sequelize: Sequelize;

const getDB = async () => {
  if (sequelize) return sequelize;
  try {
    sequelize = new Sequelize(
      `postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}`
    );
    await sequelize.authenticate();
    console.log(`PostgreSQL is connected to ${DB_HOST}:${DB_PORT}`);
    return sequelize;
  } catch (error) {
    console.error("Unable to connect to the database:", error);
  }
};

export default getDB;

I am doing this because I want to make sure that the sequelize instance is created only once and after the database connection is established. I also want to handle any errors that may occur during the connection.

Is this a good way to export and import a single sequelize instance in Node.js? Will this create a new instance every time I import it from another module? Or will it reuse the same instance that was created the first time?

For example, if I import and use the sequelize instance in another module like this:

import getDB from "./db";

const sequelize = await getDB();

const User = sequelize.define("User", { ... });

Will this create a new User model every time I import it? Or will it use the same User model that was defined the first time?

Any help or advice would be appreciated. Thank you.

2

Answers


  1. Chosen as BEST ANSWER

    I appreciate the explanations from @Seti and @Bergi, they helped me understand the concept of module caching in Node.js. To make it more clear for others who may have the same question, I want to share a simple example that illustrates how Node.js caches modules and exports only one instance of a value.

    Let's say we have a file called foo.js that exports a variable foo with the value of 1. The file also logs a message "new create" when it is executed.

    // foo.js
    let foo = 1;
    console.log("new create");
    module.exports = foo;
    

    Now, let's say we have another file called bar.js that imports the variable foo from foo.js four times using require.

    // bar.js
    const foo1 = require("./foo.js");
    const foo2 = require("./foo.js");
    const foo3 = require("./foo.js");
    const foo4 = require("./foo.js");
    

    If we run bar.js, we will see that the message "new create" is logged only once, even though we imported foo four times. This is because Node.js cached the module foo.js after the first time it was loaded, and returned the same instance of foo for every subsequent call to require. This means that we have only one instance of foo throughout our application, and we don't need to use a function to get it.

    I hope this example makes sense and helps someone who is looking for an answer to this question.


  2. There is not point in makeing this pattern of yours, as if you export anything from module, it becomes singleton of some sort (explained in documentation). Thats why all examples experted sequelize once, and all shared the same database


    Modules are cached after the first time they are loaded. This
    means (among other things) that every call to require(‘foo’) will get
    exactly the same object returned, if it would resolve to the same
    file.

    Provided require.cache is not modified, multiple calls to
    require(‘foo’) will not cause the module code to be executed multiple
    times. This is an important feature. With it, "partially done" objects
    can be returned, thus allowing transitive dependencies to be loaded
    even when they would cause cycles.

    To have a module execute code multiple times, export a function, and
    call that function.
    *

    Modules are cached based on their resolved filename. Since modules may
    resolve to a different filename based on the location of the calling
    module (loading from node_modules folders), it is not a guarantee that
    require(‘foo’) will always return the exact same object, if it would
    resolve to different files.

    Additionally, on case-insensitive file systems or operating systems,
    different resolved filenames can point to the same file, but the cache
    will still treat them as different modules and will reload the file
    multiple times. For example, require(‘./foo’) and require(‘./FOO’)
    return two different objects, irrespective of whether or not ./foo and
    ./FOO are the same file.

    Source: https://nodejs.org/api/modules.html

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search