Skip to content

feat(product): add SKU search support to admin API#13930

Open
bqst wants to merge 4 commits intomedusajs:developfrom
bqst:feat/product-sku-search
Open

feat(product): add SKU search support to admin API#13930
bqst wants to merge 4 commits intomedusajs:developfrom
bqst:feat/product-sku-search

Conversation

@bqst
Copy link
Copy Markdown
Contributor

@bqst bqst commented Oct 31, 2025

Summary

What — What changes are introduced in this PR?

This PR adds the ability to search products by their variant SKU through the admin /admin/products endpoint using the q query parameter. Products can now be found by searching for exact or partial SKU matches across all product variants.
Note: This feature was available in Medusa v1 but was missing in v2, causing friction for users migrating from v1 or integrating with external systems.

Why — Why are these changes relevant or necessary?

Critical for WMS/ERP Integration and Internal Operations:

  • Warehouse Management Systems (WMS) and ERP applications typically work with SKUs as the primary product identifier for inventory management, order fulfillment, and stock tracking
  • Admin comboboxes and autocomplete need to support SKU-based lookups for efficient product selection during order creation, inventory adjustments, and fulfillment operations
  • Customer service representatives need to quickly locate products by SKU when handling customer inquiries or processing orders
  • Inventory managers need to search by SKU when receiving shipments, conducting audits, or managing stock levels
  • v1 to v2 migration: Users migrating from Medusa v1 expect this functionality to work as it did before

How — How have these changes been implemented?

The implementation leverages Medusa's existing free text search infrastructure:

  1. Product Model (packages/modules/product/src/models/product.ts):

    • Marked the variants relationship as .searchable() to enable search traversal into product variants
  2. Product Module Service (packages/modules/product/src/services/product-module-service.ts):

    • Added FreeTextSearchFilterKeyPrefix import
    • Applied free text search filter in listProducts() method when q parameter is present
    • Applied free text search filter in listAndCountProducts() method when q parameter is present
    • The implementation uses the same pattern as other searchable entities (e.g., ProductCategory)
  3. Search Behavior:

    • Searches across product fields (title, subtitle, description) AND variant fields (SKU, title, barcode, EAN, UPC)
    • Returns the complete product (with all variants) when any variant's SKU matches
    • Supports partial matching: ?q=ABC will find "ABC-123", "TEST-ABC-XYZ", etc.
    • Case-insensitive matching
    • Uses database-level full-text search for optimal performance

Testing — How have these changes been tested, or how can the reviewer test the feature?

Comprehensive integration tests have been added in integration-tests/http/__tests__/product/admin/product-sku-search.spec.ts:

All 6 tests passing:

  • ✅ Exact SKU match
  • ✅ Partial SKU match
  • ✅ Multi-variant products (returns full product when one variant matches)
  • ✅ Combined search (works for both product title AND variant SKU)
  • ✅ Non-existent SKU (correctly returns empty results)
  • ✅ Case-insensitive search

To test manually:

# Search by exact SKU
GET /admin/products?q=SKU-123

# Search by partial SKU
GET /admin/products?q=SKU

# Combined with other filters
GET /admin/products?q=SKU-123&status=published&limit=10

Checklist

Please ensure the following before requesting a review:

  • I have added a changeset for this PR
    • Every non-breaking change should be marked as a patch
    • To add a changeset, run yarn changeset and follow the prompts
  • The changes are covered by relevant tests
  • I have verified the code works as intended locally
  • I have linked the related issue(s) if applicable

Additional Context

  • No breaking changes - this is a backward-compatible enhancement
  • No new dependencies required
  • Performance impact is minimal as it uses existing indexed fields
  • Works seamlessly with existing pagination, filtering, and sorting parameters
  • Restores feature parity with Medusa v1

Note

Medium Risk
Changes product listing query behavior by introducing free-text search traversal across variants, which may affect result sets and query performance on large catalogs; covered by integration tests.

Overview
Adds support for free-text searching products by variant SKU (and other searchable variant fields) via the admin GET /admin/products?q=... endpoint by wiring q into the module’s free-text search filter.

This marks the Product.variants relation as .searchable() to allow search traversal into variants, and updates listProducts/listAndCountProducts to translate filters.q into a FreeTextSearchFilterKeyPrefix + Product filter (removing q from the remaining filters). Integration tests are added to cover exact/partial SKU matching, multi-variant results, combined title+SKU search, non-matches, and case-insensitivity.

Written by Cursor Bugbot for commit e024914. This will update automatically on new commits. Configure here.

@bqst bqst requested a review from a team as a code owner October 31, 2025 15:15
@vercel
Copy link
Copy Markdown

vercel bot commented Oct 31, 2025

@bqst is attempting to deploy a commit to the medusajs Team on Vercel.

A member of the Team first needs to authorize it.

cursor[bot]

This comment was marked as outdated.

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Oct 31, 2025

🦋 Changeset detected

Latest commit: e024914

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 74 packages
Name Type
@medusajs/product Patch
integration-tests-http Patch
@medusajs/medusa Patch
@medusajs/test-utils Patch
@medusajs/medusa-oas-cli Patch
@medusajs/analytics Patch
@medusajs/api-key Patch
@medusajs/auth Patch
@medusajs/caching Patch
@medusajs/cart Patch
@medusajs/currency Patch
@medusajs/customer Patch
@medusajs/file Patch
@medusajs/fulfillment Patch
@medusajs/index Patch
@medusajs/inventory Patch
@medusajs/link-modules Patch
@medusajs/locking Patch
@medusajs/notification Patch
@medusajs/order Patch
@medusajs/payment Patch
@medusajs/pricing Patch
@medusajs/promotion Patch
@medusajs/region Patch
@medusajs/sales-channel Patch
@medusajs/settings Patch
@medusajs/stock-location Patch
@medusajs/store Patch
@medusajs/tax Patch
@medusajs/user Patch
@medusajs/workflow-engine-inmemory Patch
@medusajs/workflow-engine-redis Patch
@medusajs/draft-order Patch
@medusajs/oas-github-ci Patch
@medusajs/cache-inmemory Patch
@medusajs/cache-redis Patch
@medusajs/event-bus-local Patch
@medusajs/event-bus-redis Patch
@medusajs/analytics-local Patch
@medusajs/analytics-posthog Patch
@medusajs/auth-emailpass Patch
@medusajs/auth-github Patch
@medusajs/auth-google Patch
@medusajs/caching-redis Patch
@medusajs/file-local Patch
@medusajs/file-s3 Patch
@medusajs/fulfillment-manual Patch
@medusajs/locking-postgres Patch
@medusajs/locking-redis Patch
@medusajs/notification-local Patch
@medusajs/notification-sendgrid Patch
@medusajs/payment-stripe Patch
@medusajs/core-flows Patch
@medusajs/framework Patch
@medusajs/js-sdk Patch
@medusajs/modules-sdk Patch
@medusajs/orchestration Patch
@medusajs/types Patch
@medusajs/utils Patch
@medusajs/workflows-sdk Patch
@medusajs/cli Patch
@medusajs/deps Patch
@medusajs/telemetry Patch
@medusajs/admin-bundler Patch
@medusajs/admin-sdk Patch
@medusajs/admin-shared Patch
@medusajs/admin-vite-plugin Patch
@medusajs/dashboard Patch
@medusajs/icons Patch
@medusajs/toolbox Patch
@medusajs/ui-preset Patch
create-medusa-app Patch
medusa-dev-cli Patch
@medusajs/ui Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Dec 7, 2025

This PR is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

@github-actions github-actions bot added the Stale label Dec 7, 2025
@bqst
Copy link
Copy Markdown
Contributor Author

bqst commented Dec 8, 2025

unstale

@github-actions github-actions bot removed the Stale label Dec 9, 2025
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Jan 8, 2026

This PR is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

@github-actions github-actions bot added the Stale label Jan 8, 2026
@bqst
Copy link
Copy Markdown
Contributor Author

bqst commented Jan 8, 2026

unstale

@github-actions github-actions bot removed the Stale label Jan 12, 2026
@github-actions
Copy link
Copy Markdown
Contributor

This PR is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

@github-actions github-actions bot added the Stale label Feb 11, 2026
@github-actions
Copy link
Copy Markdown
Contributor

This PR was closed because it has been stalled for 5 days with no activity.

@github-actions github-actions bot closed this Feb 17, 2026
@NicolasGorga NicolasGorga reopened this Feb 20, 2026
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

This is the final PR Bugbot will review for you during this billing cycle

Your free Bugbot reviews will reset on March 17

Details

Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

fromEntity: Product.name,
}
delete filters.q
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant free text search filter duplicates base service logic

Low Severity

The manually added free text search filter logic in listProducts and listAndCountProducts is entirely redundant. The underlying this.productService_.list() and this.productService_.listAndCount() already call applyFreeTextSearchFilter(filters, config) in the base MedusaInternalService, which performs the identical operation — checking filters.q, adding the same FreeTextSearchFilterKeyPrefix + model.name filter to config.filters, and deleting filters.q. The only change actually needed for SKU search is the .searchable() annotation on the variants relationship in the model. This duplication increases maintenance burden and risks divergence if the base service logic changes.

Additional Locations (1)

Fix in Cursor Fix in Web

@github-actions github-actions bot removed the Stale label Feb 23, 2026
@medusa-os-bot
Copy link
Copy Markdown

medusa-os-bot bot commented Apr 9, 2026

Thank you for your contribution!

After reviewing this PR, we need a few things addressed before we can move forward:

Required changes:

  • Please open a GitHub issue describing the problem (SKU search missing from admin API in v2) and link it here with a closing keyword (e.g. Closes #<issue_number>). Non-trivial code contributions require a linked issue per our contribution guidelines.

Notes:

Marking variants as .searchable() means the q parameter will search across all variant searchable fields — sku, title, barcode, ean, and upc — not just SKU. This is broader than what the PR title describes. Depending on team intent, this may be fine or may need to be scoped down. Worth confirming before merge.

The implementation pattern follows product-category.ts correctly, integration tests are comprehensive, and the changeset is included.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants