Skip to content

Download

OSMForge downloads PBF extracts from Geofabrik. Region paths mirror the Geofabrik URL structure.

CLI

The osmforge-download command is installed automatically with the package.

# Single region
osmforge-download europe/united-kingdom/england/isle-of-wight

# Multiple regions in one call
osmforge-download \
    europe/united-kingdom/england/greater-london \
    europe/united-kingdom/england/west-midlands

# Force re-download (overwrite existing file)
osmforge-download --force europe/united-kingdom/england/isle-of-wight

Files are saved to the OS user-data directory by default:

OS Default path
Linux ~/.local/share/osmforge/
macOS ~/Library/Application Support/osmforge/
Windows %LOCALAPPDATA%\osmforge\

Override the destination with an environment variable:

export OSMFORGE_DATA_DIR=/data/osm
osmforge-download europe/united-kingdom/england/isle-of-wight

Example region paths

europe/united-kingdom/england/isle-of-wight
europe/united-kingdom/england/greater-london
europe/united-kingdom/england/west-midlands
europe/united-kingdom/scotland
europe/germany/berlin
north-america/us/california

Full index: https://download.geofabrik.de/


Python API

You can also call the download functions directly from Python:

from osmforge.download import download, get_data_dir

# Show where files will be saved
print(get_data_dir())
# /home/user/.local/share/osmforge

# Download a region (skips if already present)
path = download("europe/united-kingdom/england/isle-of-wight")
print(path)
# /home/user/.local/share/osmforge/isle-of-wight-latest.osm.pbf

# Force re-download
path = download("europe/united-kingdom/england/isle-of-wight", force=True)

API Reference

osmforge.download

Download OSM PBF extracts from Geofabrik.

Usage: python3 osmforge/download.py [region-path ...] python3 osmforge/download.py --force

Examples: python3 osmforge/download.py europe/united-kingdom/england/isle-of-wight python3 osmforge/download.py europe/united-kingdom/england/greater-london python3 osmforge/download.py europe/united-kingdom/england/west-midlands europe/united-kingdom/england/staffordshire

Or via make: make download REGION=europe/united-kingdom/england/isle-of-wight make download REGION="europe/united-kingdom/england/west-midlands europe/united-kingdom/england/staffordshire"

get_data_dir()

Resolve the directory where PBF files are stored.

Priority: 1. OSMFORGE_DATA_DIR environment variable 2. OS user-data directory (~/.local/share/osmforge on Linux, ~/Library/Application Support/osmforge on macOS, etc.)

Source code in osmforge/download.py
32
33
34
35
36
37
38
39
40
41
42
43
44
def get_data_dir() -> Path:
    """
    Resolve the directory where PBF files are stored.

    Priority:
      1. OSMFORGE_DATA_DIR environment variable
      2. OS user-data directory (~/.local/share/osmforge on Linux,
         ~/Library/Application Support/osmforge on macOS, etc.)
    """
    env = os.environ.get("OSMFORGE_DATA_DIR")
    path = Path(env) if env else Path(user_data_dir("osmforge"))
    path.mkdir(parents=True, exist_ok=True)
    return path

download(region_path, force=False)

Source code in osmforge/download.py
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
def download(region_path: str, force: bool = False) -> Path:
    data_dir = get_data_dir()
    url = f"{BASE_URL}/{region_path}-latest.osm.pbf"
    dest = dest_path(region_path, data_dir)

    if dest.exists() and not force:
        size_mb = dest.stat().st_size / 1_048_576
        print(f"  [skip] {dest.name} already exists ({size_mb:.1f} MB)")
        return dest

    print(f"  -> {url}")
    print(f"  saving to {dest}")

    tmp = dest.with_suffix(".part")
    try:
        with requests.get(url, stream=True, timeout=60) as r:
            r.raise_for_status()
            total = int(r.headers.get("content-length", 0))
            downloaded = 0
            with tmp.open("wb") as f:
                for chunk in r.iter_content(chunk_size=1 << 20):
                    f.write(chunk)
                    downloaded += len(chunk)
                    if total:
                        pct = downloaded / total * 100
                        mb = downloaded / 1_048_576
                        print(
                            f"\r    {mb:6.1f} / {total/1_048_576:.1f} MB"
                            f"  ({pct:.0f}%)",
                            end="",
                            flush=True,
                        )
        print()
        tmp.rename(dest)
        print(f"  saved -> {dest.name}")
    except Exception:
        tmp.unlink(missing_ok=True)
        raise

    return dest