How to Import Modules in a Large Python Project
You’ll structure your project as a package and use stable imports that keep working as you add more files.
What you’ll build or solve
You’ll set up a package folder, import modules using absolute imports, and run your code in a way that matches how Python resolves imports. Done looks like your imports keep working when you move code into new folders.
Learn Python on Mimo
When this approach works best
This approach works best when you:
- Split code into multiple folders like
api/,services/,models/, andutils/. - Run code from more than one entry point, such as a CLI script and a web server.
- Collaborate with teammates and want imports that behave the same on every machine.
Avoid this approach when:
- You have a single-file script. A full package layout will slow you down.
Prerequisites
- Python installed
- A code editor
- Basic terminal familiarity
- Comfort with files and folders
Step-by-step instructions
1) Put your code under one top-level package
Give your project a single import root by putting code under one package folder.
Example structure:
CSS
my_project/
src/
my_app/
__init__.py
main.py
utils/
__init__.py
formatting.py
services/
__init__.py
billing.py
tests/
test_billing.py
Minimal module:
Python
# src/my_app/utils/formatting.py
defformat_money(amount_cents:int) ->str:
returnf"${amount_cents/100:.2f}"
What to look for
Each folder you want to import from includes an __init__.py. This tells Python it’s a package.
2) Prefer absolute imports inside the project
Absolute imports start from your package name. They stay readable and survive refactors better.
Python
# src/my_app/services/billing.py
frommy_app.utils.formattingimportformat_money
definvoice_line(amount_cents:int) ->str:
returnf"Total:{format_money(amount_cents)}"
What to look for
Imports begin with my_app, not .. or filesystem paths.
3) Run your code from the project root using m
Many import errors happen because a file gets run directly from inside a package folder. Running as a module from the project root gives Python the package context it expects.
From the project root:
python-m my_app.main
Example main.py:
# src/my_app/main.py
frommy_app.services.billingimportinvoice_line
defmain() ->None:
print(invoice_line(1299))
if__name__=="__main__":
main()
What to look for
If python -m my_app.main works, your package structure and absolute imports line up.
If python src/my_app/main.py fails but python -m my_app.main works, the issue is how you’re running the code.
4) Import from sibling modules without changing your working directory
In large projects, you’ll often move between folders. Keep one habit consistent: run from the project root.
From the root, you can run other entry points the same way:
python-m my_app.services.billing
To make that runnable, add a small __main__ block:
Python
# src/my_app/services/billing.py
frommy_app.utils.formattingimportformat_money
definvoice_line(amount_cents:int) ->str:
returnf"Total:{format_money(amount_cents)}"
if__name__=="__main__":
print(invoice_line(2500))
What to look for
If imports break only when you cd into subfolders, go back to the root and run with python -m ....
5) Use __init__.py for shorter imports
If you find yourself importing deep paths everywhere, you can re-export names from a package folder.
# src/my_app/utils/__init__.py
frommy_app.utils.formattingimportformat_money
__all__= ["format_money"]
Now you can write:
frommy_app.utilsimportformat_money
What to look for
Keep re-exports small. Too many can make it harder to trace where code lives.
Examples you can copy
Example 1: Import a helper from utils/
# src/my_app/utils/slug.py
defslugify(text:str) ->str:
returntext.strip().lower().replace(" ","-")
# src/my_app/main.py
frommy_app.utils.slugimportslugify
defmain() ->None:
print(slugify("Hello World"))
if__name__=="__main__":
main()
Run:
python-m my_app.main
Example 2: Split logic across modules
PHP
# src/my_app/services/math_tools.py
defadd(a:int,b:int) ->int:
returna+b
# src/my_app/main.py
frommy_app.services.math_toolsimportadd
print(add(2,3))
Run:
python-m my_app.main
Example 3: Tests that import your package
# tests/test_formatting.py
frommy_app.utils.formattingimportformat_money
deftest_format_money() ->None:
assertformat_money(250)=="$2.50"
Run from the project root:
python-m pytest
Common mistakes and how to fix them
Mistake 1: Running a file directly and breaking imports
You might run:
CSS
python src/my_app/main.py
Why it breaks
Python sets a different import root, so from my_app... may fail with ModuleNotFoundError.
Fix
Run it as a module from the project root:
python-m my_app.main
Mistake 2: Adding sys.path hacks to “make imports work”
You might write:
importsys
sys.path.append("..")
Why it breaks
It depends on the current working directory, so behavior changes across terminals, IDEs, and CI.
Fix
Use a real package layout and run from the root with python -m package.module.
Troubleshooting
If you see: ModuleNotFoundError: No module named 'my_app'
Confirm you’re running from the project root and using:
python-m my_app.main
Also confirm your package folder exists under src/my_app/ or your chosen root.
If you see: ImportError: attempted relative import with no known parent package
You ran a module directly. Run it with:
Java
python-m package.module
from the project root.
If imports work in your IDE but fail in the terminal
Your IDE may add paths automatically. Run from the project root and use the same interpreter in your terminal and IDE.
If you see: cannot import name ... from partially initialized module ...
You likely have a circular import. Move shared code into a third module, or delay one import by moving it inside a function.
Quick recap
- Put code under one top-level package folder, such as
src/my_app/. - Use absolute imports starting with your package name.
- Run from the project root with
python -m package.module. - Avoid
sys.pathhacks that depend on where you run commands. - If you hit “partially initialized module,” check for circular imports.
Join 35M+ people learning for free on Mimo
4.8 out of 5 across 1M+ reviews
Check us out on Apple AppStore, Google Play Store, and Trustpilot