diff --git a/doc/user/project/repository/code_suggestions/repository_xray.md b/doc/user/project/repository/code_suggestions/repository_xray.md
index 5d5ce745cd286286177869a0ffe0098bf58c35b2..d77dddab18d1053d1bae2e70dd351ec2123c1856 100644
--- a/doc/user/project/repository/code_suggestions/repository_xray.md
+++ b/doc/user/project/repository/code_suggestions/repository_xray.md
@@ -37,22 +37,22 @@ The Repository X-Ray service is automatically enabled if:
 
 The Repository X-Ray searches a maximum of two directory levels from the repository's root. For example, it supports `Gemfile.lock`, `api/Gemfile.lock`, or `api/client/Gemfile.lock`, but not `api/v1/client/Gemfile.lock`. For each language, only the first matching configuration file is processed. Where available, lock files take precedence over their non-lock file counterparts.
 
-| Language   | Package manager | Configuration file               | GitLab version |
-| ---------- |-----------------| -------------------------------- | -------------- |
-| C/C++      | Conan           | `conanfile.py`                   | 17.5 or later  |
-| C/C++      | Conan           | `conanfile.txt`                  | 17.5 or later  |
-| C/C++      | vcpkg           | `vcpkg.json`                     | 17.5 or later  |
-| C#         | NuGet           | `*.csproj`                       | 17.5 or later  |
-| Go         | Go Modules      | `go.mod`                         | 17.4 or later  |
-| Java       | Gradle          | `build.gradle`                   | 17.4 or later  |
-| Java       | Maven           | `pom.xml`                        | 17.4 or later  |
-| JavaScript | NPM             | `package-lock.json`              | 17.5 or later  |
-| Kotlin     | Gradle          | `build.gradle.kts`               | 17.5 or later  |
-| PHP        | Composer        | `composer.lock`, `composer.json` | 17.5 or later  |
-| Python     | Conda           | `environment.yml`                | 17.5 or later  |
-| Python     | Pip             | `requirements.txt`               | 17.5 or later  |
-| Python     | Poetry          | `poetry.lock`, `pyproject.toml`  | 17.5 or later  |
-| Ruby       | RubyGems        | `Gemfile.lock`                   | 17.4 or later  |
+| Language   | Package manager | Configuration file                   | GitLab version |
+| ---------- |-----------------| ------------------------------------ | -------------- |
+| C/C++      | Conan           | `conanfile.py`                       | 17.5 or later  |
+| C/C++      | Conan           | `conanfile.txt`                      | 17.5 or later  |
+| C/C++      | vcpkg           | `vcpkg.json`                         | 17.5 or later  |
+| C#         | NuGet           | `*.csproj`                           | 17.5 or later  |
+| Go         | Go Modules      | `go.mod`                             | 17.4 or later  |
+| Java       | Gradle          | `build.gradle`                       | 17.4 or later  |
+| Java       | Maven           | `pom.xml`                            | 17.4 or later  |
+| JavaScript | NPM             | `package-lock.json`, `package.json`  | 17.5 or later  |
+| Kotlin     | Gradle          | `build.gradle.kts`                   | 17.5 or later  |
+| PHP        | Composer        | `composer.lock`, `composer.json`     | 17.5 or later  |
+| Python     | Conda           | `environment.yml`                    | 17.5 or later  |
+| Python     | Pip             | `requirements.txt`                   | 17.5 or later  |
+| Python     | Poetry          | `poetry.lock`, `pyproject.toml`      | 17.5 or later  |
+| Ruby       | RubyGems        | `Gemfile.lock`                       | 17.4 or later  |
 
 ## Enable Repository X-Ray in your CI pipeline (deprecated)
 
diff --git a/ee/lib/ai/context/dependencies/config_files/constants.rb b/ee/lib/ai/context/dependencies/config_files/constants.rb
index 5cb1324c8abf10ac772913a01eb32b22bdf65087..760e549b45df93bc6f17f6fec9fae4ee74bd2977 100644
--- a/ee/lib/ai/context/dependencies/config_files/constants.rb
+++ b/ee/lib/ai/context/dependencies/config_files/constants.rb
@@ -27,6 +27,7 @@ module Constants
             ConfigFiles::JavaGradle,
             ConfigFiles::JavaMaven,
             ConfigFiles::JavascriptNpmLock,
+            ConfigFiles::JavascriptNpm,
             ConfigFiles::KotlinGradle,
             ConfigFiles::PhpComposerLock,
             ConfigFiles::PhpComposer,
diff --git a/ee/lib/ai/context/dependencies/config_files/javascript_npm.rb b/ee/lib/ai/context/dependencies/config_files/javascript_npm.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b06cd5ab2da2ccb24520e03d743b4076ca6a1654
--- /dev/null
+++ b/ee/lib/ai/context/dependencies/config_files/javascript_npm.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+module Ai
+  module Context
+    module Dependencies
+      module ConfigFiles
+        class JavascriptNpm < Base
+          def self.file_name_glob
+            'package.json'
+          end
+
+          def self.lang_name
+            'JavaScript'
+          end
+
+          private
+
+          ### Example format:
+          # "dependencies": {
+          #   "all-the-cities": "3.1.0",
+          #   "argon2": "0.41.1",
+          #   "countly-request": "file:api/utils/countly-request"
+          # },
+          # "devDependencies": {
+          #   "apidoc": "^1.0.1",
+          #   "apidoc-template": "^0.0.2"
+          # },
+          #
+          def extract_libs
+            parsed = ::Gitlab::Json.parse(content)
+
+            %w[dependencies devDependencies].flat_map do |key|
+              dig_in(parsed, key).try(:map) do |name, version|
+                # skip dependency if the version is a filepath
+                next if version.include?('/')
+
+                Lib.new(name: name, version: version)
+              end
+            end.compact
+          rescue JSON::ParserError
+            raise ParsingError, 'content is not valid JSON'
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/ee/spec/lib/ai/context/dependencies/config_files/javascript_npm_spec.rb b/ee/spec/lib/ai/context/dependencies/config_files/javascript_npm_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..67b8569406d055e0083dc78e691f8e8520dfdf65
--- /dev/null
+++ b/ee/spec/lib/ai/context/dependencies/config_files/javascript_npm_spec.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ai::Context::Dependencies::ConfigFiles::JavascriptNpm, feature_category: :code_suggestions do
+  it 'returns the expected language value' do
+    expect(described_class.lang).to eq('javascript')
+  end
+
+  it_behaves_like 'parsing a valid dependency config file' do
+    let(:config_file_content) do
+      <<~JSON
+        {
+          "name": "countly-server",
+          "version": "24.5.0",
+          "dependencies": {
+            "all-the-cities": "3.1.0",
+            "argon2": "0.41.1",
+            "countly-request": "file:api/utils/countly-request"
+          }
+        }
+      JSON
+    end
+
+    let(:expected_formatted_lib_names) do
+      ['all-the-cities (3.1.0)', 'argon2 (0.41.1)']
+    end
+  end
+
+  context 'when the content contains dev dependencies' do
+    it_behaves_like 'parsing a valid dependency config file' do
+      let(:config_file_content) do
+        <<~JSON
+          {
+            "name": "countly-server",
+            "version": "24.5.0",
+            "devDependencies": {
+              "apidoc": "^1.0.1"
+            },
+            "dependencies": {
+              "all-the-cities": "3.1.0",
+              "argon2": "0.41.1",
+              "countly-request": "file:api/utils/countly-request"
+            }
+          }
+        JSON
+      end
+
+      let(:expected_formatted_lib_names) do
+        ['apidoc (^1.0.1)', 'all-the-cities (3.1.0)', 'argon2 (0.41.1)']
+      end
+    end
+  end
+
+  it_behaves_like 'parsing an invalid dependency config file' do
+    let(:expected_parsing_error_message) { 'content is not valid JSON' }
+  end
+
+  describe '.matches?' do
+    using RSpec::Parameterized::TableSyntax
+
+    where(:path, :matches) do
+      'package.json'             | true
+      'dir/package.json'         | true
+      'dir/subdir/package.json'  | true
+      'dir/package-lock.json'    | false
+      'Package.json'             | false
+      'package_json'             | false
+    end
+
+    with_them do
+      it 'matches the file name glob pattern at various directory levels' do
+        expect(described_class.matches?(path)).to eq(matches)
+      end
+    end
+  end
+end