Debugging deployment issues on Cyclic.sh for a Nodejs Application

Debugging deployment issues on Cyclic.sh for a Nodejs Application

Cyclic.sh is one of the best out there when it comes to the level of ease it provides for deploying your web app. To deploy your project, all you need do is connect your GitHub repo and they take care of the rest, this is the main reason why I love Cyclic. They have other features that you should check out, you'll really love them. Check them out here Cylic.sh

As good as it is, there are some pitfalls you should avoid when deploying your app. I'll be listing them here and I'll also share how to handle them.

Generally, whenever you get a build error, always read through the error, you'll surely find hints on what's going wrong and that will go a long way in helping you solve the issue. In fact, that's the first step to take, read through the error (you can also check the logs from the dashboard).

  1. Dotenv

    It is highly recommended that you do not include your secrets directly in your source code. One of the ways to go about this is to add them as environment variables and then access those variables in your code where needed. When developing in a Nodejs runtime environment, this can be done using the dotenv package. The most straightforward setup requires adding your secrets to a file named .env in your root directory.

     PORT=8080
     SECRET_KEY=SECRET_VALUE
    

    Then call the config() method from the dotenv package in the entry point of your program.

     import express from 'express';
     import * as dotenv from 'dotenv';
    
     const app = express();
    
     dotenv.config();
    
     const port = process.env['PORT'] // Access the variable after calling the config function
    
     app.listen(port, () => {
         console.log(`Server started on port ${port}`);
     })
    

    This is great for development but in production, we really do not need it. Ideally, the dotenv package is usually installed as a dev dependency. This means that it isn't bundled into your production code, this is exactly why it causes a build error.

    You may consider making it a dependency to solve the issue, which is not recommendable. In fact, there's a more elegant way to solve this issue. From the dotenv docs, you can preload your environment variables, that way you remove the need for calling the config method in your code. In your package.json file, you can modify your start script to look like the one below.

     {
         "start": "node -r dotenv/config ./index.js"
     }
    

    Actually, I recommend having, at least, two scripts to start your app, one for development and the other for production. This way, your package.json will look like this.

     {
         "dev": "node -r dotenv/config ./index.js",
         "start": "node ./index.js"
     }
    

    This is only the simplest use case, you can modify it to fit your needs. For instance, you can optionally provide the path to your config file if it's not in the root directory or it's not named .env by passing the dotenv_config_path argument followed by the path to your config file. Also, do check out the dotenv docs to see other ways you can use this package.

  2. Environment Variables

    Even after settling issues with dotenv, the build process might still fail. Another thing to check is your environment variables. Make sure all environment variables your app needs to function are correctly set. If you have a config file where you record all environment variables, this will help you add them up easily without missing out on any. Cyclic.sh automatically builds your app again once you add a new environment variable, you should check to see if the build was successful.

  3. Build Size

    This is one of the problems that really bugged me because I didn't really understand why my build size was that large. I faced this issue with a simple weather app I built with typescript, Cyclic.sh automatically runs the build script whenever it finds one but the build process kept failing with a build size error. To resolve this, I added files that are not necessary for my production code to a .npmignore file. In my case, I had an image that I featured in my README.md file but I didn't need it in my production code, adding that to my .npmignore file solved this issue for me. In the end, my .npmignore file looked like this

    You should also make sure to remove stale dependencies.

  4. Nodemon

    Nodemon is a very useful package in development. It basically helps with hot-reloading and you can configure it to reload only when certain files have changed. The nice thing is that it is very flexible and easy to set up but you don't need it in production. Having two startup scripts as I recommended earlier will help you prevent this. By the way, as of node version 18, you can use node with the --watch flag to watch for changes in your codebase.

Are there other issues you've faced I didn't mention, please share them in the comment section and how you solved them.