How to Import Modules From Another Folder in Python
When working on large Python projects, your code is often organized across multiple directories. You may need to import a module that lives in a completely different folder from your current script. By default, Python only searches a limited set of directories for modules, so importing from arbitrary locations requires some configuration.
In this guide, you will learn multiple methods to import Python modules from another folder, understand how Python's module search path works, and discover best practices to keep your imports clean and maintainable.
Understanding Python's Module Search Path
Before importing from another folder, it helps to understand where Python looks for modules. When you write import module_name, Python searches these locations in order:
- The directory containing the current script.
- Directories listed in the
PYTHONPATHenvironment variable. - The default installation-dependent directories (for example,
site-packages).
All of these paths are stored in the sys.path list:
import sys
for path in sys.path:
print(path)
If your target module's folder is not in any of these paths, the import will fail with a ModuleNotFoundError.
Setting Up the Example
For all the methods below, assume the following project structure:
Desktop/
├── Task/
│ └── modules/
│ └── module0.py
└── Projects/
└── ImportModule/
└── main.py
The module we want to import (module0.py) contains:
# module0.py
def run():
print("Module 0 imported successfully")
Our goal is to import module0 from main.py, even though they are in completely different directories.
Method 1: Using sys.path.insert() or sys.path.append()
The most common approach is to programmatically add the target folder to Python's module search path at runtime using sys.path.
Using sys.path.insert()
sys.path.insert(0, path) adds the directory at the beginning of the search path, giving it the highest priority:
# main.py
import sys
# Add the modules folder to the beginning of the search path
sys.path.insert(0, "C:\\Users\\tom\\Desktop\\Task\\modules")
# Now Python can find module0
import module0
module0.run()
Output:
Module 0 imported successfully
Using sys.path.append()
sys.path.append(path) adds the directory at the end of the search path:
# main.py
import sys
# Add the modules folder to the end of the search path
sys.path.append("C:\\Users\\tom\\Desktop\\Task\\modules")
import module0
module0.run()
Output:
Module 0 imported successfully
Difference Between insert and append
| Method | Priority | Use When |
|---|---|---|
sys.path.insert(0, path) | Highest, searched first | You want your module to take precedence over any same-named module in other paths |
sys.path.append(path) | Lowest, searched last | You want standard library and installed packages to take precedence |
Hardcoding paths like "C:\\Users\\tom\\Desktop\\Task\\modules" makes your code non-portable. Use os.path or pathlib to build paths dynamically:
# ❌ Hardcoded: breaks on other machines
sys.path.insert(0, "C:\\Users\\tom\\Desktop\\Task\\modules")
# ✅ Relative to the current script's location
import os
module_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'Task', 'modules'))
sys.path.insert(0, module_path)
Or with pathlib:
from pathlib import Path
module_path = Path(__file__).resolve().parent.parent.parent / "Task" / "modules"
sys.path.insert(0, str(module_path))
Method 2: Using the PYTHONPATH Environment Variable
Instead of modifying sys.path inside your code, you can set the PYTHONPATH environment variable before running your script. Python automatically adds all directories listed in PYTHONPATH to sys.path.
Setting PYTHONPATH on Windows
set PYTHONPATH=C:\Users\tom\Desktop\Task\modules
python main.py
Setting PYTHONPATH on macOS/Linux
export PYTHONPATH=/home/tom/Desktop/Task/modules
python main.py
With PYTHONPATH set, your script needs no path manipulation at all:
# main.py: no sys.path modification needed
import module0
module0.run()
Output:
Module 0 imported successfully
PYTHONPATH persistentThe set and export commands only last for the current terminal session. To make them permanent:
- Windows: Add the variable through System Properties → Environment Variables.
- macOS/Linux: Add the
exportline to your~/.bashrc,~/.zshrc, or~/.profilefile.
Method 3: Using importlib for Dynamic Imports
When you need to import a module dynamically at runtime (for example, based on user input or configuration), use Python's importlib module along with spec_from_file_location:
import importlib.util
# Specify the full path to the module file
module_path = "C:\\Users\\tom\\Desktop\\Task\\modules\\module0.py"
# Create a module spec from the file location
spec = importlib.util.spec_from_file_location("module0", module_path)
# Create a module object from the spec
module0 = importlib.util.module_from_spec(spec)
# Execute the module to load its contents
spec.loader.exec_module(module0)
# Use the module
module0.run()
Output:
Module 0 imported successfully
This method is particularly useful when:
- The module path is determined at runtime.
- You want to load a specific file without affecting
sys.pathglobally. - You are building a plugin system that loads modules from arbitrary locations.
Method 4: Using Packages with __init__.py
If you control the project structure, the cleanest approach is to organize your code as a proper Python package. Add an __init__.py file (can be empty) to each directory that should be treated as a package:
MyProject/
├── main.py
├── utils/
│ ├── __init__.py
│ └── helpers.py
└── core/
├── __init__.py
└── engine.py
# helpers.py
def greet():
print("Hello from helpers!")
# main.py
from utils.helpers import greet
greet()
Output:
Hello from helpers!
| Method | Best For |
|---|---|
sys.path.insert/append | Quick scripts, prototyping, one-off imports |
PYTHONPATH | Team environments, CI/CD pipelines, consistent configurations |
importlib | Plugin systems, dynamic loading, runtime-determined paths |
Package with __init__.py | Structured projects, production codebases, pip-installable packages |
Common Mistakes and How to Fix Them
Mistake 1: Forgetting __init__.py in Package Directories
mypackage/
module1.py # No __init__.py!
# ❌ This fails with ModuleNotFoundError
from mypackage import module1
Fix: Add an __init__.py file (even an empty one) to the directory:
mypackage/
__init__.py # Makes it a package
module1.py
Starting with Python 3.3, namespace packages allow imports without __init__.py in some cases. However, including __init__.py is still considered a best practice for explicit package declaration.
Mistake 2: Circular Imports
If module_a.py imports from module_b.py and module_b.py imports from module_a.py, you get a circular import error:
# ❌ module_a.py
from module_b import function_b
# ❌ module_b.py
from module_a import function_a
Fix: Restructure your code to eliminate the cycle, or move the import inside the function that needs it:
# ✅ module_b.py: import inside the function
def some_function():
from module_a import function_a
function_a()
Mistake 3: Modifying sys.path After the Import Statement
# ❌ Import fails: path not yet added
import module0
import sys
sys.path.insert(0, "/path/to/modules")
Fix: Always modify sys.path before the import:
# ✅ Correct order
import sys
sys.path.insert(0, "/path/to/modules")
import module0
Conclusion
Python provides multiple ways to import modules from another folder, each suited to different scenarios.
- For quick prototyping,
sys.path.insert()orsys.path.append()are the simplest options. - For environment-level configuration,
PYTHONPATHkeeps your code clean by externalizing path management. For dynamic or plugin-based loading,importliboffers maximum flexibility. - For production projects, structuring your code as a proper package with
__init__.pyfiles is the most maintainable and professional approach. Whichever method you choose, avoid hardcoding absolute paths and prefer relative, portable path construction usingpathliboros.path.