DEV Community

Olen Daelhousen
Olen Daelhousen

Posted on • Edited on

How to Access dotenv Variables Using fastify-env Plugin

As a small project to upgrade my web developer portfolio, I decided to take a JavaScript trivia game I coded for a class project and improve it from a simple front end only application to a full stack web application. Initially I was going to use Mongo, Express, Vue, and Node as the stack. However, after poking around the web and reading up on Express alternatives, I thought it would be fun to try out a new framework that supported async/await and decided on fastify.

The Problem: How do I Access my .env File in Fastify?

Coming from an Express background, I was used to using the dotenv module to read configuration variables such as the username and password for the database, secrets for jsonwebtokens, and others from my .env file. Getting onboard with fastify's plugin ecosystem, I installed fastify-env and attempted to use it to load the contents of my .env file. An initial challenge I faced was the documentation for accessing .env variables using fastify-env seemed a bit sparse and I was unable to find any good tutorials.

After trying several different approaches with fastify-env and failing to read the variables from .env, I gave up and installed dotenv. This approach worked and I was able to successfully connect fastify with the Mongo database. However, one huge drawback with using dotenv with fastify is that the .env variables are not available on the fastify instance, so accessing them from modules buried in the directory structure rapidly becomes a headache.

I will be using jsonwebtokens in my application to authenticate users on the backend. To validate them, I need to store a secret on the server and access it from different modules that include the validation logic. While the dotenv solution worked well enough for the database credentials, it was too unwieldy for accessing the secret. So, I gave fastify-env a second try.

The Solution, or the Key Points I Missed

Using fastify for the first time, I was learning several new concepts at once while getting the back end up and running and missed several critical items in my initial attempts to use fastify-env. Hopefully the following summary of my experience will help others new to fastify-env save some time and frustration.

.env Variables Need to be Included in the Schema

The first thing I missed in my first attempt at using fastify-env was that the variables in the .env file need to be included in the schema used by fastify-env, otherwise they will not be accessible. The following code snippets give an example of how this works:

.env

USERNAME=databaseUsername
PASSWORD=doubleSecretDatabasePassword
Enter fullscreen mode Exit fullscreen mode

server.js

const schema = {
  type: 'object',
  required: ['PASSWORD', 'USERNAME'],
  properties: {
    PASSWORD: {
      type: 'string'
    },
    USERNAME: {
      type: 'string'
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Set the "data" key to "process.env"

The second key point I missed was that the data key in the options object needs to be set to "process.env" to read the .env file. Simply setting the dotenv key to true is not enough. The following code snippet shows how to correctly set both keys.

server.js

const options = {
  dotenv: true,
  data: process.env
}
Enter fullscreen mode Exit fullscreen mode

How I Thought ready() Worked Versus How it Really Works

The third and final thing I didn't realize when initially attempting to use fastify-env was that awaiting fastify.ready() before fastify.listen() does not load all the plugins in order. However awaiting fastify.after() on the line after fastify.register() will ensure the .env variables are defined following fastify.after(), as shown in the following code snippet.

server.js

fastify.register(fastifyEnv, options)
await fastify.after()

// Now the .env variables are defined
Enter fullscreen mode Exit fullscreen mode

Putting it all Together

The following code snippet shows my entire solution using fastify-env to set up a connection url to authenticate to a MongoDB database using username and password values set in a .env file.

server.js

// Fastify
const fastify = require('fastify')({
  logger: true
})

const fastifyEnv = require('fastify-env')
const schema = {
  type: 'object',
  required: ['DB_PASSWORD', 'DB_USERNAME'],
  properties: {
    DB_PASSWORD: {
      type: 'string'
    },
    DB_USERNAME: {
      type: 'string'
    }
  }
}

const options = {
  confKey: 'config',
  schema,
  dotenv: true,
  data: process.env
}

const initialize = async () => {
  fastify.register(fastifyEnv, options)
  await fastify.after()

  // Database
  // Connection URL
  const username = encodeURIComponent(fastify.config.DB_USERNAME)
  const password = encodeURIComponent(fastify.config.DB_PASSWORD)
  const dbName = 'databaseName'

  const url = `mongodb://${username}:${password}@localhost:27017/${dbName}`

  fastify.register(require('./database-connector'), {
    url,
    useUnifiedTopology: true
  })
}

initialize()

// Fire up the server
(async () => {
  try {
    await fastify.ready()
    await fastify.listen(process.env.PORT)
  } catch (error) {
    fastify.log.error(error)
    process.exit(1)
  }
})()
Enter fullscreen mode Exit fullscreen mode

I hope other coders find this useful. Also, if any fastify-env experts have suggestions for improving this approach, please feel free to leave them in the comments. Thanks for reading and happy coding!

Please note: "database-connection" is a fastify plugin I wrote to use the official MongoDB driver version 4.x because fastify-mongodb was using the 3.x driver under the hood at that time. Since then, fastify-mongodb has been updated to use the 4.x driver, so probably use that in your project.

Top comments (6)

Collapse
 
davipon profile image
David Peng

Hi Olen, this article is really helpful!
I agree with you that the doc is somehow confusing and lacks real-life examples.

Collapse
 
olen_d profile image
Olen Daelhousen

Hi David,

I'm glad you found this useful, I went through a lot of trial and error before getting everything to work.

Collapse
 
billysarmanto profile image
Billy Sarmanto 🇮🇩 🇵🇸

Hi Olen, thank you for writing this guide. I followed your tutorial in here on my Fastify project which use Typescript. The problem is , the config key gave this error when I ran yarn dev :

error TS7053: Element implicitly has an 'any' type because expression of type '"config"' can't be used to index type 'FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTypeProviderDefault>'.
  Property 'config' does not exist on type 'FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTypeProviderDefault>'.
Enter fullscreen mode Exit fullscreen mode

Could you give me your thought how to access the config on festify intance in Typescript ? Many thanks in advance.

Collapse
 
olen_d profile image
Olen Daelhousen

Hi Billy,

This guide is a little outdated now, you should be able to access the environment variables using the following:

process.env.YOUR_ENV_VARIABLE

That works in vanilla JavaScript, I don' t use Typescript, so I can't speak to that. Hopefully this will at least get you pointed towards a solution.

Collapse
 
billysarmanto profile image
Billy Sarmanto 🇮🇩 🇵🇸

Hello Olen. Thank you for your reply. I have tested your suggestion and it worked well in my Express.js Typescript project.

Collapse
 
mathengenewton profile image
Mathenge Newton

Good stuff. Very helpful