sequelize: defaultValue: Sequelize.UUIDV4 is not setting a default value on column in postgres

What you are doing?

"use strict";
module.exports = {
  up: async (queryInterface, Sequelize) => {
    await queryInterface.createTable("Test", {
      id: {
        allowNull: false,
        autoIncrement: false,
        primaryKey: true,
        type: Sequelize.UUID,
        defaultValue: Sequelize.UUIDV4,
      },
      name: {
        type: Sequelize.TEXT,
        defaultValue: "123",
      },
    });
  },
  down: async (queryInterface, Sequelize) => {
    await queryInterface.dropTable("Test");
  },
};

Checking the default column value with:

SELECT column_name, column_default
FROM information_schema.columns
WHERE (table_schema, table_name) = ('public', 'Currencies')
ORDER BY ordinal_position;

Gives me:

column_name column_default
id (NULL)
name ‘123’::text

What do you expect to happen?

default to be uuid_generate_v4() or gen_random_uuid()

What is actually happening?

default is (NULL)

Dialect: postgres Database version: 13.2 Sequelize CLI version: 6.2.0 Sequelize version: 6.2.2

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 20 (7 by maintainers)

Most upvoted comments

Summary of the solution here, to bump it up in search results for using an auto-generated UUID as a primary key in Postgres. For example, for an entity called Product, create your migration like this:

"use strict";
module.exports = {
  up: async (queryInterface, Sequelize) => {
    await queryInterface.createTable("Products", {
      id: {
        type: Sequelize.UUID,
        primaryKey: true,
        defaultValue: Sequelize.UUIDV4,
      },
      productName: {
        type: Sequelize.STRING,
      },
    });
  },
  down: async (queryInterface, Sequelize) => {
    await queryInterface.dropTable("Products");
  },
};

Then, create your model like this:

"use strict";
const { Model } = require("sequelize");
module.exports = (sequelize, DataTypes) => {
  class Product extends Model {
    static associate(models) {
      // associations
    }
  }
  Product.init(
    {
      id: {
        type: DataTypes.UUID,
        defaultValue: DataTypes.UUIDV4,
        primaryKey: true,
      },
      productName: DataTypes.STRING,
    },
    {
      sequelize,
      modelName: "Product",
    }
  );
  return Product;
};

now when you create a new instance of Product, you only need the productName field. The UUID is auto-generated by the Sequelize model.

const {
    Product
  } = require("./models");

const createProduct = async (name) => {
  const newProductData = { productName: "First product" };
  const creationResult = await Product.create(newProductData);
};

The id field in the model will trace the defaultValue setting back to the https://www.npmjs.com/package/uuid package that Sequelize relies on. As @Spekpannenkoek and @ephys have pointed out, Sequelize relies on that package to auto-generate the UUID as part of the model operation, not as part of native Postgres.

The other option in the case of Postgres specifically, would be to use its native uuid_generate_v4() function. The only issue there is, that function is not part of core Postgres, and thus is not loaded automatically in a default install of Postgres. You’d need to run this on your PostgreSQL instance first:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

This may or may not be possible, depending on what level of access you have to your DB. Thus, IMHO it’s best to keep the NPM uuid dependency, even if the native Postgres UUID option gets added. Maybe a config like this could be added?

dialectOptions: {
    // Your pg options here
    useNativeUUID: true
}

@SimonHausdorf I was facing same issue and tried this in a migration file

queryInterface.createTable(‘users’, { id: { type: Sequelize.UUID, defaultValue: Sequelize.literal(‘gen_random_uuid()’), // postgres will generate UUID by default I’m using version 15.1 primaryKey: true, }, });

I still want to add DataTypes.UUIDV4.NATIVE but in the meantime I’ve documented how to use uuid_generate_v4 in the new documentation (not yet released):

image

Of the three types of defaultValues (“A literal default value, a JavaScript function, or an SQL function”), in this case you’re passing a JavaScript function. Short of implementing PLv8, Sequelize has to generate the default value on the client side (your app) rather than in the database.

You ought to still get a default value when you insert a new record, just not one generated by your database & its definition would not be visible in the db schema.

While I haven’t tried it, I think you should be able to achieve what you want by setting a SQL function: defaultValue: sequelize.fn('uuid_generate_v4').

I don’t think that there is an implementation for the migration to set UUID as default in the database? I could not find anything about uuid_generate_v4() or gen_random_uuid() in the code? As it looks like, it can only be used in the model which then is generating a UUID.

  Test.init(
    {
      id: {
        allowNull: false,
        primaryKey: true,
        type: DataTypes.UUID,
        defaultValue: DataTypes.UUIDV4,
      },
      name: DataTypes.TEXT,
    },
    {
      sequelize,
      modelName: "Test",
    }
  );

defaultValue: DataTypes.UUIDV4 or defaultValue: Sequelize.UUIDV4 does not work for migrations. I think it should be possible to set the default type inside the migration as well?

@SimonHausdorf I’ve found the same issue but checking the source code I’ve found that perhaps the docs are incorrect. Instead of Sequelize.UUIDV4, it should be DataTypes.UUIDV4. Moreover, checking from the Typescript declaration files, it’s also pointing to DataTypes.UUIDV4. All of them bring me to the conclusion that the documentation is misled.

Refs: https://github.com/sequelize/sequelize/blob/9f950cbcbdd659d559496b77c40e0f827b108561/test/unit/utils.test.js#L45 https://github.com/sequelize/sequelize/blob/9f950cbcbdd659d559496b77c40e0f827b108561/test/integration/instance/increment.test.js#L27 https://github.com/sequelize/sequelize/blob/9f950cbcbdd659d559496b77c40e0f827b108561/types/lib/data-types.d.ts#L451

Not sure I can add anything more. If you want to use a defaultValue for UUID in migrations, you need to use the native SQL function (shown how above and here), otherwise you’ll need to manually set a value in JS

Well, probably not the best implementation, but i kinda solved this problem using beforeCreate hook in my sequelize model and getting UUID with crypto, like this:

this.addHook('beforeCreate', (user) => {
  user.uuid = crypto.randomUUID();
});

In Sequelize 7, you can now use sql.uuidV1 and sql.uuidV4. They set the default value on the database when possible, and fallback to JavaScript the rest of the time:

https://sequelize.org/docs/v7/models/data-types/#built-in-default-values-for-uuid

Hi 👋 I solved the same problem with Sequelize v16.9.1 and PostgreSQL v12 using the uuid-ossp extension and set the uuid_generate_v4 function as default value in the migration file and in the model with Sequelize.literal

Ex:

// migration file
'use strict';
module.exports = {
  up: async (queryInterface, Sequelize) => {
    await queryInterface.sequelize.query('CREATE EXTENSION IF NOT EXISTS "uuid-ossp";')
    await queryInterface.createTable('my_table', {
      id: {
        primaryKey: true,
        type: Sequelize.UUID,
        allowNull: false,
        defaultValue: Sequelize.literal('uuid_generate_v4()'),
      },
      data: {
        type: Sequelize.TEXT,
        allowNull: false,
      },
    });
  },
  down: async (queryInterface, Sequelize) => {
    await queryInterface.dropTable('my_table');
  },
};


// Model
module.exports = function (sequelize, DataTypes) {
  const MyTable = sequelize.define(
    'myTable',
    {
      id: {
        primaryKey: true,
        type: DataTypes.UUID,
        allowNull: false,
        defaultValue: sequelize.literal('uuid_generate_v4()'),
      },
      data: {
        type: DataTypes.TEXT,
        allowNull: false,
      },
    },
    {
      sequelize,
      tableName: 'myTable',
      schema: 'public',
    },
  );

  return MyTable;
};


// Controller 
const { myTable: MyTable } = require('../models');

module.exports = {
  create(req, res) {
    MyTable.create({ data: 'hello' })
      .then(x => res.status(200).send(x))
      .catch(err => res.status(400).send(err));
  },
};

DBeaver screenshots: Captura de pantalla 2023-10-06 a la(s) 16 59 24

Captura de pantalla 2023-10-06 a la(s) 17 00 36

only on migration file you need not using (all the 3 options not working):

  • defaultValue: fn(“uuid_generate_v4”)
  • defaultValue: DataTypes.UUIDV4
  • defaultValue: sequelize.UUIDV4

you need to remove this defaultValue from migration file only and if you are create rows on migration file then manually determine uuid value. for example:

import {v1 as uuidv1} from ‘uuid’; await query.bulkInsert({ tableName: ‘user’, schema }, [ {id: uuidv1(), name: “tom” }, {id: uuidv1(), name: “gil” }, ]);

This issue has been automatically marked as stale because it has been open for 7 days without activity. It will be closed if no further activity occurs. If this is still an issue, just leave a comment or remove the “stale” label. 🙂