India's borders, drawn correctly on any web map.

Free map styles are built from OpenStreetMap, which shows Kashmir, Ladakh and Arunachal Pradesh differently from the Survey of India. bharatmap fixes that with one function call. No server, no API key, no dependencies.

npm install bharatmap
Read the guide

About 40 kB gzipped. Apache-2.0. Works with MapLibre, Leaflet, OpenLayers and deck.gl.

VKrishna04by VKrishna04
Basemap as shippedWith bharatmap

Drag the handle to compare. Pan and zoom the map, or use the buttons. To zoom with the scroll wheel hold Ctrl; on a phone use two fingers.

-
Installs this month
-
Installs this week
-
Installs in total
-
GitHub stars
-
Latest version

Add it to your map

Pick the library you use. Three steps, about a minute.

  1. Install the package

    npm install bharatmap
  2. Call fixMap after you create the map

    It fixes the style you have now and every later setStyle, so switching between light and dark keeps working.

    import maplibregl from "maplibre-gl";
    import { fixMap } from "bharatmap";
    
    const map = new maplibregl.Map({ container: "map", style: STYLE_URL, center: [78, 22], zoom: 4 });
    await fixMap(maplibregl, map);

    If you would rather fix the style before the map exists, use install(maplibregl) once, then await fixStyle(STYLE_URL) and pass the result as style.

  3. Check that it worked

    • Open the map in light and dark if you support both, and look at these views.
    • Whole India (zoom 2 to 3): one line around India, with no extra dashed lines over Ladakh or Kashmir.
    • Arunachal Pradesh (zoom 5 to 7): one continuous border, and the Myanmar and Bhutan borders still drawn.
    • Where the line meets Himachal Pradesh and Bhutan (zoom 9 to 12): no gaps and no doubled lines.
    • Credits: the border data attribution shows in the map's corner.

Or let your AI assistant do it

It reads the project, finds your map library and basemap, makes the change and checks it at several zoom levels.

One command for your project

Writes the instructions where your assistant looks: Claude Code, Cursor, Copilot, Windsurf, Gemini CLI, or AGENTS.md for the rest. Then ask it to "fix the India borders on my map with bharatmap".

npx bharatmap init

Claude Code plugin

/plugin marketplace add Life-Experimentalist/bharatmap
/plugin install bharatmap@bharatmap

Any assistant that can open a link

Paste this. The file behind the link is always the current version, so you never have stale instructions.

Follow https://bharatmap.vkrishna04.me/skill.md to fix the India borders on my map.

Crawlers and agents can also read skill.md and llms.txt directly.

What works with what

Any vector basemap in the OpenMapTiles schema: CARTO (Positron, Dark Matter, Voyager), OpenFreeMap, MapTiler, Stadia and others.

  • MapLibre GL JS

    fixMap(maplibregl, map) Tested in a browser, light and dark, zoom 2 to 14.

  • Leaflet, vector basemap

    fixStyle, then L.maplibreGL({ style }). Tested in a browser.

  • OpenLayers

    fixStyle with protocol: false and olTileLoadFunction. Tested in a browser.

  • deck.gl, react-map-gl

    Same as MapLibre, on the style you pass in. Same engine, not tested separately.

  • Mapbox GL JS, Tangram, QGIS

    Use tileProxy, a handler you host. Covered by unit tests only.

  • Leaflet, raster tiles

    Only an overlay is possible: L.geoJSON(BharatMap.boundary). The raster's own line stays underneath, because a border baked into a picture cannot be cut.

  • Google Maps

    Nothing to do. Google already draws India's borders per local depiction.

  • Apple Maps

    Not possible. The vendor decides what it draws.

Why a style filter is not enough

Free basemaps are built from OpenStreetMap, whose contributors draw disputed borders as the lines on the ground. So an OpenStreetMap-based map shows the Line of Actual Control, the Line of Control and the China side of Arunachal Pradesh as international borders, often as dashed fragments that are still visible at world zoom.

You cannot hide them with a style rule. The tile builder merges several disputed borders into one long line, so a filter removes all of it or none of it. A filter box big enough to catch the strays also deletes real borders, such as Myanmar and Bhutan in Arunachal Pradesh.

bharatmap cuts the geometry inside each vector tile as it loads, then draws India's boundary in its place, in the basemap's own line style. Tiles that miss the affected areas come back untouched, and the rest take a few milliseconds each. The technical details are in how it works, and custom schemas are covered in basemaps.

If something looks wrong, and other questions

Troubleshooting

Nothing changed on my map

Check three things. First, the basemap must be vector tiles. If your map uses .png or .jpg tiles the border is part of the picture and cannot be cut. Second, the style needs a boundary layer with admin_level 2, which is the OpenMapTiles schema. Look for "source-layer": "boundary" in the style JSON. Third, make sure the style you pass to the map is the one that came back from fixStyle, and that you waited for it.

It is right until I switch between light and dark

A new style replaces the fixed one. Use fixMap(maplibregl, map), which fixes every later setStyle for you. If you use fixStyle instead, run every style you load through it, including the dark one.

Where did the data credit go?

bharatmap adds the border data attribution to the map's credits on its own. Keep the attribution control on the map and it stays there.

I see a small gap at a high zoom

The coverage check reports no gaps from zoom 1 to 10 and a few tile-edge pieces at zoom 11 and 12. Zoom 13 and above was checked by eye. If you find one, open an issue on GitHub with the zoom level and the coordinates, and it can be fixed in the module's region data.

My basemap uses a different schema

You can pass a profile that names the tile layer and says which lines to cut. The three parts are described in basemaps, along with a command that checks a new basemap for gaps.

Questions

Is the line legally authoritative?

No. It follows a published depiction of the Survey of India line, checked against OpenStreetMap where OpenStreetMap independently draws the same line. If you publish the map, verify the line against the Survey of India itself.

Does it need a server or an API key?

No. It runs in the browser. Only the optional tile proxy for Mapbox GL JS and similar clients needs hosting.

Does it slow the map down?

Tiles that do not touch the affected areas are returned untouched. The others take a few milliseconds each. The library is about 40 kB gzipped and has no runtime dependencies.

What is the license?

The code is Apache-2.0. The border data is ODbL 1.0, and its attribution is added to the map for you. Both are described in the repository.

Does it work with TypeScript?

Yes. Types ship with the package.

Badges and banner

Using bharatmap on your site or in your project? Add a badge so others can find it.

  • npm version
  • npm downloads per month
  • GitHub stars
  • Bundle size
  • Types included
  • License

"Uses bharatmap" badge

Map borders: bharatmap

[![Map borders: bharatmap](https://img.shields.io/badge/map%20borders-bharatmap-000?style=flat-square&color=000000&labelColor=737373)](https://bharatmap.vkrishna04.me/)

Project badges for your README

[![npm version](https://img.shields.io/npm/v/bharatmap?style=flat-square&color=000000&labelColor=737373)](https://www.npmjs.com/package/bharatmap)
[![npm downloads per month](https://img.shields.io/npm/dm/bharatmap?style=flat-square&color=000000&labelColor=737373)](https://www.npmjs.com/package/bharatmap)
[![GitHub stars](https://img.shields.io/github/stars/Life-Experimentalist/bharatmap?style=flat-square&color=000000&labelColor=737373)](https://github.com/Life-Experimentalist/bharatmap)
[![Bundle size](https://img.shields.io/bundlephobia/minzip/bharatmap?style=flat-square&color=000000&labelColor=737373)](https://bundlephobia.com/package/bharatmap)
[![Types included](https://img.shields.io/npm/types/bharatmap?style=flat-square&color=000000&labelColor=737373)](https://www.npmjs.com/package/bharatmap)
[![License](https://img.shields.io/npm/l/bharatmap?style=flat-square&color=000000&labelColor=737373)](https://github.com/Life-Experimentalist/bharatmap/blob/main/LICENSE)

Banner

A 1200 by 630 image, the same one used when this page is shared.

[![bharatmap: correct India borders on web maps](https://bharatmap.vkrishna04.me/og.png)](https://bharatmap.vkrishna04.me/)