Skip to main content

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:

  1. The directory containing the current script.
  2. Directories listed in the PYTHONPATH environment variable.
  3. 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

MethodPriorityUse When
sys.path.insert(0, path)Highest, searched firstYou want your module to take precedence over any same-named module in other paths
sys.path.append(path)Lowest, searched lastYou want standard library and installed packages to take precedence
Avoid hardcoding absolute paths

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
Making PYTHONPATH persistent

The 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 export line to your ~/.bashrc, ~/.zshrc, or ~/.profile file.

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:

main.py
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.path globally.
  • 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!
When to use each method
MethodBest For
sys.path.insert/appendQuick scripts, prototyping, one-off imports
PYTHONPATHTeam environments, CI/CD pipelines, consistent configurations
importlibPlugin systems, dynamic loading, runtime-determined paths
Package with __init__.pyStructured 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
note

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() or sys.path.append() are the simplest options.
  • For environment-level configuration, PYTHONPATH keeps your code clean by externalizing path management. For dynamic or plugin-based loading, importlib offers maximum flexibility.
  • For production projects, structuring your code as a proper package with __init__.py files is the most maintainable and professional approach. Whichever method you choose, avoid hardcoding absolute paths and prefer relative, portable path construction using pathlib or os.path.