Offline lookup for India PIN codes, states, districts, and post offices, with typo-, case-, and abbreviation-tolerant search.
The dataset is the official All India Pincode Directory (Department of Posts), mirrored by The India Post PIN Code Finder. A GitHub Actions workflow refreshes it weekly and publishes a new dated build as a GitHub Release. The lookup code never changes between builds — only the bundled data does.
- ~154,000 post offices, ~19,000 PIN codes, 36 states/UTs
- Zero network calls at runtime — everything is bundled
- One small dependency (MiniSearch) for fuzzy search
Each weekly build is a GitHub Release asset (indiapins-<version>.tgz). Pin the version
you want — npm and yarn both install directly from the tarball URL:
# npm
npm i https://github.com/OWNER/indiapins/releases/download/v2026.6.28/indiapins-2026.6.28.tgz
# yarn classic (v1)
yarn add https://github.com/OWNER/indiapins/releases/download/v2026.6.28/indiapins-2026.6.28.tgz
# yarn berry (v2+)
yarn add indiapins@https://github.com/OWNER/indiapins/releases/download/v2026.6.28/indiapins-2026.6.28.tgzOr declare it in package.json (honored by both npm and yarn), then npm install / yarn:
{
"dependencies": {
"indiapins": "https://github.com/OWNER/indiapins/releases/download/v2026.6.28/indiapins-2026.6.28.tgz"
}
}To move to a later weekly build, change the version in the URL and reinstall. (A tarball URL pins one build — there's no semver auto-upgrade; see Versioning & releases below.)
Note:
npm i github:OWNER/indiapins(installing from the git repo) will not include the data —data/is generated, not committed. Always install a Release tarball, or runnpm run generateyourself after cloning.
indiapins is an ES module. In an ESM project ("type": "module" in package.json, or a
.mjs file):
// app.js
import { lookup, getDistricts, getPostOffices, searchPlace, meta } from 'indiapins';
console.log(lookup('110001'));
// [{ officeName: 'Connaught Place S.O', pincode: '110001', officeType: 'SO',
// delivery: false, district: 'Central Delhi', state: 'Delhi' }, ...]
console.log(lookup(' 110 001 ').length); // 21 - whitespace/punctuation tolerant
console.log(getDistricts('tn').includes('Chennai')); // true - abbreviation tolerant
console.log(getPostOffices('tn', 'chennai').length); // 112
console.log(searchPlace('connaght')[0].officeName); // 'Connaught Place S.O' - typo tolerant
console.log(searchPlace('chennai', { state: 'tn', limit: 5 })); // scoped to Tamil Nadu
console.log(meta().version); // '2026.6.28'node app.jsThe package is ESM-only, so from a CommonJS file use dynamic import():
// app.cjs
(async () => {
const { lookup, searchPlace } = await import('indiapins');
console.log(lookup('560001').length);
console.log(searchPlace('coimbatoer')[0].officeName); // 'Coimbatore H.O' - typo tolerant
})();node app.cjsTypes ship with the package — no @types needed:
import { lookup, searchPlace, type PostOffice, type SearchResult } from 'indiapins';
const offices: PostOffice[] = lookup('110001');
const hits: SearchResult[] = searchPlace('connaght', { state: 'tn' });PostOffice = { officeName, pincode, officeType, delivery, district, state }
where officeType is HO | SO | BO | BO DIRECTLY A/W HEAD OFFICE and delivery is a boolean.
All text inputs are case-folded, diacritic-stripped, and punctuation-normalized. Name
search adds Levenshtein fuzziness and prefix matching; a curated abbreviation map covers
states (tn, ap, up, ...) and major cities (blr, hyd, mum, ...), plus acronym
matching (cp -> Connaught Place). State/district arguments are fuzzy-resolved too.
The fuzzy search index (data/search-index.json) is loaded lazily on the first
searchPlace call, so plain lookup / getPostOffices stay lightweight.
scripts/generate.mjs:
- Fetches the minimal complete source — the by-prefix shards
https://indiapost.org/data/pincodes/by-prefix/{NN}.json(one per used 2-digit PIN region; their union is the entire directory). - Validates hard (6-column rows, 6-digit PINs, sane totals) and aborts on any structural failure so a bad fetch is never published.
- Writes
data/pincodes/{NN}.json(compact rows),data/index.json(states -> prefixes/districts, counts, version, content hash), and a serialized MiniSearch indexdata/search-index.json.
- Version is CalVer
YYYY.M.D(e.g.2026.6.28); the rawyyyymmddis inmeta(). - The workflow (
.github/workflows/update-and-publish.yml) runs weekly, regenerates the data, runs the tests, and creates a GitHub Release with the packed tarball — using only the built-inGITHUB_TOKEN(no npm or registry credentials). - A content hash gates publishing: if the source data is unchanged from the last Release,
no new build is created. Run the workflow manually (
workflow_dispatch) with force to override, or dry_run to build and test without releasing.
npm install
npm run generate # fetch + build data/ (network required)
npm test # node --testData originates from the Department of Posts' All India Pincode Directory, accessed via
indiapost.org. This project is not affiliated with or endorsed by India Post. Accuracy
is best-effort and reflects the source at generation time.
MIT (code). The underlying postal data is public-domain government data.
