npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

gstin-tools

v1.0.0

Published

A tiny, dependency-free TypeScript library to validate and parse Indian GSTINs and work with related artefacts

Downloads

4

Readme

gstin-tools

A tiny, dependency-free TypeScript library to validate and parse Indian GSTINs and work with related artefacts (PAN extraction, state code lookup, check-digit computation, masking). Includes a robust implementation of the GSTIN check digit (Luhn mod-36 variant) and complete state/UT code tables (including 97/99).

npm version Build Status Coverage Status License: MIT

Features

  • Dependency-free: No external dependencies
  • TypeScript-first: Written in TypeScript with full type definitions
  • Tiny bundle size: < 5KB minified + gzipped
  • Tree-shakeable: Individual function exports
  • ESM + CJS: Supports both module systems
  • 100% test coverage: Thoroughly tested
  • Correct checksum: Proper Luhn mod-36 implementation
  • Complete state codes: All Indian states/UTs including special codes (97, 99)
  • PAN validation: Format validation and type extraction
  • Safe masking: Utilities for logging/PII protection

Installation

npm install gstin-tools
yarn add gstin-tools
pnpm add gstin-tools

Quick Start

import { validateGSTIN, parseGSTIN, computeCheckDigit, fromComponents } from 'gstin-tools';

// Quick validation
console.log(validateGSTIN('27AABCU9603R1ZN').ok); // true

// Parse GSTIN components
const parsed = parseGSTIN('27AABCU9603R1ZN');
console.log(parsed);
// {
//   raw: '27AABCU9603R1ZN',
//   stateCode: '27',
//   stateName: 'Maharashtra',
//   pan: 'AABCU9603R',
//   panType: 'C',
//   entity: '1',
//   defaultZ: 'Z',
//   checkDigit: 'N'
// }

// Compute checksum
console.log(computeCheckDigit('27AABCU9603R1Z')); // 'N'

// Generate GSTIN from components
console.log(fromComponents('27', 'AABCU9603R', '1')); // '27AABCU9603R1ZN'

API Reference

Validation Functions

validateGSTIN(input: string, options?: ValidateOptions): ValidateResult

Validates a GSTIN string and returns detailed validation results.

const result = validateGSTIN('27AABCU9603R1ZN');
console.log(result.ok); // true
console.log(result.parsed); // ParsedGSTIN object
console.log(result.issues); // Array of validation issues (if any)

Options:

  • allowSpecialStates?: boolean - Accept 97 (Other Territory) and 99 (Centre Jurisdiction). Default: true
  • collectAllIssues?: boolean - Return all issues instead of failing fast. Default: true
  • normalizeInput?: boolean - Uppercase and trim input. Default: true

isValidGSTIN(input: string): boolean

Quick boolean validation (fast-fail, minimal allocation).

console.log(isValidGSTIN('27AABCU9603R1ZN')); // true
console.log(isValidGSTIN('invalid')); // false

parseGSTIN(input: string, safe?: boolean): ParsedGSTIN

Parses a GSTIN into its components. Throws on invalid input unless safe is true.

const parsed = parseGSTIN('27AABCU9603R1ZN');
// Returns ParsedGSTIN object

// Safe parsing (returns detailed error)
try {
  const parsed = parseGSTIN('invalid-gstin', true);
} catch (error) {
  console.log(error.message); // Detailed validation error
}

Checksum Functions

computeCheckDigit(first14: string): string

Computes the correct check digit for the first 14 characters of a GSTIN using Luhn mod-36.

console.log(computeCheckDigit('27AABCU9603R1Z')); // 'N'

verifyCheckDigit(gstin: string): boolean

Verifies if a 15-character GSTIN has the correct checksum.

console.log(verifyCheckDigit('27AABCU9603R1ZN')); // true
console.log(verifyCheckDigit('27AABCU9603R1ZX')); // false

Generation Functions

fromComponents(stateCode: string, pan: string, entity: string, defaultZ?: 'Z'): string

Generates a valid GSTIN from components, automatically computing the check digit.

const gstin = fromComponents('27', 'AABCU9603R', '1');
console.log(gstin); // '27AABCU9603R1ZN'

State Code Functions

gstStateName(code: string): string | undefined

Returns the state/UT name for a given code.

console.log(gstStateName('27')); // 'Maharashtra'
console.log(gstStateName('97')); // 'Other Territory'
console.log(gstStateName('99')); // 'Centre Jurisdiction'

isValidStateCode(code: string, options?: { allowSpecial?: boolean }): boolean

Validates a state/UT code.

console.log(isValidStateCode('27')); // true
console.log(isValidStateCode('97')); // true
console.log(isValidStateCode('25')); // false (deprecated)
console.log(isValidStateCode('97', { allowSpecial: false })); // false

PAN Functions

validatePAN(pan: string): PanValidationResult

Validates PAN format and extracts the type.

const result = validatePAN('AABCU9603R');
console.log(result.ok); // true
console.log(result.type); // 'C' (Company)

extractPAN(gstin: string): string | undefined

Extracts the PAN from a GSTIN.

console.log(extractPAN('27AABCU9603R1ZN')); // 'AABCU9603R'

Helper Functions

maskGSTIN(gstin: string, mode?: 'show-last-3' | 'show-pan-only'): string

Masks GSTIN for safe logging/display.

console.log(maskGSTIN('27AABCU9603R1ZN')); // '************1ZN'
console.log(maskGSTIN('27AABCU9603R1ZN', 'show-pan-only')); // '**AABCU9603R***'

normalizeGSTIN(input: string): string

Normalizes GSTIN input (trim, uppercase, remove invisible chars).

console.log(normalizeGSTIN(' 27aabcu9603r1zn ')); // '27AABCU9603R1ZN'

Data Tables

The library includes complete data tables for:

State/UT Codes

  • All 38 Indian states and Union Territories
  • Special codes: 97 (Other Territory), 99 (Centre Jurisdiction)
  • Excludes deprecated code 25 (Daman & Diu, merged into 26)

PAN Types

  • P: Individual
  • C: Company
  • H: HUF (Hindu Undivided Family)
  • F: Firm
  • A: AOP (Association of Persons)
  • B: BOI (Body of Individuals)
  • L: Local Authority
  • J: Artificial Juridical Person
  • G: Government
  • T: Trust
  • N: Non-Resident
  • K: Krish (legacy category)

Validation Rules

The library validates GSTINs according to the official specification:

  1. Length: Exactly 15 characters
  2. State code: Valid 2-digit state/UT code (positions 1-2)
  3. PAN: Valid PAN format AAAAA9999A (positions 3-12)
  4. Entity code: 1-9 or A-Z, but not 0 (position 13)
  5. Default Z: Must be 'Z' for regular taxpayers (position 14)
  6. Check digit: Luhn mod-36 checksum (position 15)

Tree Shaking

The library supports tree shaking via individual exports:

// Import only what you need
import { validateGSTIN } from 'gstin-tools/validation';
import { computeCheckDigit } from 'gstin-tools/checksum';
import { maskGSTIN } from 'gstin-tools/helpers';
import { gstStateName } from 'gstin-tools/state-codes';

Examples

Form Validation

import { validateGSTIN } from 'gstin-tools';

function validateGSTINField(input: string) {
  const result = validateGSTIN(input, {
    normalizeInput: true,
    collectAllIssues: true
  });
  
  if (!result.ok) {
    return result.issues?.map(issue => issue.message);
  }
  
  return null; // Valid
}

Invoice Processing

import { parseGSTIN, maskGSTIN } from 'gstin-tools';

function processInvoice(gstinInput: string) {
  try {
    const gstin = parseGSTIN(gstinInput);
    
    console.log(`State: ${gstin.stateName}`);
    console.log(`PAN: ${gstin.pan} (${gstin.panType})`);
    console.log(`Masked: ${maskGSTIN(gstin.raw)}`);
    
    return gstin;
  } catch (error) {
    console.error('Invalid GSTIN:', error.message);
    return null;
  }
}

Batch Validation

import { isValidGSTIN } from 'gstin-tools';

function validateGSTINBatch(gstins: string[]) {
  return gstins.map(gstin => ({
    gstin,
    valid: isValidGSTIN(gstin)
  }));
}

Browser Support

This library works in all modern browsers and Node.js 18+. The build targets ES2020.

Contributing

Contributions are welcome! Please read our Contributing Guide for details.

License

MIT © Naveen Bhavnani

Disclaimer

This is not an official government library. While we strive for accuracy, always verify GSTINs through official GSTN portals for production use.