Skip to content

Overleaf uses the latexmk build tool to automatically build your project. latexmk ensures that we run LaTeX and BibTeX (or other similar programs) the right number of times. latexmk reads a configuration file called latexmkrc that contains custom rules for building your project. By default, Overleaf automatically adds an invisible latexmkrc file to your project in order to build it. That latexmkrc file contains rules for glossaries, nomenclature, and other commonly used packages. In full, it currently reads:

###############################
# Post processing of pdf file #
###############################

# assume the jobname is 'output' for Overleaf v2
my $ORIG_PDF_AGE = -M "output.pdf"; # get age of existing pdf if present

END {
    my $NEW_PDF_AGE = -M "output.pdf";
    return if !defined($NEW_PDF_AGE); # bail out if no pdf file
    return if defined($ORIG_PDF_AGE) && $NEW_PDF_AGE == $ORIG_PDF_AGE; # bail out if pdf was not updated
    my $QPDF = "/usr/bin/qpdf";
    return if ! -x $QPDF; # check that qpdf exists
    my $status = system($QPDF, "--linearize", "output.pdf", "output.pdf.opt");
    my $exitcode = ($status >> 8);
    print "qpdf exit code=$exitcode\n";
    # qpdf returns 0 for success, 3 for warnings (output pdf still created)
    return if !($exitcode == 0 || $exitcode == 3);
    print "Renaming optimised file to output.pdf\n";
    rename("output.pdf.opt", "output.pdf");
}

##############
# Glossaries #
##############
add_cus_dep( 'glo', 'gls', 0, 'glo2gls' );
add_cus_dep( 'acn', 'acr', 0, 'glo2gls');  # from Overleaf v1
sub glo2gls {
	system("makeglossaries $_[0]");
}

#############
# makeindex #
#############
@ist = glob("*.ist");
if (scalar(@ist) > 0) {
        $makeindex = "makeindex -s $ist[0] %O -o %D %S";
}

################
# nomenclature #
################
add_cus_dep("nlo", "nls", 0, "nlo2nls");
sub nlo2nls {
	system("makeindex $_[0].nlo -s nomencl.ist -o $_[0].nls -t $_[0].nlg");
}

#########
# Knitr #
#########
my $root_file = $ARGV[-1];

add_cus_dep( 'Rtex', 'tex', 0, 'rtex_to_tex');
sub rtex_to_tex {
    do_knitr("$_[0].Rtex");
}

sub do_knitr {
    my $dirname = dirname $_[0];
    my $basename = basename $_[0];
    system("Rscript -e \"library('knitr'); setwd('$dirname'); knit('$basename')\"");
}

my $rtex_file = $root_file =~ s/\.tex$/.Rtex/r;
unless (-e $root_file) {
	if (-e $rtex_file) {
		do_knitr($rtex_file);
	}
}

##########
# feynmf #
##########
push(@file_not_found, '^feynmf: Files .* and (.*) not found:$');
add_cus_dep("mf", "tfm", 0, "mf_to_tfm");
sub mf_to_tfm { system("mf '\\mode:=laserjet; input $_[0]'"); }

push(@file_not_found, '^feynmf: Label file (.*) not found:$');
add_cus_dep("mf", "t1", 0, "mf_to_label1");
sub mf_to_label1 { system("mf '\\mode:=laserjet; input $_[0]' && touch $_[0].t1"); }
add_cus_dep("mf", "t2", 0, "mf_to_label2");
sub mf_to_label2 { system("mf '\\mode:=laserjet; input $_[0]' && touch $_[0].t2"); }
add_cus_dep("mf", "t3", 0, "mf_to_label3");
sub mf_to_label3 { system("mf '\\mode:=laserjet; input $_[0]' && touch $_[0].t3"); }
add_cus_dep("mf", "t4", 0, "mf_to_label4");
sub mf_to_label4 { system("mf '\\mode:=laserjet; input $_[0]' && touch $_[0].t4"); }
add_cus_dep("mf", "t5", 0, "mf_to_label5");
sub mf_to_label5 { system("mf '\\mode:=laserjet; input $_[0]' && touch $_[0].t5"); }
add_cus_dep("mf", "t6", 0, "mf_to_label6");
sub mf_to_label6 { system("mf '\\mode:=laserjet; input $_[0]' && touch $_[0].t6"); }
add_cus_dep("mf", "t7", 0, "mf_to_label7");
sub mf_to_label7 { system("mf '\\mode:=laserjet; input $_[0]' && touch $_[0].t7"); }
add_cus_dep("mf", "t8", 0, "mf_to_label8");
sub mf_to_label8 { system("mf '\\mode:=laserjet; input $_[0]' && touch $_[0].t8"); }
add_cus_dep("mf", "t9", 0, "mf_to_label9");
sub mf_to_label9 { system("mf '\\mode:=laserjet; input $_[0]' && touch $_[0].t9"); }

##########
# feynmp #
##########
push(@file_not_found, '^dvipdf: Could not find figure file (.*); continuing.$');
add_cus_dep("mp", "1", 0, "mp_to_eps");
sub mp_to_eps {
    system("mpost $_[0]");
    return 0;
}

#############
# asymptote #
#############
sub asy {return system("asy --offscreen '$_[0]'");}
add_cus_dep("asy","eps",0,"asy");
add_cus_dep("asy","pdf",0,"asy");
add_cus_dep("asy","tex",0,"asy");

#############
# metapost  #  # from Overleaf v1
#############
add_cus_dep('mp', '1', 0, 'mpost');
sub mpost {
  my $file = $_[0];
  my ($name, $path) = fileparse($file);
  pushd($path);
  my $return = system "mpost $name";
  popd();
  return $return;
}

##########
# chktex #
##########
unlink 'output.chktex' if -f 'output.chktex';
if (defined $ENV{'CHKTEX_OPTIONS'}) {
    use File::Basename;
    use Cwd;

    # identify the main file
    my $target = $ARGV[-1];
    my $file = basename($target);

    if ($file =~ /\.tex$/) {
	# change directory for a limited scope
	my $orig_dir = cwd();
	my $subdir = dirname($target);
	chdir($subdir);
	# run chktex on main file
	$status = system(
    "/usr/bin/run-chktex.sh",
    $orig_dir,
    $file
  );
	# go back to original directory
	chdir($orig_dir);

	# in VALIDATE mode we always exit after running chktex
	# otherwise we exit if EXIT_ON_ERROR is set

	if ($ENV{'CHKTEX_EXIT_ON_ERROR'} || $ENV{'CHKTEX_VALIDATE'}) {
	    # chktex doesn't let us access the error info via exit status
	    # so look through the output
	    open(my $fh, "<", "output.chktex");
	    my $errors = 0;
	    {
		local $/ = "\n";
		while(<$fh>) {
		    if (/^\S+:\d+:\d+: Error:/) {
			$errors++;
			print;
		    }
		}
	    }
	    close($fh);
	    exit(1) if $errors > 0;
	    exit(0) if $ENV{'CHKTEX_VALIDATE'};
	}
    }
}

You can customise the build process by adding a custom latexmkrc file to your project. If you have a file called latexmkrc in your project, Overleaf will not add the default latexmkrc file, so you may want to copy the default latexmkrc above into your latexmkrc file, to make sure that the rules above are still included.

Note that some latexmk options are not compatible with Overleaf. In particular, if you set the $preview_continuous_mode or $output_dir options, that may break the preview on Overleaf.

If you want to build your Overleaf project offline, for example via the Overleaf-git bridge, using latexmk, you may want to copy the latexmkrc file to your project locally, to make sure it builds in the same way as we build it on Overleaf. Note also that on Overleaf v2, the job name is always output for the build to work correctly.

For more information about latexmkrc files, check out our blog post with tips and tricks from our friendly Overleaf TeXperts.

Overleaf guides

LaTeX Basics

Mathematics

Figures and tables

References and Citations

Languages

Document structure

Formatting

Fonts

Presentations

Commands

Field specific

Class files

Advanced TeX/LaTeX