Search for Parts ⋅ tscircuit ⋅ discord
This is an in-stock parts search engine for JLCPCB parts. It also features an easy-to-use API (just add ".json" to your URL on any page)
Play with it at jlcsearch.tscircuit.com
You can go on any page and click "json" in the top right corner to automatically convert whatever filter you've made to a JSON query.
curl https://jlcsearch.tscircuit.com/resistors/list.json?package=&resistance=1k
# {
# "resistors": [
# {
# "lcsc": 21190,
# "mfr": "0603WAF1001T5E",
# "package": "0603",
# "resistance": 1000,
# "tolerance_fraction": 0.01,
# "power_watts": 100,
# "stock": 31485061,
# "price1": 0.000814286
# },
# {
# "lcsc": 11702,
# "mfr": "0402WGF1001TCE",
# "package": "0402",
# "resistance": 1000,
# ...Look up a generated tscircuit footprinter string by numeric or C-prefixed
LCSC number:
curl https://jlcsearch.tscircuit.com/api/footprinter_strings/C2906861
# {
# "component_footprinter_details": {
# "lcsc": 2906861,
# "footprinter_string": "sod723_p0.865mm_pw0.54mm_pl0.57mm",
# "copper_iou": 0.9923751612092405,
# "updated_at": "2026-08-12 04:34:12"
# }
# }A 200 response with a null footprinter_string means the component was
processed without a match above 95% copper IoU. A 404 means the component has
not been processed yet.
Fetch raw EasyEDA component JSON through the shared R2-backed cache:
curl https://jlcsearch.tscircuit.com/api/easyeda_components/C2906861
# {
# "easyeda_component_details": {
# "lcsc": 2906861,
# "easyeda_uuid": "...",
# "fetched_at": "2026-08-13T16:00:00.000Z",
# "easyeda_json": { "...": "..." }
# }
# }The endpoint normalizes numeric and C-prefixed LCSC numbers. It serves fresh
objects from the shared R2 bucket and fills missing objects from EasyEDA.
Successful payloads are refreshed after 90 days; definitive not-found results
are negative-cached for six hours. Callers that only want an existing object
can add ?cache_only=true; a cache_miss response never contacts EasyEDA.
The x-cache response header reports R2-HIT, R2-MISS, or R2-STALE.
Bun is required. Install dependencies for both the data pipeline and Cloudflare worker:
bun install
bun install --cwd cf-proxyRun bun start to start the Cloudflare worker locally. The production site is
implemented entirely in cf-proxy; there is no separate origin web server.
To add a component page:
- Add or update its derived-table definition in
lib/db/derivedtables. - Register the table in
cf-proxy/scripts/sync-db.shso it is copied to D1. - Add the D1 type, filter configuration, route mapping, response key, and page
label under
cf-proxy/src. - Add worker rendering and route tests under
cf-proxy/test. - Run
bun run format,bunx tsc --noEmit --project cf-proxy/tsconfig.json, andbun run test --cwd cf-proxy.
Use bun deploy to apply pending D1 schema migrations and then publish the
worker. Use cf-proxy/scripts/sync-db.sh to rebuild and synchronize derived
table data from a prepared local SQLite database.
Production D1 data is populated by the Build and Sync D1 GitHub Actions
workflow. Every night at 05:00 UTC, after the upstream jlcparts refresh, it
performs a stock_only sync and clears the production response cache. The
stock-only path updates changed values in component_catalog and search_index
without rebuilding either table or the FTS index. Its compact stock snapshot
also sets recently removed parts to zero instead of leaving stale quantities.
API clients are instructed to revalidate within 24 hours so the nightly stock
snapshot is not hidden by an older response. On relevant merges to main, the
workflow
downloads the current upstream source-db-v2 database, builds and verifies a
compact db.sqlite3 containing the requested derived tables, applies D1
migrations, uploads those tables, and refreshes the affected production API
cache. Transient Cloudflare failures during migrations or upload are retried
per D1 command with incremental delays. Upload batches are
idempotent, so a lost import-status response can be retried without duplicating
rows or restarting completed work. Full-catalog uploads use 1,000-row batches
for catalog tables, 5,000-row batches for FTS, up to six attempts per D1
command, and a three-hour job timeout so the component catalog and search index
can finish before the next upstream refresh. The workflow can also be run
manually in derived, stock_only, or full_catalog mode. derived accepts a
comma-separated derived_tables input. stock_only performs the same in-place
stock refresh used by the nightly schedule. full_catalog rebuilds and uploads
the component catalog, search index, and FTS index from the current source-db-v2
snapshot. Catalog and stock syncs require a numeric smoke_test_lcsc whose
remote stock must match the prepared source database. All modes accept an
optional cache_bust_url. The workflow requires the
CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN repository secrets.
The manually dispatched Populate footprinter strings workflow processes the highest-stock unindexed components first for up to four hours by default. It runs eight component conversions concurrently and probes the shared EasyEDA R2 cache before any upstream request. Cache misses are limited to two component fills per second, or about four EasyEDA requests per second. An EasyEDA 403 pauses all fills for two minutes and lowers the rest of that run to one fill per second. Production D1 reads and writes are batched, and the final log reports R2 hits and misses, fill, conversion, D1, and CPU timing metrics.
As a developer new to this codebase, or a curious user, you may have some questions about the flow of data through the scripts and automations inside this repo. It all starts with the jlcparts project, which compiles a massive 11GB sqlite3 database of everything JLCPCB has to offer. As you can imagine, this would be very resource-intensive and slow to search, so the next steps are scripts that optimize it heavily, although it's more accurate to say that they rebuild it entirely.
scripts/setup-db-optimizations.ts and scripts/setup-derived-tables.ts show the various optimizations that are performed, including:
- Removing stale components that haven't been in stock for over a year.
- Only keeping categories of components that we are currently interested in and have a schema defined for (see the corresponding component types in
lib/db/derivedtablesfor examples). - Adding columns for traits that we care about such as price, stock level, and basic/ preferred status (to save on assembly costs).
The result is db.sqlite3 which presently comes in at under 2GB in size.
If you wish to use some data that exists in the jlcparts database but is not yet being brought over to the optimized db.sqlite3, you can look at the originating database to get familiar with it and find the data structures you wish to bring over. An easy way to do this can be: after you have run bun run setup and it has completed, the cache zip archive files are still located at ./buildtmp - simply unpack these yourself (preferably into a separate directory outside of the project) and there is your 11GB cache.sqlite3 database to look at.
To recap:
- If you wish to use additional component data (like the basic/ preferred status) that exists in jlcparts, it won't be in the optimized
db.sqlite3(and thus jlcsearch won't know about it) until you add it via a script inlib/db/optimizations/and then call it inscripts/setup-db-optimizations.ts. You should then dobun run setupagain to rebuild the optimized database with your new data. - If you wish to add additional component types (like gyroscopes or Molex connectors) you would need to set up a new schema for them in
lib/db/derivedtablesand then dobun run generate:db-typesto generate the new table types as per the Development section above.
None of this would be possible without JLCPCB and the work jlcparts project.
