diff --git a/db/migrate/20240318160548_add_usage_count_to_catalog_resources.rb b/db/migrate/20240318160548_add_usage_count_to_catalog_resources.rb
new file mode 100644
index 0000000000000000000000000000000000000000..cec7b725cd7c485977a3fde1adafce70369922f7
--- /dev/null
+++ b/db/migrate/20240318160548_add_usage_count_to_catalog_resources.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class AddUsageCountToCatalogResources < Gitlab::Database::Migration[2.2]
+  milestone '16.11'
+
+  def change
+    add_column :catalog_resources, :last_30_day_usage_count, :integer, null: false, default: 0
+    add_column :catalog_resources, :last_30_day_usage_count_updated_at, :datetime_with_timezone,
+      null: false, default: '1970-01-01'
+  end
+end
diff --git a/db/migrate/20240318160612_add_usage_count_to_catalog_resource_components.rb b/db/migrate/20240318160612_add_usage_count_to_catalog_resource_components.rb
new file mode 100644
index 0000000000000000000000000000000000000000..56ef3c2a9268f26de8b88ead8130bcf96ef3ea07
--- /dev/null
+++ b/db/migrate/20240318160612_add_usage_count_to_catalog_resource_components.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class AddUsageCountToCatalogResourceComponents < Gitlab::Database::Migration[2.2]
+  milestone '16.11'
+
+  def change
+    add_column :catalog_resource_components, :last_30_day_usage_count, :integer, null: false, default: 0
+    add_column :catalog_resource_components, :last_30_day_usage_count_updated_at, :datetime_with_timezone,
+      null: false, default: '1970-01-01'
+  end
+end
diff --git a/db/schema_migrations/20240318160548 b/db/schema_migrations/20240318160548
new file mode 100644
index 0000000000000000000000000000000000000000..9e0357d3d7f76035a4866abe1b03cfc20e69a365
--- /dev/null
+++ b/db/schema_migrations/20240318160548
@@ -0,0 +1 @@
+98454d2080cba05c35033694887f7dbb68965015e19e323e35b48bf6b1c0c893
\ No newline at end of file
diff --git a/db/schema_migrations/20240318160612 b/db/schema_migrations/20240318160612
new file mode 100644
index 0000000000000000000000000000000000000000..5e155659baf78f4068c0de8c3cd84643bca63eb2
--- /dev/null
+++ b/db/schema_migrations/20240318160612
@@ -0,0 +1 @@
+77f42280c79176fa52da6f202067dc67128c2f3fa384d1d84624938312325fc7
\ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index cc2f400de2eec535bfd3f6c070d0c062c5a7218f..582e2d1f2e927302677322d74b3465eb4c4c84c0 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -5649,6 +5649,8 @@ CREATE TABLE catalog_resource_components (
     name text NOT NULL,
     path text,
     spec jsonb DEFAULT '{}'::jsonb NOT NULL,
+    last_30_day_usage_count integer DEFAULT 0 NOT NULL,
+    last_30_day_usage_count_updated_at timestamp with time zone DEFAULT '1970-01-01 00:00:00+00'::timestamp with time zone NOT NULL,
     CONSTRAINT check_a76bfd47fe CHECK ((char_length(path) <= 255)),
     CONSTRAINT check_ddca729980 CHECK ((char_length(name) <= 255))
 );
@@ -5695,7 +5697,9 @@ CREATE TABLE catalog_resources (
     description text,
     visibility_level integer DEFAULT 0 NOT NULL,
     search_vector tsvector GENERATED ALWAYS AS ((setweight(to_tsvector('english'::regconfig, (COALESCE(name, ''::character varying))::text), 'A'::"char") || setweight(to_tsvector('english'::regconfig, COALESCE(description, ''::text)), 'B'::"char"))) STORED,
-    verification_level smallint DEFAULT 0
+    verification_level smallint DEFAULT 0,
+    last_30_day_usage_count integer DEFAULT 0 NOT NULL,
+    last_30_day_usage_count_updated_at timestamp with time zone DEFAULT '1970-01-01 00:00:00+00'::timestamp with time zone NOT NULL
 );
 
 CREATE SEQUENCE catalog_resources_id_seq