Portable Stata Projects: Running the Same Do-File on Any Computer

Hard-coded file paths are one of the most common obstacles to reproducible Stata projects. A path such as

global main_path "C:/Users/jamel/Dropbox/Revision-MDY-25-07-china-provinces-uncertainty"

works on one computer, but it may fail on another computer because the username, drive letter, Dropbox location, or operating system is different.

A better solution is to let Stata identify the project root from its current working directory.

The project structure

The project shown in the screenshot has the following organization:

Revision-MDY-25-07-china-provinces-uncertainty/
├── code/
├── data/
├── results/
└── revision/

The folder Revision-MDY-25-07-china-provinces-uncertainty is the project root. The portable setup should work when Stata is launched from the root or from any of its four main subdirectories.

Complete portable setup

The following code reflects the actual folder structure:

*-------------------------------------------------------------------------------
* Portable project paths
*
* The do-file may be launched from:
*   - the project root
*   - code
*   - data
*   - results
*   - revision
*-------------------------------------------------------------------------------

* Store Stata's current working directory
local here "`c(pwd)'"

* Use forward slashes on all operating systems
local here : subinstr local here "\" "/", all

* Remove a trailing slash, if one is present
if substr("`here'", -1, 1) == "/" {
    local here = substr("`here'", 1, strlen("`here'") - 1)
}

* Extract the name of the current folder
local last_folder = lower(substr( ///
    "`here'", ///
    strrpos("`here'", "/") + 1, ///
    . ///
))

* If Stata is in a project subfolder, move to the project root
if inlist( ///
    "`last_folder'", ///
    "code", ///
    "data", ///
    "results", ///
    "revision" ///
) {
    quietly cd ..
}

* Store and normalize the project-root path
local root "`c(pwd)'"
local root : subinstr local root "\" "/", all

* Define the main project directories
global main_path "`root'"
global code      "${main_path}/code"
global data      "${main_path}/data"
global results   "${main_path}/results"
global revision  "${main_path}/revision"

* Verify that the required folders exist
foreach folder in code data revision {

    capture cd "${main_path}/`folder'"

    if _rc {
        display as error ///
            "Required folder not found: ${main_path}/`folder'"
        display as error ///
            "Current candidate root: ${main_path}"
        exit 170
    }

    quietly cd "${main_path}"
}

* Create the results folder if it does not yet exist
capture mkdir "${results}"

* Verify that the results folder can be opened
capture cd "${results}"

if _rc {
    display as error ///
        "Results directory could not be opened: ${results}"
    exit 603
}

* Finish the setup in the project root
quietly cd "${main_path}"

display as text "Project root: ${main_path}"

How the code works

1. Read the current working directory

Stata stores its current working directory in c(pwd):

local here "`c(pwd)'"

On the computer shown in the screenshot, it might initially contain:

C:\Users\jamel\Dropbox\Revision-MDY-25-07-china-provinces-uncertainty

If Stata was opened from the code folder, it might instead contain:

C:\Users\jamel\Dropbox\Revision-MDY-25-07-china-provinces-uncertainty\code

The exact location does not need to be written into the do-file.

2. Standardize the directory separators

Windows typically uses backslashes:

C:\Users\jamel\Dropbox\project

macOS and Linux use forward slashes:

/Users/jamel/Dropbox/project

The following command replaces all backslashes with forward slashes:

local here : subinstr local here "\" "/", all

The Windows path therefore becomes:

C:/Users/jamel/Dropbox/project

Stata accepts forward slashes on Windows, macOS, and Linux. Using a common separator makes the remaining code easier to manage.

3. Identify the current folder

This block extracts the final component of the path:

local last_folder = lower(substr( ///
    "`here'", ///
    strrpos("`here'", "/") + 1, ///
    . ///
))

For example, suppose the working directory is:

C:/Users/jamel/Dropbox/project/code

The function strrpos() finds the position of the final slash. The function substr() then extracts everything after that slash.

The result is:

code

The lower() function converts the folder name to lowercase. Consequently, code, Code, and CODE are treated identically.

4. Move to the project root

The following condition checks whether Stata is currently in one of the four project subdirectories:

if inlist( ///
    "`last_folder'", ///
    "code", ///
    "data", ///
    "results", ///
    "revision" ///
) {
    quietly cd ..
}

When Stata is in code, data, results, or revision, the command

cd ..

moves one level upward.

For example:

.../Revision-MDY-25-07-china-provinces-uncertainty/code

becomes:

.../Revision-MDY-25-07-china-provinces-uncertainty

When Stata is already in the project root, no directory change is needed.

5. Define reusable project paths

Once Stata has identified the root, the code creates four global macros:

global code      "${main_path}/code"
global data      "${main_path}/data"
global results   "${main_path}/results"
global revision  "${main_path}/revision"

On one computer, they might expand to:

C:/Users/jamel/Dropbox/Revision-MDY-25-07-china-provinces-uncertainty/code

On a coauthor’s computer, they might expand to:

D:/Dropbox/Revision-MDY-25-07-china-provinces-uncertainty/code

On macOS, the same macro might become:

/Users/coauthor/Dropbox/Revision-MDY-25-07-china-provinces-uncertainty/code

The Stata code remains unchanged in all three cases.

Using the project paths

Data can be loaded with:

use "${data}/china_provinces.dta", clear

Another do-file can be executed with:

do "${code}/estimation.do"

A graph can be exported with:

graph export ///
    "${results}/threshold_LR.png", ///
    as(png) replace width(2400)

A document in the revision folder can be referenced with:

global response_letter ///
    "${revision}/response_to_reviewers.docx"

Explicit paths are preferable to repeatedly changing the working directory. Each command makes clear whether the file is an input, a program, a result, or a revision document.

Checking that the project is correctly identified

The setup verifies that the expected folders exist:

foreach folder in code data revision {
    capture cd "${main_path}/`folder'"

    if _rc {
        display as error ///
            "Required folder not found: ${main_path}/`folder'"
        exit 170
    }

    quietly cd "${main_path}"
}

The capture prefix prevents Stata from stopping immediately when a directory is missing. Instead, the return code is stored in _rc.

When _rc is nonzero, Stata prints an informative message such as:

Required folder not found:
C:/Users/jamel/Dropbox/wrong-directory/data

Current candidate root:
C:/Users/jamel/Dropbox/wrong-directory

This is much easier to diagnose than a later generic “file not found” error.

Creating the results directory automatically

Input folders such as data should normally already exist. The results folder, however, can safely be created by the do-file:

capture mkdir "${results}"

If the directory already exists, capture suppresses the resulting warning. If it does not exist, Stata creates it.

The code then checks whether the directory can actually be opened:

capture cd "${results}"

if _rc {
    display as error ///
        "Results directory could not be opened: ${results}"
    exit 603
}

This helps identify problems such as a missing folder, an inaccessible Dropbox directory, or insufficient write permissions before tables and graphs are exported.

An important limitation

This approach uses c(pwd), which is Stata’s current working directory. It does not automatically detect the physical location of the do-file.

The method therefore works when Stata’s current directory is one of the following:

project root
project root/code
project root/data
project root/results
project root/revision

It will not identify the project correctly when the current working directory is unrelated to the project. For example, running a do-file stored in code while Stata remains in Documents will make c(pwd) point to Documents, not to the do-file.

A practical routine is therefore to open the project root in Stata before running the main do-file, or to launch the analysis while Stata is already positioned in one of the recognized project folders.

Conclusion

Portable project paths eliminate usernames, drive letters, and computer-specific Dropbox locations from Stata code. The do-file derives the project root from c(pwd), standardizes path separators, identifies whether it was launched from a subdirectory, and defines reusable paths for code, data, results, and revision.

The same project can consequently be moved between computers without rewriting its directory definitions. This improves collaboration, simplifies replication, and prevents many avoidable file-path errors.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.