Typescript Uncategorized Web

Using dotenv in Typescript

Typescript is awesome, I think that as we start using it, this becomes apparent. It provides type safety and to build full stack applications with an object-oriented mindset. However Typescript is a superset of Javascript and its support for typing doesn’t come for free. It has its own compiler in order to understand its syntax. Ultimately Typescript code is compiled into Javascript.

If you’re building production applications, you’ll be familiar with the need to keep your secrets outside the source code and provide them as runtime configuration and if you are a full-stack Javascript developer chances are that you have used Node.js as backend server.

Every application has the basic need to externalise some configuration properties, and historically the npm package to achieve this has been dotenv. This package loads .env files and fills the process.env object which can then be used to access environment variables in your application.

Working with third-party libraries in Typescript is not as straight-forward as one might think. It a typical Node.js setup, to use dotenv one would use something like this (after installing dotenv with npm i dotenv):


From now all environment variables in .env are accessible through process.env.YOUR_EV

With Typescript this doesn’t work because require is a Node.js syntax, not a Typescript syntax.

The goal is to use dotenv (and generally any TP Javascript modules) in a Typescript application: how do we achieve that?

The usual way to use third-party libraries in Typescript is to use types. There’s an open source project which makes available most types for existing Javascript libraries to Typescript applications. It’s called DefinitelyTyped. Thanks to this project, it’s possible to use existing Javascript libraries in Typescript projects by using the following syntax:

npm i --save-dev @types/<module>

This guarantees that Typescript will access the module types as if they were Typescript types. For dotenv I’ve found that this doesn’t work and indeed @types/dotenv is deprecated. After considerable time spent on the internet looking at possible solutions, none of which worked, I’ve found a way to achieve this with Webpack.

Webpack to the rescue

Webpack is a bundler that can be used in combination with plugins to provide compile and bundling options for your application. It’s the de-facto standard for packaging JS/Typescript/CSS files into production-ready applications. In a nutshell, one provides a webpack configuration file, instructs the tool what to compile and the target environment and Webpack creates bundles which can then be used on the frontend as well as backend. Thanks to Webpack is also possible not only to optimise the bundles for production, by creating minified versions, thus improving the overall performance of your application but also to create code that works in older browsers, eg IE9.

Let’s say that you have a .env file in the root of your project with the following environment variable, an API key to use Google Geolocation APIs:


You’d like to use this environment variable in your Typescript application as follows:

// ./src/app.ts
const form = document.querySelector('form')!;
const addressInput = document.getElementById('address')! as HTMLInputElement;

const apiKey = process.env.API_KEY;
if (!apiKey) {
  throw new Error('No API Key');

function searchAddressHandler(event: Event) {
  const enteredAddress = addressInput.value;

  // send to Google's API!
form.addEventListener('submit', searchAddressHandler);

First you’ll need to install the webpack and dotenv-webpack npm modules. You can do this by running the following command:

npm i --save-dev dotenv-webpack ts-loader typescript webpack webpack-cli webpack-dev-server

Then, you can setup your Webpack config (webpack.config.js) as follows:

const path = require('path');
const Dotenv = require('dotenv-webpack');

module.exports = {
  mode: 'development',
  entry: './src/app.ts',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: 'dist',
  devtool: 'inline-source-map',
  module: {
    rules: [
        test: /\.ts$/,
        use: 'ts-loader',
        exclude: /node-modules/,
  resolve: {
    extensions: ['.ts', '.js'],
  plugins: [new Dotenv()],

Here you will notice the Dotenv declaration as well as the plugins entry.

Et voila’. You can now use process.env.YOUR_EV in your code, without the need to install dotenv or any complex configuration for Node.js or type compatibility.

Happy coding folks!