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

    Programmer analyzing code to identify file MIME types with Python
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    mimetypes.guess_file_type: Detect MIME Types

    Learn Python mimetypes.guess_file_type for MIME detection in paths, URLs, uploads, and HTTP responses with safe fallbacks.

    Ler mais

    Tempo de leitura: 5 minutos
    13/09/2026
    Server components representing isolated Python interpreters running in parallel
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    InterpreterPoolExecutor: True Parallelism in Python

    Learn Python InterpreterPoolExecutor for CPU-bound tasks, isolated interpreters, true parallelism, and safer concurrency design.

    Ler mais

    Tempo de leitura: 6 minutos
    13/09/2026
    Microprocessor representing CPUs available to a Python process
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    os.process_cpu_count: Count Available CPUs

    Learn Python os.process_cpu_count to size workers according to the CPUs actually available to the process.

    Ler mais

    Tempo de leitura: 4 minutos
    12/09/2026
    Laptop with digital code representing SQLite BLOB data
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    sqlite3.Blob: Incremental BLOB Reads and Writes

    Learn Python sqlite3.Blob for incremental BLOB reads and writes, lower memory use, and safer binary data handling in SQLite.

    Ler mais

    Tempo de leitura: 5 minutos
    12/09/2026
    Statistical analysis for Python random.binomialvariate
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    random.binomialvariate: Simulate Binomial Outcomes

    Learn Python random.binomialvariate to simulate successes, validate probabilities, and analyze binomial scenarios with practical examples.

    Ler mais

    Tempo de leitura: 5 minutos
    11/09/2026
    Python source code and function signature analysis
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    inspect.signature.bind: Validate Function Arguments

    Learn Python inspect.signature.bind to validate arguments, apply defaults, and build safer decorators and dynamic APIs.

    Ler mais

    Tempo de leitura: 4 minutos
    11/09/2026