Building a Community Contribution System for VIN Decoding Patterns

Published: (March 12, 2026 at 08:25 PM EDT)
2 min read
Source: Dev.to

Source: Dev.to

Overview

Cover image for Building a Community Contribution System for VIN Decoding Patterns

VIN decoding sounds straightforward until you realize every manufacturer implements it differently, and the authoritative database (NHTSA VPIC) only covers US‑market vehicles.

We maintain Corgi, an open‑source offline VIN decoder. To handle international vehicles, we built a community contribution system. Here’s how it works.

The Problem

A VIN (Vehicle Identification Number) is 17 characters:

  • Positions 1‑3: WMI (World Manufacturer Identifier)
  • Positions 4‑8: Vehicle attributes (model, engine, etc.)
  • Position 9: Check digit
  • Position 10: Model year
  • Position 11: Plant code
  • Positions 12‑17: Serial number

NHTSA’s VPIC database maps WMIs to manufacturers and defines how to interpret positions 4‑8, but it only covers vehicles sold in the US.

Examples:

  • Tesla’s Shanghai factory uses WMI LRW.
  • Tesla’s Berlin factory uses WMI XP7.

Neither WMI exists in VPIC.

Our Solution: YAML Patterns

Contributors add a YAML file describing a new WMI:

wmi: LRW
manufacturer: Tesla
make: Tesla
country: China
vehicle_type: Passenger Car
years:
  from: 2020
  to: null

sources:
  - type: service_manual
    description: Tesla Model 3/Y VIN decoder
    url: https://example.com/source

patterns:
  - pattern: "3E****"
    element: Model
    value: Model 3
  - pattern: "YG****"
    element: Model
    value: Model Y
  - pattern: "*D****"
    element: Drive Type
    value: AWD
  - pattern: "*C****"
    element: Drive Type
    value: RWD

test_vins:
  - vin: LRW3E7FA6NC433523
    expected:
      make: Tesla
      model: Model 3
      drive_type: RWD

Validation Pipeline

When a PR is opened, CI runs several checks.

Schema Validation (Zod)

const wmiFileSchema = z.object({
  wmi: z.string().length(3).regex(/^[A-HJ-NPR-Z0-9]{3}$/),
  manufacturer: z.string().min(1),
  make: z.string().min(1),
  country: z.string().min(1),
  vehicle_type: z.enum(VALID_VEHICLE_TYPES),
  years: yearsSchema,
  patterns: z.array(patternSchema).min(1),
  test_vins: z.array(testVinSchema).min(1),
});

Check Digit Verification

Every test VIN must have a valid check digit (position 9):

function validateCheckDigit(vin: string): boolean {
  const weights = [8,7,6,5,4,3,2,10,0,9,8,7,6,5,4,3,2];
  const transliteration = { A:1, B:2, /* … */ };

  let sum = 0;
  for (let i = 0   
  • npm:
0 views
Back to Blog

Related posts

Read more »

Jemalloc un-abandoned by Meta

- Meta recognizes the long‑term benefits of jemalloc, a high‑performance memory allocator, in its software infrastructure. - We are renewing focus on jemalloc,...

Meta’s renewed commitment to jemalloc

Meta recognizes the long‑term benefits of jemalloc, a high‑performance memory allocator, in its software infrastructure. We are renewing focus on jemalloc, aimi...