To get the current directory in Python, call os.getcwd() - it returns the process working directory, the folder you were in when the program started. That is the answer most searches want, and it is also the answer that quietly breaks in production. os.getcwd() is not where your .py file lives. It is where the process was launched. Run the same script from a different folder, from cron, or from a container that starts at /, and the value changes underneath you. When you want the location of the script itself, you want __file__ and pathlib, not getcwd.
Half the confusion around this comes from treating two different questions as one. Where am I running from, and where does this file live, are not the same thing - and mixing them up is how a script that works on your laptop reads the wrong config file on the server.
Table of contents
- Getting the working directory with os.getcwd
- Getting the directory the script actually lives in
- Why the distinction breaks in production
- The rule: never depend on the working directory for your own files
- Changing and checking the directory
- How this fits the rest of the stack
- FAQ
Getting the working directory with os.getcwd
The direct answer, and it is one line:
import os
print(os.getcwd())
# /home/deploy/app
os.getcwd() returns an absolute path to the current working directory - the directory the process inherited from whatever launched it. Open a shell in /home/deploy/app, run python script.py, and you get /home/deploy/app. Change into /tmp first and run the same file by absolute path, and you get /tmp.
The modern equivalent returns a Path object instead of a string, which is usually what you want:
from pathlib import Path
print(Path.cwd())
# /home/deploy/app
Both read the same underlying value. The difference is that Path.cwd() gives you something you can join, resolve, and glob without stringly-typed os.path.join calls everywhere. If you are on Python 3, reach for pathlib first.
Getting the directory the script actually lives in
This is the one people actually need and rarely ask for by name. To find the folder containing the running .py file, use __file__:
from pathlib import Path
HERE = Path(__file__).resolve().parent
config = HERE / "config.yaml"
print(config)
# /home/deploy/app/config.yaml - no matter where you launched from
Path(__file__).resolve().parent is stable. It does not care what the working directory is, because it is derived from the file’s own path. Run the script from /tmp, from cron, from a systemd unit, and config.yaml still resolves next to the script.
The .resolve() matters: without it, __file__ can be a relative path depending on how the interpreter was invoked, and joining a relative base with a relative file gives you a path that still depends on the cwd. Resolve first, then join. That one habit removes an entire category of it-works-on-my-machine bugs.
Why the distinction breaks in production
On your laptop, the working directory and the script directory are usually the same folder, because you cd into the project and run it there. So the two look interchangeable, and code that reads open("config.yaml") works.
Then it ships. A cron job runs with the working directory set to the user’s home. A systemd service starts at /. A container’s entrypoint launches from /app but the file lives in /app/src. In every one of those cases, a bare open("config.yaml") looks in the wrong place and throws FileNotFoundError - for a file that is sitting right next to your script.
The failure is confusing precisely because the file exists. The path is relative, and relative means relative to the cwd, and the cwd is not what you assumed. This is the single most common reason a script that ran fine locally cannot find its own data files once it is deployed.
The rule: never depend on the working directory for your own files
The working directory belongs to whoever launched the process. Treat it as untrusted input, not as a base path for your assets.
- For files that ship with your code - templates, config, fixtures - anchor them to
Path(__file__).resolve().parent. - For files the user points you at - an input path on the command line -
os.getcwd()is the right base, because the user’s cwd is exactly the context they mean. - Never write
open("data/thing.json")and hope. Build the absolute path explicitly.
from pathlib import Path
BASE = Path(__file__).resolve().parent
DATA = BASE / "data" / "thing.json"
with DATA.open() as f:
payload = f.read()
If you must change the working directory, do it deliberately with os.chdir() and know that it is process-global - it affects every relative path in the whole program from that point on. That global reach is why depending on it for library code is a bad idea.
Changing and checking the directory
Occasionally you do want to move the process:
import os
from pathlib import Path
os.chdir("/var/log")
print(os.getcwd()) # /var/log
# a context-managed change (3.11+) that restores the old cwd on exit
from contextlib import chdir
with chdir("/tmp"):
... # cwd is /tmp in here
# cwd is back to what it was
contextlib.chdir is the clean way to scope a directory change so you do not leave the rest of the program in a surprising state. Before 3.11, people wrote their own context manager to save os.getcwd(), chdir, and restore in a finally - the built-in version just does that for you.
The takeaway is small but load-bearing: os.getcwd() answers where am I, __file__ answers where is this code, and confusing the two is what turns a green local run into a red deploy.
How this fits the rest of the stack
A script that reads its own files by absolute path is a script that behaves the same on your laptop and on the box it deploys to. When that script becomes a service with a database and storage behind it, the working-directory question stops being about one file and starts being about the whole runtime. The RunxBuild hosting calculator lays out the service, database, storage, and bandwidth as separate line items, and the RunxBuild dashboard is where the team watches deploys, logs, and restarts as they happen.
Useful related references:
- Python Environment Variables: os.environ, .env Files, and pydantic
- Python Secrets: How to Stop Hardcoding Them, Where to Put Them, and the Pattern That Scales
- server.js Not Included in npm run build: What Next.js Produces, What You Have to Ship, and Where It Actually Lives
- Python services on RunxBuild
FAQ
How do I get the current directory in Python?
Call os.getcwd(), which returns the absolute path of the process working directory, or Path.cwd() from pathlib for a Path object. Both give you where the program was launched from - not necessarily where the script file lives.
What is the difference between os.getcwd and file?
os.getcwd() returns the working directory the process inherited from whatever launched it, which changes depending on where you run the program. __file__ is the path of the script itself, so Path(__file__).resolve().parent always points to the folder containing your code regardless of the working directory.
Why does my Python script say file not found when the file is right there?
Because you opened it with a relative path and the working directory is not the folder you assumed. Cron, systemd, and containers often start with a different cwd than your terminal. Anchor the file to Path(__file__).resolve().parent instead of relying on the cwd.
How do I get the script directory instead of the working directory?
Use Path(__file__).resolve().parent. The .resolve() makes the path absolute so it does not depend on how the interpreter was invoked, and .parent gives you the containing folder. Join your files onto that base.
How do I change the current directory in Python?
Use os.chdir(path). On Python 3.11 and later, contextlib.chdir(path) used as a context manager changes the directory temporarily and restores the previous one on exit, which avoids leaving the rest of the program in an unexpected working directory.