diff --git a/dotCMS/src/main/java/com/dotmarketing/startup/runonce/Task241007CreateUniqueFieldsTable.java b/dotCMS/src/main/java/com/dotmarketing/startup/runonce/Task241007CreateUniqueFieldsTable.java
new file mode 100644
index 000000000000..78ffb94785ec
--- /dev/null
+++ b/dotCMS/src/main/java/com/dotmarketing/startup/runonce/Task241007CreateUniqueFieldsTable.java
@@ -0,0 +1,226 @@
+package com.dotmarketing.startup.runonce;
+
+import com.dotcms.content.elasticsearch.business.ESContentletAPIImpl;
+import com.dotcms.contenttype.model.field.Field;
+import com.dotcms.notifications.bean.NotificationType;
+import com.dotcms.util.JsonUtil;
+import com.dotmarketing.business.APILocator;
+import com.dotmarketing.common.db.DotConnect;
+import com.dotmarketing.common.db.DotDatabaseMetaData;
+import com.dotmarketing.common.db.Params;
+import com.dotmarketing.db.DbConnectionFactory;
+import com.dotmarketing.exception.DotDataException;
+import com.dotmarketing.exception.DotRuntimeException;
+import com.dotmarketing.startup.StartupTask;
+import com.dotmarketing.util.Logger;
+import com.dotmarketing.util.StringUtils;
+import com.dotmarketing.util.UtilMethods;
+import com.liferay.util.StringPool;
+import io.vavr.control.Try;
+import org.jetbrains.annotations.NotNull;
+import org.postgresql.util.PGobject;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.sql.Array;
+import java.sql.SQLException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static com.dotcms.util.CollectionsUtils.list;
+
+/**
+ * Task Upgrade to Create/populate the unique_fields Table for Unique Field Validation
+ *
+ * This introduces a new table, unique_fields, which will be used to validate fields that must be unique.
+ *
+ * Table Structure
+ *
+ *
+ * CREATE TABLE unique_fields (
+ * unique_key_val VARCHAR(64) PRIMARY KEY,
+ * supporting_values JSONB
+ * );
+ *
+ *
+ * - unique_key_val: This field will store a hash created from a combination of the following:
+ *
+ * Content type ID
+ * Field variable name
+ * Field value
+ * Language
+ * Host ID (if the uniquePerSite option is enabled)
+ *
+ * - supporting_values: This field contains a JSON object with the following format:
+ *
+ *
+ * {
+ * "contentTypeID": "",
+ * "fieldVariableName": "",
+ * "fieldValue": "",
+ * "languageId": "",
+ * "hostId": "",
+ * "uniquePerSite": true|false,
+ * "contentletsId": [...]
+ * }
+ *
+ *
+ * The contentletsId array holds the IDs of contentlets with the same field value that existed before the database was upgraded.
+ * After the upgrade, no more contentlets with duplicate values will be allowed.
+ *
+ * Additional Details
+ *
+ *- The Host ID is included in the hash calculation only if the uniquePerSite field variable is enabled.
+ *- The unique_key_val field ensures that only truly unique values can be inserted moving forward.
+ *- This upgrade task also populates the unique_fields table with the existing unique field values from the current database.
+ */
+public class Task241007CreateUniqueFieldsTable implements StartupTask {
+
+ private final static String CREATE_TABLE_QUERY = "CREATE TABLE IF NOT EXISTS unique_fields (" +
+ "unique_key_val VARCHAR(64) PRIMARY KEY," +
+ "supporting_values JSONB" +
+ " )";
+
+ private static final String RETRIVE_UNIQUE_FIELD_VALUES_QUERY = "SELECT structure.inode AS content_type_id," +
+ " field.velocity_var_name AS field_var_name," +
+ " contentlet.language_id AS language_id," +
+ " identifier.host_inode AS host_id," +
+ " jsonb_extract_path_text(contentlet_as_json -> 'fields', field.velocity_var_name)::jsonb ->> 'value' AS field_value," +
+ " ARRAY_AGG(contentlet.identifier) AS contentlet_identifier" +
+ " FROM contentlet" +
+ " INNER JOIN structure ON structure.inode = contentlet.structure_inode" +
+ " INNER JOIN field ON structure.inode = field.structure_inode" +
+ " INNER JOIN identifier ON contentlet.identifier = identifier.id" +
+ " WHERE jsonb_extract_path_text(contentlet_as_json->'fields', field.velocity_var_name) IS NOT NULL AND " +
+ " field.unique_ = true " +
+ " GROUP BY structure.inode," +
+ " field.velocity_var_name ," +
+ " contentlet.language_id," +
+ " identifier.host_inode," +
+ " jsonb_extract_path_text(contentlet_as_json -> 'fields', field.velocity_var_name)::jsonb ->> 'value'";
+ private static final String INSERT_UNIQUE_FIELDS_QUERY = "INSERT INTO unique_fields(unique_key_val, supporting_values) VALUES(?, ?)";
+
+ @Override
+ public boolean forceRun() {
+ try {
+ final DotDatabaseMetaData databaseMetaData = new DotDatabaseMetaData();
+ return !databaseMetaData.tableExists(DbConnectionFactory.getConnection(), "unique_fields");
+ } catch (SQLException e) {
+ Logger.error(this, e.getMessage(),e);
+ return false;
+ }
+ }
+
+ @Override
+ public void executeUpgrade() throws DotDataException, DotRuntimeException {
+
+ if (forceRun()) {
+ createUniqueFieldTable();
+
+ try {
+ populate();
+ } catch (SQLException e) {
+ throw new DotDataException(e);
+ }
+ }
+ }
+
+ /**
+ * Populate the unique_fields table with the Unique Fields values
+ *
+ * @throws DotDataException
+ * @throws SQLException
+ */
+ private void populate() throws DotDataException, SQLException {
+ final List