diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/DataProvider/ProductDataProvider.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/DataProvider/ProductDataProvider.php
new file mode 100644
index 0000000000000..dbbb9d4caddaa
--- /dev/null
+++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/DataProvider/ProductDataProvider.php
@@ -0,0 +1,64 @@
+productResourceModel = $productResourceModel;
+ $this->productFactory = $productFactory;
+ }
+
+ /**
+ * Get list of products by IDs with full data set
+ *
+ * @param array $productIds
+ * @param array $attributeCodes
+ * @return ProductInterface[]|Product[]
+ */
+ public function getProductByIds(array $productIds, array $attributeCodes): array
+ {
+ $products = [];
+
+ foreach ($productIds as $productId) {
+ /** @var Product $product */
+ $product = $this->productFactory->create();
+ $this->productResourceModel->load($product, $productId, $attributeCodes);
+ $products[] = $product;
+ }
+
+ return $products;
+ }
+}
diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/DataProvider/ProductDataProviderInterface.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/DataProvider/ProductDataProviderInterface.php
new file mode 100644
index 0000000000000..c5a2aea864e20
--- /dev/null
+++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/DataProvider/ProductDataProviderInterface.php
@@ -0,0 +1,25 @@
+cacheTag, implode('_', $resolvedData['ids'])];
+ }
+}
diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/ProductsByID.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/ProductsByID.php
new file mode 100644
index 0000000000000..45aa2ae05b85d
--- /dev/null
+++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/ProductsByID.php
@@ -0,0 +1,70 @@
+productDataProvider = $productDataProvider;
+ $this->productFieldsSelector = $productFieldsSelector;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function resolve(
+ Field $field,
+ $context,
+ ResolveInfo $info,
+ array $value = null,
+ array $args = null
+ ) {
+ $productIds = ($args['ids'] ?? []);
+ $fields = $this->productFieldsSelector->getProductFieldsFromInfo($info);
+
+ /** @var \Magento\Catalog\Model\Product[] $products */
+ $products = $this->productDataProvider->getProductByIds($productIds, $fields);
+ $data = [];
+
+ foreach ($products as $product) {
+ $productData = $product->getData();
+ $productData['model'] = $product;
+ $data[] = $productData;
+ }
+
+ return $data;
+ }
+}
diff --git a/app/code/Magento/CatalogGraphQl/etc/di.xml b/app/code/Magento/CatalogGraphQl/etc/di.xml
index 5fec7bfd4fda7..8abd7e9ed14fe 100644
--- a/app/code/Magento/CatalogGraphQl/etc/di.xml
+++ b/app/code/Magento/CatalogGraphQl/etc/di.xml
@@ -74,4 +74,5 @@
+
diff --git a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls
index f77b301d61e28..15c48343ac5f7 100644
--- a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls
+++ b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls
@@ -10,6 +10,10 @@ type Query {
sort: ProductAttributeSortInput @doc(description: "Specifies which attributes to sort on, and whether to return the results in ascending or descending order.")
): Products
@resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Products") @doc(description: "The products query searches for products that match the criteria specified in the search and filter attributes.") @cache(cacheIdentity: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\Identity")
+ productsByID (
+ ids: [ID!]! @doc(description: "Product IDs.")
+ ): [ProductInterface]
+ @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\ProductsByID") @doc(description: "The productsByID query fetches products that match the specified IDs.") @cache(cacheIdentity: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductsByIdIdentity")
category (
id: Int @doc(description: "Id of the category.")
): CategoryTree