Python sysconfig: Paths and Build Info

Published on: August 9, 2026
Reading time: 7 minutes
Source code and compiler representing build paths and variables with Python sysconfig

Packaging tools, installers, native extensions, and diagnostic utilities need to know where the current Python installation stores libraries, scripts, header files, and data. Those locations vary across Linux, macOS, Windows, system installations, custom builds, and virtual environments. Python sysconfig provides the official API for inspecting these details without hard-coding paths.

The module also exposes variables used to build the interpreter and third-party C extensions, including compiler commands, flags, library directories, ABI information, and configuration options. This guide explains installation schemes, purelib, platlib, virtual environments, platform identifiers, build variables, header locations, command-line diagnostics, and safe use in packaging workflows.

It complements our guides to Python py_compile, compileall, types, importlib.resources, and zoneinfo.

Why hard-coded paths fail

A path such as /usr/local/lib/python3.14/site-packages may work on one machine and fail on another. Linux distributions, Homebrew, pyenv, Microsoft Store Python, macOS framework builds, containers, and virtual environments all use different layouts.

Ask the interpreter that will actually run or build the code. Sysconfig describes that interpreter’s installation rather than an assumed global convention.

Listing installation paths

import sysconfig

paths = sysconfig.get_paths()
for name, path in paths.items():
    print(name, path)

The result includes standard-library directories, package directories, script locations, headers, and general data directories. The exact values depend on the active installation scheme.

purelib and platlib

purelib is the destination for platform-independent Python packages. platlib is intended for platform-specific packages, especially compiled extension modules.

print(sysconfig.get_path("purelib"))
print(sysconfig.get_path("platlib"))

Some installations use the same path for both. Packaging code must not assume they are always identical.

stdlib and platstdlib

stdlib identifies the platform-independent standard library, while platstdlib identifies platform-specific standard-library components.

These paths describe the Python installation. They are not general-purpose storage locations for application configuration, user uploads, or mutable runtime data.

The scripts directory

scripts = sysconfig.get_path("scripts")

Installers place console entry points and executable scripts in this directory. It is commonly named bin on POSIX and Scripts on Windows.

A setup tool can report this path when an executable is not on PATH, but it should not silently edit global shell configuration.

C API header directories

include = sysconfig.get_path("include")
platform_include = sysconfig.get_path("platinclude")

These paths matter when compiling C or C++ extensions or embedding Python. Custom builds can separate generic and platform-specific headers.

Check whether the directories and required files actually exist. A minimal runtime image may expose conceptual paths even though development headers were removed.

The default installation scheme

scheme = sysconfig.get_default_scheme()
print(scheme)

Since Python 3.11, an interpreter running inside a virtual environment normally reports the venv scheme. Outside a virtual environment, the result usually reflects the native POSIX or Windows layout.

Listing available schemes

for scheme in sysconfig.get_scheme_names():
    print(scheme)

Common names include posix_prefix, posix_user, posix_home, nt, nt_user, and venv. Python redistributors may customize preferred schemes to keep system-package-manager and language-package-manager files separate.

Selecting a preferred scheme

user_scheme = sysconfig.get_preferred_scheme("user")
prefix_scheme = sysconfig.get_preferred_scheme("prefix")
home_scheme = sysconfig.get_preferred_scheme("home")

The accepted intentions are user, prefix, and home. Prefer this public API to internal scheme tables because operating-system vendors can adjust their distribution layout.

Inspecting a specific scheme

user_paths = sysconfig.get_paths(
    scheme=sysconfig.get_preferred_scheme("user")
)

Discovering a path does not prove that the process may write there. Check permissions and organizational policy separately.

Path templates and expansion

Installation schemes contain templates with variables such as {base}, {platbase}, and {py_version_short}. By default, get_path() expands them.

template = sysconfig.get_path(
    "stdlib",
    expand=False,
)

The unexpanded form is useful for diagnostics and tooling that studies layouts. It is not usually a usable filesystem path.

Overriding expansion variables

path = sysconfig.get_path(
    "purelib",
    scheme="posix_prefix",
    vars={
        "base": "/opt/python",
        "platbase": "/opt/python",
    },
)

This can support staging areas, image construction, and packaging analysis. Do not allow untrusted input to select an arbitrary installation root.

Configuration variables

variables = sysconfig.get_config_vars()
print(variables.get("CC"))
print(variables.get("LIBDIR"))

The dictionary includes values derived from Python’s Makefile and pyconfig.h where applicable. Windows generally provides a smaller set than Unix-like builds.

The complete dictionary can be large and may reveal internal paths, so diagnostic reports should select only relevant keys.

Reading one configuration variable

shared = sysconfig.get_config_var("Py_ENABLE_SHARED")
compiler = sysconfig.get_config_var("CC")

An unknown key returns None. Treat absence explicitly instead of converting it to the literal string "None" and passing that value to a build command.

Reading several variables

ar, cxx, cflags = sysconfig.get_config_vars(
    "AR",
    "CXX",
    "CFLAGS",
)

The returned list follows the argument order. Individual values can still be None, especially on platforms that do not use the same toolchain model.

Platform identifier

platform_tag = sysconfig.get_platform()
print(platform_tag)

The value is designed for build directories and platform-specific distributions. Examples include linux-x86_64, win-amd64, win-arm64, and macOS architecture tags.

It is not a friendly system description. Use the platform module for human-readable operating-system reports.

Python major and minor version

version = sysconfig.get_python_version()
print(version)  # for example, 3.14

The result omits the patch version. Use sys.version_info when patch-level behavior matters.

Detecting a source-tree build

if sysconfig.is_python_build():
    print("running from a Python build tree")

This is useful to tools involved in building CPython itself. Ordinary applications rarely need to change business behavior based on this flag.

Finding pyconfig.h

config_header = sysconfig.get_config_h_filename()

The header contains configuration macros for the interpreter. It can support diagnostics and native builds, but tools should never modify the active installation’s file.

Finding Python’s Makefile

makefile = sysconfig.get_makefile_filename()

Availability and content vary by platform. Prefer the higher-level configuration-variable functions instead of parsing the file directly whenever possible.

Parsing a config.h-style file

with open(
    config_header,
    encoding="utf-8",
    errors="surrogateescape",
) as file:
    values = sysconfig.parse_config_h(file)

The parser targets config.h-style definitions. It is not a complete C preprocessor and should not be used for arbitrary headers.

Virtual environments

Inside a virtual environment, package and script paths should point to the environment, while parts of the standard library can remain in the base installation. Do not reconstruct these paths from sys.prefix manually; ask sysconfig.

For diagnostics, it can still be helpful to compare sys.prefix and sys.base_prefix, but path resolution should use the scheme APIs.

Installing packages

Sysconfig describes destinations used by installers. Application code should not copy packages directly into site-packages. Use pip, build backends, wheels, and packaging metadata so dependencies and uninstall operations remain manageable.

Native extensions and ABI data

Variables such as EXT_SUFFIX, SOABI, CC, CFLAGS, and LDSHARED help a build system match the active interpreter.

extension_suffix = sysconfig.get_config_var("EXT_SUFFIX")
soabi = sysconfig.get_config_var("SOABI")

Do not concatenate compiler strings into a shell command. Use a build system or execute a structured argument list to avoid quoting bugs and injection vulnerabilities.

Cross-compilation

The sysconfig data of the interpreter currently running usually describes that interpreter. In cross-compilation, the build host and target can differ. Use the target toolchain and the configuration data explicitly supplied by the cross-build environment.

Do not assume get_platform() represents the deployment target when it is executed on the build host.

Containers and minimal images

A runtime container can omit compilers, Makefiles, and development headers even when configuration variables reference expected locations. Test file existence before opening or invoking tools.

Use separate build and runtime stages when compiling native wheels.

Command-line diagnostics

python -m sysconfig

The command prints the platform, Python version, current scheme, paths, and configuration variables. It is useful in CI logs, support sessions, and installation troubleshooting.

Review the output before publishing it because it can reveal internal directory names and infrastructure details.

A compact diagnostic report

def diagnostic():
    return {
        "python": sysconfig.get_python_version(),
        "platform": sysconfig.get_platform(),
        "scheme": sysconfig.get_default_scheme(),
        "purelib": sysconfig.get_path("purelib"),
        "scripts": sysconfig.get_path("scripts"),
        "soabi": sysconfig.get_config_var("SOABI"),
    }

Collect only information needed for the current issue instead of exposing the full environment.

Testing portable tooling

Tests should avoid asserting one absolute path. Check types, non-empty values, relationships between paths, and existence only when the deployment guarantees it.

def test_scripts_path():
    path = sysconfig.get_path("scripts")
    assert isinstance(path, str)
    assert path

Run the suite on Windows, Linux, macOS, and virtual environments when those platforms are supported.

Common mistakes

  • Hard-coding a site-packages path.
  • Confusing purelib and platlib.
  • Assuming every reported path exists or is writable.
  • Passing a missing configuration value to a command.
  • Copying packages directly instead of using packaging tools.
  • Executing compiler flags through an unsafe shell string.
  • Confusing build-host and target platforms.
  • Publishing complete diagnostics with internal paths.

Best practices

  • Query the interpreter that will actually execute the code.
  • Use preferred schemes rather than internal tables.
  • Handle None configuration values.
  • Check existence and permission separately.
  • Use modern packaging tools for installations.
  • Pass build commands as structured arguments.
  • Test virtual environments and every supported platform.
  • Collect only necessary diagnostic data.

Conclusion

Python sysconfig is the official source for installation paths, schemes, build variables, ABI information, and platform identifiers for the active interpreter. It prevents fragile assumptions in packaging tools, native-extension builds, and diagnostics.

Use the information as an environment description, not as authorization to write anywhere. Combine sysconfig with modern packaging, permission checks, and cross-platform tests. Consult the official sysconfig documentation and the Python Packaging User Guide when designing installers and build systems.

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    Hard drive representing memory-mapped files with Python mmap
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python mmap: Memory-Mapped Files

    Learn Python mmap to map files into memory, search bytes, share data, and choose read, write, or copy-on-write access safely.

    Ler mais

    Tempo de leitura: 6 minutos
    09/08/2026
    Source code representing parser tokens and constants with the Python token module
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python token: Parser Constants

    Learn Python token constants for lexical types, exact operators, indentation, f-strings, t-strings, and version-aware parsers.

    Ler mais

    Tempo de leitura: 7 minutos
    07/08/2026
    Source code representing reserved words and soft keywords in Python
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python keyword: Reserved Words

    Learn Python keyword to validate identifiers, reserved words, and soft keywords for the target interpreter version.

    Ler mais

    Tempo de leitura: 5 minutos
    07/08/2026
    Software architecture representing abstract base classes with Python abc
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python abc: Abstract Base Classes

    Learn Python abc to create abstract classes, required methods, virtual subclasses, and stable runtime contracts.

    Ler mais

    Tempo de leitura: 5 minutos
    06/08/2026
    Code and structures representing runtime types with the Python types module
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python types: Runtime Type Utilities

    Learn Python types for SimpleNamespace, MappingProxyType, runtime type names, and safe dynamic class creation.

    Ler mais

    Tempo de leitura: 5 minutos
    06/08/2026
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python sched: Schedule Events

    Learn Python sched to schedule events, control priorities, cancel tasks, and build recurring work with a monotonic clock.

    Ler mais

    Tempo de leitura: 7 minutos
    05/08/2026