Git Hash And Build Date In Rust Build

For command line tools, or for web sites, sometimes it’s helpful to have build date and git commit hash be part of binary.

Cargo has a feature that runs a rust program as part of build process.

Add the following to Cargo.toml:

name = "package_name"
# ...
build = ""

vergen = "3"

Here we are telling Cargo that before building (and checking etc), run, and further that has a dependency on vergen crate, so install it if needed.

Getting Date

Among other things can do to assist rust toolchain by printout out some instructions on STDOUT, and what we are interested in is setting environment variable that are active during compilation:

fn main() {

This will ensure that environment variable ENV_VAR is given the value ENV_VALUE during compilation.

So we can set the current date as environment variable during compilation. How to get it back?

Using std::env::var(), usual method for reading environment variables would not work, as that method is for reading environment variable with the compiled binary runs. We need to read the environment variable when the binary is being compiled. For that we have the env!() macro.

Getting Commit Hash

One way to get commit hash is to open .git/ and muck around with file system. Or to invoke git commands or even libgit2.

The approach we will use is to rely on vergen crate:

fn main() {
        vergen::ConstantsFlags::BUILD_TIMESTAMP |
    .expect("unable to generate vergen keys");

Instead of printing ourselves, we relied on vergen::generate_cargo_keys() helper, and requested SHA_SHORT and BUILD_TIMESTAMP to be printed.

Commit Hash on Heroku

The approach only works if we have the corresponding .git folder, which unfortunately is not the case when deploying on heroku.

Fortunately they have a bunch of variable we can rely on if Dyno Metadata feature is activated:

heroku labs:enable runtime-dyno-metadata -a <app_name>

Reading the Date and Hash

So far we have enabled some environment variable be present at compile time or run time, lets read them in our program:

let info = format!(
    "{}: {}",
        let sha = env!("VERGEN_SHA_SHORT");
        if sha.is_empty() {
                .map(|v| v.chars().take(7).collect())
                .unwrap_or_else(|_| "unknown".to_string())
        } else {
// eg "2020-01-06T09:47:49: eb90f18"

The BUILD_TIMESTAMP etc environment variables set during build time get a prefix of VERGEN_, are read via env!() macro. We strip out milliseconds and timezone information from data using .chars().take(19).

On Heroku, VERGEN_SHA_SHORT would be empty as .git is missing, so we check for that and fall back to HEROKU_SLUG_COMMIT, which is present because of Dyno Metadata (of which we take only the first 7 characters). And some fallback code in case the environment variable is not set.

Table Of Content

Immobile v2


Link Log

August 2020

July 2020

June 2020

May 2020

April 2020

March 2020

February 2020

January 2020


Books Have Read / Recommend

Product Management Books

Badass: Making Users Awesome


Five Cs of An Organisation

Success and failure of encryption

Open Source

Observer: Observability for Rust

Realm: Web Development Framework Using Rust and Elm

MartD: Server To Browser Messages

On Writing And Formats Of Written Communications

Rust Stuff

Rust feature flags

Why is diesel not compatible with async?

Making Postgres Only Diesel Code To Also Support Sqlite

Rust Git2’s Concepts

Git Hash And Build Date In Rust Build

Systray Only Native App In Rust

Software and Tools I Use Often


DNS Over HTTPS Controversy

The Patel Motel Cartel

Standalone Complex


January 2020

Word Of The Day





Nix On OSX Catalina

Postgres: WAL / Logical Decoding

Postgres: Listen-Notify



Go All The Way

SSH Commands



Nu Shell

SHA256 vs SHA224

Pronouns Bad


Web Components

Early Return