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.14The 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 sysconfigThe 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 pathRun the suite on Windows, Linux, macOS, and virtual environments when those platforms are supported.
Common mistakes
- Hard-coding a
site-packagespath. - Confusing
purelibandplatlib. - 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
Noneconfiguration 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.







