__main__.py
Python
programming
Python scripts
Python modules

What is __main__.py?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

__main__.py is the file Python executes when you run a package with python -m package_name or when the package is used as an executable archive. It gives a package a command-line entry point without requiring users to target a specific module file manually.

The Core Idea

A Python package is normally a directory with Python modules in it. When you run:

bash
python -m mypackage

Python looks inside mypackage for __main__.py and executes it.

That means __main__.py is to a package what a top-level script file is to a standalone program: the place where execution begins.

A Minimal Example

Suppose your project looks like this:

text
1mypackage/
2    __init__.py
3    __main__.py
4    tools.py

And __main__.py contains:

python
1from .tools import greet
2
3def main():
4    greet("world")
5
6if __name__ == "__main__":
7    main()

With tools.py:

python
def greet(name):
    print(f"Hello, {name}!")

Now this command works:

bash
python -m mypackage

Python runs mypackage/__main__.py, which imports greet and executes main().

Why Not Just Use if __name__ == '__main__' In Any File

That pattern and __main__.py are related, but not identical.

The if __name__ == "__main__": block controls what happens when one specific module file is executed as a script. __main__.py defines what happens when the package itself is executed.

So these solve different entry-point problems:

  • 'script.py with a __name__ == "__main__" guard makes a module directly runnable'
  • 'package/__main__.py makes the package runnable with python -m package'

Both are useful. They are just aimed at different invocation styles.

Why python -m Is Nice

Running a package with python -m has practical benefits.

  • imports resolve relative to package structure more naturally
  • users run the package by name instead of by path
  • the project feels more like a real tool than an ad hoc script

For command-line applications distributed as Python packages, __main__.py is a clean default entry point.

A Realistic CLI Pattern

A common pattern is to keep command-line argument parsing in __main__.py and move business logic into other modules.

python
1import argparse
2from .tools import greet
3
4
5def main():
6    parser = argparse.ArgumentParser()
7    parser.add_argument("name", nargs="?", default="world")
8    args = parser.parse_args()
9    greet(args.name)
10
11if __name__ == "__main__":
12    main()

This keeps the entry-point file small while the reusable logic lives elsewhere.

That separation matters because __main__.py should usually coordinate execution, not contain the entire application.

Zip Apps And Executable Archives

__main__.py also matters for Python zip applications. If a zip archive contains a top-level __main__.py, Python can execute it directly.

That means __main__.py is not only about packages on disk. It is also part of Python's executable-package model more broadly.

Import Behavior And Relative Imports

Inside __main__.py, you often use relative imports such as:

python
from .tools import greet

That is one reason invoking the package with python -m mypackage is better than trying to run mypackage/__main__.py as a raw file path. The module execution path preserves package context properly.

If you bypass that and run the file directly in the wrong way, relative imports may fail.

When You Do Not Need __main__.py

Not every package needs one. Library packages that are meant only to be imported may not need any command-line entry point at all.

Use __main__.py when:

  • the package should be executable
  • you want python -m package_name to work
  • you are building a CLI or small tool package

Skip it when the package is only a library.

Common Pitfalls

  • Confusing __main__.py with the if __name__ == "__main__" idiom in an arbitrary module.
  • Putting too much business logic directly into __main__.py instead of delegating to other modules.
  • Running package/__main__.py as a raw file path and then being surprised when relative imports break.
  • Assuming every package needs __main__.py even when it is only meant to be imported.
  • Forgetting that python -m package_name is the execution style that makes __main__.py relevant.

Summary

  • '__main__.py is the package entry point for python -m package_name.'
  • It lets a package behave like an executable program.
  • It is related to, but different from, the if __name__ == "__main__" pattern in a single module.
  • Keep __main__.py small and delegate real logic to reusable modules.
  • Use it when the package should be runnable, not just importable.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.