Server-side development made simple — from backend setup and APIs to frameworks like Node.js and Express. All about the logic that powers your frontend.
While learning Typescript, I encountered many issues that were either recurring or difficult to solve. Because of this, I decided to share them in this post so that I could have access to the most common Typescript errors and their solutions. Since these are my first steps in learning TypeScript, feel free to share your insights and correct me if you see a solution applied incorrectly.
I will occasionally add more typescript errors to this post, hoping to save time and spare at least one of you the frustration and effort of dealing with them!
TS2580 – Cannot find name ‘require’
Error 🆘 (TS2580)
errorTS2580:Cannotfindname'require'.Doyouneedtoinstalltypedefinitionsfornode?Try`npm i --save-dev @types/node`.
Bash
Reason 🔬
As the error description clearly suggests, Typescript needed @types/node to successfully finish the compilation.
Solution ✅
Running npm i --save-dev @types/node solves this issue
My tsconfig.json file had compilerOptions: {"strict": true } set, so it was basically telling TS not to accept type any for its parameters. strict: true is a shortcut for applying strict rules, including the noImplicitAny rule.
If you’re running into this error while setting up a backend project, it usually means Express is working but TypeScript isn’t fully configured yet. In that case, you might find it helpful to follow a complete walkthrough on setting up an Express.js server with Typescript from scratch, including the correct typings and project structure.
Solution ✅
To solve this issue, we need to install @types/express by running
npminstall--save-dev@types/express
Bash
In addition, we will refactor our code to use explicit types for our function parameters and constants.
This error occurs because module X may not include TypeScript type definitions by default, and type definitions for module X haven’t been installed or declared in your project.
Solution ✅
If there are community-maintained type definitions, e.g @types/module-x install them, and this will solve your issue. Another way to overcome this error is to create a custom-type declaration if option 1 is unavailable.
TS18003 – No inputs were found in config file <filename>
While initializing my project, I saw this error when running npx tsc
Typescript needs at least one ts file in a project to compile. I was seeing this error cause I was too eager to run the tc compiler without any .tsc files include in my project.
Solution ✅
Just add a .ts file, even an empty one, for starters, in your project.
How to prevent common Typescript errors in new projects
Many Typescript errors appear not because something is broken, but because the project setup is incomplete. A few small habits can prevent most of the issues listed above.
First, always install type definitions alongside your dependencies. If you’re using node, Express, or other popular Javascript libraries, there’s usually a corresponding @types/* package available. Installing these early prevents many implicit any and missing type errors.
Second, review your tsconfig.json before writing too much code. Options like strict, noImplicitAny, and moduleResolution have a big impact on how Typescript behaves. Enabling strict mode early is usually easier than fixing hundreds of errors later.
Finally, don’t silence Typescript errors just to make the project compile. Typescript is most useful when you understand why an error exists — fixing the root cause often prevents the same issue from showing up again in future projects.
Common beginner mistakes when working with Typescript
Running the Typescript compiler too early is a frequent issue. Typescript expects at least one valid .ts file, so initializing a project without source files will often result in misleading errors.
Another common mistake is ignoring Typescript warnings just to “make it work.” While this may speed things up short-term, it usually leads to repeated issues later. Treat TypeScript errors as guidance, not obstacles.
Finally, relying too heavily on any defeats the purpose of using Typescript in the first place. If you find yourself adding any often, it’s usually a sign that some types or definitions are missing.
If you’re experiencing a recurring error that’s frustrating you, please mention it in the comments section so we can address it and help others who might be facing the same issue.
In this post, I will share my findings and what I learned while trying to understand how to use absolute paths in a node project. I found two different methods for doing so, using NODE_PATH and package.json imports, so let’s quickly dive in and hopefully help you out with your own project, too.
Disclaimer! I hate path resolving, I truly hate it! 😋 It feels so complicated for some reason, especially when you have to decide if you want Typescript, if you want CommonJS, or ESM… it feels that hell breaks loose for something that should be much simpler….! 😡 Now that I got it out of my system, let’s continue.🤭
By the way, if you are here because you are creating a cool side project and want to stop using relative paths hell, this is your post! If, on the other hand, you are a node guru 🧙♂️, and you have already climbed the ladders of node wisdom then this is also a post for you. In your case, though, maybe you could add some comments in the end and share your knowledge with us. Don’t be shy! We need Gandalfs like you to guide us! 🌟
Before explaining how you can change your importing using absolute paths, let’s build a basic project structure so that we are both on the same page when referring to folders/files in our post’s code snippets.
So, nothing fancy here, just an empty folder initialized by npm. I just ran npm init --yes so that my project is initialized automatically with all default values preselected. After doing that, we’ll need some basic folder files and folders:
Typing mkdir -p server/src/controllers will create all structures at once. The -p flag throws no error if the parent folder doesn’t exist, on the contrary, it creates the parent.
Define our importing challenge
Now that we have completed our project’s structure let’s decide on our challenge. Suppose we want to import one helper – in this case validateEmail – from server/src/utils/helper.js
Now that we are ready, I’ll start my node server by running nodemon app.js. (I am using nodemon to watch for file changes and make my life easier, instead of using node).
One common approach for asking node to search for our imported paths from the root folder is by exploiting NODE_PATH. Based on node’s documentation, we just need to add our root folder path in the NODE_PATH variable.
Let’s do that by adding the following lines in our app’s earliest possible point, in our case, the app.js file’s first lines.
There it is! Nodemon restarted our server and the new import path worked like a charm! 🥳🥳
For those of you who would like to know a bit more, let’s see what we did.
app.js
process.env.NODE_PATH = process.cwd();
JavaScript
In this line of code we are configuring the environment variable NODE_PATH to match our Node process’s current working directory.
NODE_PATH is used when the require method is called to import modules, so we are expanding Node’s search scope by adding one more place to search for, when we ask it to load a new module.
app.js
require("module").Module._initPaths();
JavaScript
This line of code serves to initialize the module paths within our Node.js application. The initPaths method is pivotal in this process, as it handles the initialization.
Using package.json imports for absolute paths
If the first method didn’t suit you or didn’t work, there’s another way to import your files using absolute paths by exploiting imports in your package.json file.
Open your package.json file and add the following highlighted lines
package.json
"main": "app.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"imports": {"#helper": "./server/src/utils/helper.js"}
If you decide to go with “imports” you could see some errors thrown by your IDE. I had the same issue while working with Webstorm 2023.3.6.
This happens because your IDE does not support the imports field, and you need to help your IDE understand your new setting. (You could also be facing the same issue with other IDEs like VScode.)
I managed to help my Webstorm understand what was going on by adding the following jconfig.json file in the root folder
So you are ready to use your secret credentials for your awesome project but have no idea how to hide them from the world? You’re in the perfect place! Let’s dive into the steps you should follow to add environment variables to your project using dotenv.
In this post, you will find solutions for Ruby on Rails and Javascript projects. Simply select the approach that best fits your tech stack.
Why use environment variables?
I am pretty sure you already know why environment variables are essential, but just to get it out of our way, let’s take a moment and dig a bit deeper. Why do we need to use environment variables? Is it because everyone else is using them? I am sure your gut feeling tells you that’s not the case. So, what’s the main reason?
Security is the key to all your environment variable questions
The first and most important answer to this question is Security. Imagine you have credentials for a database with sensitive user information, like financial data. Or perhaps you have an API key that you get charged for using, e.g an API for sending emails.
To use these sensitive credentials in your codebase, you’ll eventually need to hardcode them. The problem with hardcoding is that whoever accesses your code, even accidentally, could gain access to these credentials. This could lead to a major security breach, especially if they start using them for personal gain, leaving you with the charges!
How do we solve this? Dotenv to the rescue! 🦸♂️
What is dotenv?
Dotenv is a popular library that helps with managing variables in applications. It loads environment variables from an .env file to your development environment, making them accessible via the process.env for Javascript developers or through ENV for Rails developers.
In Javascript, the library’s name is dotenv and, in Rails, its name is dotenv-rails.
But what is an .env file? An .env file is a simple text file used to store environment variables for an application. It typically contains key:value pairs, like API_KEY=123456, and is used to keep sensitive information separate from the application code.
Using dotenv allows our code to pull specific values from a secure, designated location instead of hardcoding them into the codebase. These values are loaded by dotenv from the .env file.
dotenv is mainly for development, in production, platforms like Vercel, Netlify, Heroku, or AWS usually provide their own way of setting environment variables.
Environment variables for Javascript
As mentioned above, we will be using the dotenv library for our Javascript project.
How to install dotenv?
The first thing we need to do is install the dotenv package by typing:
The next thing we need to do is create our .env file by doing:
touch.env
Bash
Make sure your .env file is included in your .gitignore so you don’t accidentally commit sensitive values to your repo.
How to use dotenv?
Great, so we have our empty .env file and dotenv installed. Let’s combine all the necessary pieces and make this work.
In the .env file, add an API_KEY variable like this:
.env
API_KEY="my super secret key here"
Ruby
At this point, if you try to print the API_KEY you won’t see anything. Although we’ve defined the variable, we haven’t properly loaded dotenv yet.
To load the dotenv library and make it populate all variables from our .env file, simply add the following line to your code:
index.js
require('dotenv').config();// or ES6 if you have "type": "module" enabled in your package.jsonimport"dotenv/config";
JavaScript
Make sure to add this line at the very beginning of your code to load environment variables as early as possible.
By loading dotenv, all variables from our .env file are added to process.env (in JavaScript) or ENV (in Rails).
Environment variables for Rails
For our Rails project, we’ll be using dotenv-rails to manage environment variables. Here’s how to set it up and use it effectively:
How to install dotenv rails?
In your Gemfile add the following line
GemFile
gem 'dotenv-rails'
Ruby
Remember, you need to activate this for your development and test environment, so if you have used the Rails generator, you will see the development/test group near the bottom of your Gemfile. That’s where you need to add your new dotenv-rails gem.
GemFile
group :development, :test do gem 'dotenv-rails'# add this lineend
Ruby
Otherwise, you could also add the following code:
GemFile
gem 'dotenv-rails', groups: [:development, :test]
Ruby
You need to create an .env file now in which you’ll be adding all your environment variables. In your terminal, type:
touch.env
Bash
Let’s now proceed with installing the new gem that we added to our Gemfile:
bundleinstall
Bash
How to use dotenv rails?
Suppose we have the following env variable in our .env file
.env
MY_VARIABLE="cool-password-here"
Ruby
Depending on where you are, you might see the following ways to access your environment variable
value = ENV["MY_VARIABLE"]
Ruby
or in a YAML file, e.g database.yml
<%= ENV.fetch("MY_VARIABLE") %>
Ruby
Different .env files per environment
In some cases, you will need to use different .env files per environment.
Common setups are:
A single.env file for all environments
Separate .env files for each environment, such as .env.development, .env.test and .env.production.
This approach may make it easier for you to manage environment-specific settings and needs.
How to create an .env template file?
Regardless of the names you’ve included in your .env files, sharing them with your team can pose challenges since you won’t be including the .env file in your repository, for security reasons.
So, if you’re not sharing the .env file, how will your team – or anyone else working on the codebase – know which variable names to use?
The solution is to create an .env template file that lists all your variable keys but NOT their values. Once you’ve set up your .env file and are ready to create a template, run the following command in your terminal:
# where .env is an example of a file name, yours maybe different.dotenv-t.env
Bash
By doing so you will see a newly generated env file which will have the same keys as in the .env, but only placeholders as their respective values.
So, suppose we have the following .env
.env
MY_DB_PASSWORD="my db password"MY_AUTH_PASSWORD="my auth password"
Plaintext
by executing the env template command, we’ll get the following .env.template file
The .env.template file can be shared with your team members with no fear. Afterward, you’ll just need to find a secure way to share the actual env values so they can replace the placeholders and use them instead.
Unfortunately, templating doesn’t work for Node, so you will have to do it manually.
Add .env files to .gitignore
So far, we’ve discussed creating and using an .env file, but how can we prevent it from being accidentally committed to version control?
To ignore our .env files, we need to add to our .gitignore file:
.gitignore
.env
Plaintext
This way, we are ignoring our .env file and not our .env-template (if we have generated one).
In case we have more than one .env files, e.g .env.production and .env.test and we want to ignore these but not the template file we will have to change our previous entry to:
.gitignore
.env*!.env.template
Plaintext
Try testing this by running git status to ensure the .env file is indeed being ignored before committing your code. It’s always a good idea to double-check and validate your setup to avoid accidental commits.
Make sure to add your sensitive files to .gitignore to prevent them from being committed! This simple step protects your sensitive data from accidental exposure.
For more configuration settings, check the dotenv GitHub page.
I would suggest staying with Vite’s approach for simple projects. If you need more control and flexibility. then consider installing the dotenv package
Which command prints partial or full environment variables?
Let’s assume our variable’s key is API_KEY. To print its value, we have the following commands available:
For Javascript
In your codebase:
// To print all environment variables, use:console.log(process.env);// Or to print a specific variable:console.log(process.env.API_KEY);
JavaScript
In your terminal:
Environment variables from your project’s .env file are not loaded as a part of your shell’s environment. Your shell’s session keeps track of its own set of variables. So, if you try to do something like printenv API_KEY it won’t work unless you have explicitly exported your app’s .env file’s variables in your shell’s session.
To be able to print your project’s variables while inside a shell, you need to load them first by doing:
source.env
Bash
The source command will load your .env file variables directly in your shell’s session. By doing that, you now can type
echo$API_KEY
Bash
and see the value of your variable. Remember, though, that this will be temporary and only for your current shell session. If you close your terminal and start another session, your variables will not be available unless you reload them.
For Rails
In your codebase:
//Toprint all environment variables, use:putsENV.inspect//Or to print a specific variable:putsENV['API_KEY']
I have been using crons for a while now, but I always wanted to spend some time reading about them or creating one from scratch so that I could fully understand what is a cron job. This post is exactly that: notes on creating my first cron job, learning what a cron is, and what I’ve discovered during the process.
What is cron, and how does it work?
The name cron originates from the Greek word hronos (Greek χρόνος), which means time. Υou may also know the word as Chronos or Kronos, who was the god of time and king of the Titans in Greek mythology.
A cron is a daemon, meaning it is a process — an instance of a program — that runs continuously in the background of a Unix-like operating system. It usually starts along with the system and stops when the system shuts down.
We suffix daemon process names with the letter d to show that they refer to a daemon. That’s why you might see a cron also mentioned as crond, instead of just cron.
A typical cron day
If a cron runs continuously, what does it do while running?
📆 A cron’s typical day would probably look something like this:
For each minute of every day
Check if you have anything to do now, this minute.
If you have something to do, do it.
Get back to sleep for one minute.
Wake up and go back to step 1.
Now we are getting somewhere, so it is a process that checks every minute if it has something to do, at that specific minute. But where does it live? Can we see it?
Let’s open our terminal and type
sudosystemctlstatuscron.service
Bash
ℹ️ systemctl command is a utility – a helper command – which helps us control the systemd, the system daemon. (ctl suffix stands for control)
ℹ️ systemd – is a system daemon that is used to manage other daemons.
So basically, what we are trying to do through this command is ask a manager daemon to show us the status of our cron service. Executing it shows the following information:
●cron.service-RegularbackgroundprogramprocessingdaemonLoaded:loaded (/lib/systemd/system/cron.service; enabled; vendorpreset: >Active:active (running) since Sat 2024-03-01 09:55:40 EEST; 3daysagoDocs:man:cron(8)MainPID:981 (cron)Tasks:1 (limit: 38136)Memory:1.1MCPU:1.491sCGroup:/system.slice/cron.service└─981/usr/sbin/cron-f-P
Bash
Say hello to this little process inside your system! This is a cron! (That reminds me of a famous Al Pacino quote… 😎)
There is a lot of info in this message, and I am not quite familiar with the terminology. What is important for now is that this is about our cron.service which is a Regular background program processing daemon currently in active state and running since Sat 2023-06-10 09:55:40 EEST.
Excellent! We now know what a cron looks like and how it spends its days.
Using a cron to do our work
You can set a cron to do whatever you imagine! Ooh, strong word, right? 😯 Examples, please? Fair enough… 🤓
You could use a cron to:
Send emails to your clients.
Have a backup for specific files in your system.
Remind yourself of a specific task you have to do.
Assign a cron to do heavy-duty work when your machine’s resources are used the least.
But wait… that doesn’t make sense. Why would I need to send an email to my clients, every minute?
Well, I said a cron checks every minute, after all, didn’t I?
True, that is correct, it would (probably!) not make sense, but I also didn’t say that we have to do something every minute. I just said that the cron will check every minute if it has something to do.
We can schedule it to do something whenever we want, every minute, every hour, every end of the month, once a year, etc, by creating a cron job.
Once you define what is a cron job for your needs it becomes a reliable tool for task automation.
What is a cron job?
So what is a cron job exactly? In simple terms, a cron job is a task, that is automated and set to repeat. This task is saved in a file called crontab and it will execute automatically based on your set schedule.
By understanding what is a cron job, you unlock a powerful way to automate repetitive tasks effortlessly. Whether it’s running scripts, performing backups, or scheduling system maintenance, cron jobs ensure that tasks are executed reliably and on time without manual intervention.
How to schedule cron jobs with time syntax
Now that you know what is a cron job and how it automates tasks, the next step is understanding how to schedule it. The timing of a cron job is defined using specific fields that allow you to set it to run at precise intervals. Whether you need a task to run every minute, daily, or on specific days of the week, learning how to configure these settings is essential for mastering cron jobs. Let’s dive into the details!
We use the following formatting when we add a cron job to specify when we want our task to run:
<when> <what>
when: when we want something to happen.
what: what we want our cron to do at that point in time.
Let’s see the cron job formatting in more detail before we discover where to write a cron job. For our cron to understand when something should happen we need to add the following information:
minute
hour
day of month
month
day of week
What is this? 😩 All good, we’ll figure it out.
We need to find a way to describe in great detail and without any doubts when a job (a cron’s task) should be executed. By combining these columns, we can define any point in time we want our job to run. Let’s figure out more, through the following examples. 🧐
If we wanted to ask a cron to do something every minute, we should write it like this:
Cron job every minute
minute
hour
day of month
month
day of week
*
*
*
*
*
Using * is the same as saying, every minute of every hour of every day of the month…
Cron job every 5 minutes
minute
hour
day of month
month
day of week
5
*
*
*
*
Populating only the minute field will run the cron job every 5 minutes
Cron job daily at 10:00 am
minute
hour
day of month
month
day of week
0
10
*
*
*
See that we set the hour column to 10 and minute to 0? This means that our task will run only in the first minute of the 10th hour. If we wanted our task to run every minute of the 10th hour we should set the minute column to *.
Cron job every Saturday at 10:00 am
minute
hour
day of month
month
day of week
0
10
*
*
6
Saturday is the sixth day of the week so we define it by adding the number 6 on the “day of week“column.
Cron job on the 1st of every month at 15:30
minute
hour
day of month
month
day of week
30
15
1
*
*
Cron job daily for the first week of the month
minute
hour
day of month
month
day of week
0
0
1-7
*
6
We can also use duration, in this case, 1-7 is used for all days, starting from the 1st till the 7th.
Cron job every 30 minutes during working hours
minute
hour
day of month
month
day of week
*/30
10-18
*
*
*
There is an awesome site called crontab guru if you’d like to play around and see more complex cases of cron time settings. I suggest you check it out and bookmark it, it will come in handy, trust me!
Understanding the crontab file
Now that we are a bit more familiar with the way we set the time for our cron job, let’s see the where part.
There’s a file in our system called crontab. The word crontab comes from the combination of the words cron + table. This is the file in which we will be adding our instructions on what we want our cron to do and when we would like that to happen.
You can find the crontab file living inside the /var/spool/cron/crontabs folder. In thecrontabs folder, you will find one crontab file per system user, in my case,e my crontab file name was george. Do not edit this file directlythough, if you want to edit your assigned file, type in your terminal:
crontab-e
Bash
ℹ️ -e stands for edit.
If it is the first time you open crontab you might be asked to select your preferred editor, I prefer vim, you can select whatever you like.
In my case, pressing 2 and hitting Enter my crontab opened.
# Edit this file to introduce tasks to be run by cron.# # Each task to run has to be defined through a single line# indicating with different fields when the task will be run# and what command to run for the task# # To define the time you can provide concrete values for# minute (m), hour (h), day of month (dom), month (mon),# and day of week (dow) or use '*' in these fields (for 'any').# # Notice that tasks will be started based on the cron's system# daemon's notion of time and timezones.# # Output of the crontab jobs (including errors) is sent through# email to the user the crontab file belongs to (unless redirected).# # For example, you can run a backup of all your user accounts# at 5 a.m every week with:# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/# # For more information see the manual pages of crontab(5) and cron(8)# # m h dom mon dow command~ ~
Under the last line of this file, (# m h dom mon dow command) let’s write our first actual cron job! 🥳🥳🥳
Write your first cron job command
Our first cron job will be running every minute so that we can start our victory dance as soon as possible 🤭
# m h dom mon dow command# my first cron job instructions * * * * * echo "This is my FIRST CRON!!! :)" > /dev/pts/1
Let’s break down a bit this command
# m h dom mon dow command# my first cron job instructions * * * * * echo "This is my FIRST CRON!!! :)" > /dev/pts/1
Starting a line with a # indicates that this is a comment. Adding comments could help if you have, for example, more than one crons and it gets difficult to understand what each of them does. Watch out not to add comments in line with your cron job command since they will be considered as a part of the command.
White spaces and blank lines are ignored in this file so feel free to format it however you’d like.
# m h dom mon dow command# my first cron instructions * * * * * echo "This is my FIRST CRON!!! :)" > /dev/pts/1
* * * * * These are the 5 values of the columns we described in our previous section. Don’t forget to add spaces between each *.
echo "This is my FIRST CRON!!! :)" displays the message “This is my FIRST CRON!!! :)”.
ℹ️ echo is a Linux command used to print strings/texts on the terminal.
> is a symbol used to take a command’s output and redirect it somewhere else. So in this case the result of the echo command – what the echo command would print in the cron’s terminal – will be redirected to the next argument 👇
/dev/pts/1 #%$#@? 😟 Oh sorry I think I accidentally wrote my actual thought when I searched about it 🤓. I was trying to create a cron that just prints/displays a message in the terminal.
The problem is that crons have their own console so I needed to explicitly ask our cron to display a message in the terminal I am using. To find which terminal I was using, I typed in my terminal, tty and got the following response
~ tty/dev/pts/1
Bash
So I added this terminal’s description in my cron command.
To wrap this up we’d say that we asked our first cron job to display the message This is my FIRST CRON!!! :) to our currently open terminal.
By saving and closing the crontab file you should see a message crontab: installing new crontab which informs you that all changes added to your crontab file were saved.
At the beginning of the next minute, you should see in your terminal your first cron running.
Wait for it…. wait waaaaaaaaait waiiiit (brings back memories from Braveheart!) now! Did you see it????? 🥳🥳🥳🥳
ThisismyFIRSTCRON!!!:)
Bash
This message will show up every minute forever so you probably need to edit your crontab and remove this cron, after all, it was just for learning purposes! 🤭
(Just type crontab -e and remove the cron job you have added to do so.)
How to view cron logs
If you haven’t modified your system settings, then by default, all system logs are kept in the /var/logs/systemlog file. Typing the following command in your terminal will get you all CRON-related logs written in your system
grepCRON/var/log/syslog
Bash
ℹ️ grep command searches for patterns inside a file
In my case, the result looked like
Mar2420:18:01georgeCRON[224509]: (george) CMD (echo"This is my FIRST CRON!!! :)" > /dev/pts/5)Mar2420:19:01georgeCRON[224892]: (george) CMD (echo"This is my FIRST CRON!!! :)" > /dev/pts/5)Mar2420:20:01georgeCRON[225143]: (george) CMD (echo"This is my FIRST CRON!!! :)" > /dev/pts/5)Mar2420:21:01georgeCRON[225356]: (george) CMD (echo"This is my FIRST CRON!!! :)" > /dev/pts/5)
Bash
This is, I guess, one way you can use to check what’s going on with your crons and when they ran.
And there you have it! You created your first cron and saw all the little details about your new cron job! Well done! It’s time for more victory dance!