Getting Started with World War 2 Mapping
Most people approach this thinking it is just slapping colored polygons onto a blank map and calling it a day. It is not that simple. The problem is that WWII data is scattered across dozens of sources with conflicting coordinates, unit designations that changed weekly, and terrain data that looks nothing like it did in 1944. I spent about three weeks fighting with a single Eastern Front campaign map before I figured out a workflow that actually holds up. Here is the practical way to do it without losing your mind.
World War 2 Mapping: Setting Up Your Base Layer
Start with a modern base map, but not the default Google or OpenStreetMap one. Use SRTM or Copernicus DEM data and generate a hillshade layer at 30-meter resolution. Terrain was the single biggest factor in almost every WWII engagement, and if your base map doesn't show elevation changes properly, your unit placement is going to look ridiculous. I built a custom QGIS project that pulls a hillshade from SRTM v4.1 overlaid on a natural earth basemap, with the hillshade at about 40% opacity so roads and rivers still read clearly. Project the data. Always project your data. Most historical coordinate sources use WGS84, but if you are working with older military grids like the British OSGB36 or Soviet BSK-1942 systems, reprojecting everything to a common CRS like ETRS89 / UTM zone 33N saves you from spending hours debugging misplaced points later. I learned that the hard way with a Soviet advance map where entire divisions were rendered fifty kilometers west of where they actually were because the source grid was misidentified.
Where the Data Actually Comes From
The internet has a ton of WWII map resources, but most of them are either too granular for practical use or completely unreliable. The ones I actually trust are: The US Army Center of Military History has a massive collection of operational maps, many already georeferenced or close to it. Their online catalog is underwhelming, but the PDFs in the Special Collections section are gold. The National Archives at College Park has microfilm records from the War Department General and Special Staffs that include daily movement maps for major theaters. Battlefield Trust and American Battlefield Protection Program maps are accurate but limited to Western Front sites. For the Pacific, the Australian War Memorial has surprisingly good GIS data on campaigns. The Lekseng.org forum has archived maps from Soviet sources that are meticulously detailed, though you need to verify coordinates yourself since some were hand-drawn from memory.
Get the Full Details

German sources like the Bundesarchiv-Militärarchiv are extremely detailed but require a visit or an interlibrary loan request. The Kriegstachtkarten (war situation maps) they hold are the closest thing to primary tactical data you will find, covering everything from the BEF at Dunkirk to the 6th Army at Stalingrad. I digitized about forty of these for a personal project and cross-referenced them with Russian capture logs to fill gaps where German records were lost.
The Workflow That Actually Works
I work in QGIS with PostGIS for larger datasets, though PostGIS is overkill unless you are mapping the entire war. For anything smaller than a full theater campaign, QGIS alone is fine and loads faster. Step one is scanning or downloading the source map. Step two is georeferencing it. Open the georeferencer plugin, load your scanned map, and add control points. Use at least six points spread across the entire map, and prioritize intersections that haven't changed much since 1945. Roads and rivers are better than building footprints, which shift constantly. I usually spend about twenty to forty minutes per map on control points depending on the condition of the original document. Step three is digitizing the features you care about. If you are mapping front lines, use polylines. Unit boundaries are polygons. Artillery positions and bunkers are point layers. Keep them separate. I used to merge everything into one layer and it made editing a nightmare when you need to toggle visibility or apply different symbology.
Step four is the part nobody talks about: temporal indexing. A front line on June 22 means something different than the same line on July 5. Add a date field to every feature. Every single one. If you are doing animation or timeline browsing, this becomes critical. I set up a form configuration in QGIS that forces a date field on every new feature so I can't skip it. Took me a while to build that, but it saved me when I was three hundred features into a project and realized half of them had no date attached.

Common Pitfalls That Will Waste Your Time
The biggest one is assuming that unit names on maps are consistent. The German Wehrmacht reorganized divisions repeatedly. The 1st Panzer Division in 1941 is not the same formation as the 1st Panzer Division in 1944. If you are tracking a specific unit across multiple maps, verify the organization date against the order of battle for that period. I once labeled an entire section of a 1943 Kursk map with "1st Panzer Division" and had to redo it after realizing the source map was actually showing the division in a different combat grouping than I assumed. Another issue is scale. Many military maps from the period were drawn at 1:100,000 or 1:200,000, which means a single sheet covers a small area. If you need a complete campaign map, you will be stitching together dozens of sheets. The georeferencing compounds with each sheet. I usually allow for about two hundred meter error per sheet at 1:100,000 scale, which adds up fast. For large-scale overviews, I sometimes use pre-georeferenced versions from the McNamara Archive or Military Maps Forum instead of starting from scratch. Terrain also changes. What looks like open ground on a modern satellite image might have been a dense forest in 1943. The Historical Forest Cover datasets from the Max Planck Institute and the Hyde et al. land use reconstructions can help, but they are low resolution. For tactical accuracy, I sometimes pull old topographic maps from the Library of Congress or national archives of the relevant country to see what the landscape actually looked like at the time.
Tools I Use and Why
QGIS is the main tool. It handles georeferencing, vector editing, temporal playback, and rendering all in one package. The Temporal Controller plugin is essential for animating campaigns. It takes a bit of setup but once it is running, you can scrub through dates and watch your front lines move in real time. GRASS GIS is useful for terrain analysis. If you want to know whether a particular ridge was defensible or if a valley was actually passable for heavy vehicles, GRASS gives you slope, aspect, and visibility analysis. I used this for a project mapping the Ardennes in December 1944 and it confirmed what the historical record already suggested: the terrain analysis matched the actual German armor routes almost exactly, which helped explain why certain units got stuck while others pushed through. PhotoShop or GIMP for cleaning up scanned maps before georeferencing. Removing annotations, correcting discoloration, and sharpening lines makes control point placement significantly more accurate. I usually run a basic denoise filter, adjust contrast, and then manually clean up any smudged areas. Takes about ten minutes per map.
For publishing, QGIS print composer or ArcGIS Pro if you have access. QGIS is free and handles most output needs. I export at 300 DPI minimum for print and use Web Mercator for anything web-based.

World War 2 Mapping for Online Distribution
If you are putting this online, Leaflet or Mapbox GL JS are the simplest options. Export your QGIS layers as GeoJSON or MBTiles, then load them into a Leaflet map. I built a simple static site with embedded Leaflet maps for a personal project and hosted it on GitHub Pages. It takes about an hour to set up if you have the maps already ready. The main limitation is file size. A single theater with all the layers can easily exceed 50 MB in GeoJSON, which makes the page slow. I solved this by converting to MBTiles and serving them through a tile server, which cut load times from around twelve seconds to about two seconds on a standard connection. Another option is KMZ files for Google Earth. Easier to share, harder to customize. I use this for quick visualizations I send to people who don't want to deal with a browser-based map.
What This Approach Does Not Handle Well
Honest assessment: this method does not work well for naval or air campaigns. Ship positions are tracked differently, often with coordinates that are approximate to within several kilometers. Air reconnaissance photos and mission reports have their own coordinate systems that do not map cleanly to ground truth. If you are primarily interested in naval movements, you are better off using existing datasets like the Naval Historical Center archives or uboat.net for U-boat operations, then overlaying your own annotations on top rather than building from scratch. Similarly, logistics and supply line mapping is a whole separate project. The data exists in unit diaries and quartermaster reports, but it is rarely in a format that translates directly to spatial data. I have seen a few academic projects attempt this, mostly using spreadsheet data converted to points, but the results are always rough because supply routes were fluid and often undocumented at the tactical level. The other limitation is that this approach assumes you have time. A single division-size campaign can take two to four days to map properly if you are being careful about source verification and coordinate accuracy. If you rush it, the errors show. I have looked at my own rushed maps and cringed at the misplaced units. It happens to everyone.
If you are just starting out, pick a small engagement first. Something like the defense of a single village or a one-day battle. Get the georeferencing right, place a few units, add a date, and see how it feels. Once you have done one, the rest gets easier. The hardest part is always the first map.