API development with nodejs, express and typescript from scratch — Project Starter

This is the first part of the series “API development with nodejs, express and typescript from scratch” and it is all about starting the project.
We will cover the following steps:
- Prerequisites
- Getting Started
- Basic Configuration
- Server Setup
- Dev and Build Script
Prerequisites
Before we can start our project, we have to install Node.js®, which is an open-source, cross-platform JavaScript runtime environment. By installing nodejs, make sure that you are also installing npm, which is a package manager. Other options are yarn or pnpm, however, we are going to use npm in this series.
We are also using VSCode as editor, but feel free to use any code editor you like.
Follow the link below and install Node.js® on your machine:
Getting Started
Start by creating a new project directory anywhere on your system and open the directory in your code editor.
Next, open the terminal and initialize a nodejs project within the project directory with the following command. This will initialize the project and create a package.json file:
npm init -y
After the initialization, we can install a couple of dependencies, that we need, to create a secure express server.
npm i express dotenv cors helmet
Express is the web framework that we are going to use.
Dotenv is a zero-dependency module that loads environment variables from a
.envfile into process.env.
CORS is a node.js package for providing a Connect/Express middleware that can be used to enable CORS with various options.
Helmet helps you secure your Express apps by setting various HTTP headers. “It’s not a silver bullet, but it can help!”
To use TypeScript, we also need to install a stable version of typescript as developer dependency. We can also go ahead and install type definitions for the packages that we installed previously:
npm i -D typescript @types/node @types/express @types/dotenv @types/cors @types/helmet
When a package doesn’t have built-in types, you can get its type definitions through the
@typesnpm namespace, which hosts TypeScript type definitions from the DefinitelyTyped project. Once you install the packages, the TypeScript compiler automatically includes the types, and your IDE can use them to provide you with code assistance.
Configuration
Next we want to generate a basic tsconfig.json file in our project directory. Generate it by using the following command:
npx tsc --init
We will customize this file in the advanced section. For now, open it, uncomment and edit baseURL and outDir like this:
"baseUrl": "src",
"outDir": "dist",Instead of using hard-coded configuration variables in our files, we are creating a .env file, where we can define all of our sensitive variables.
Enter the following variable in our .env file to define the port your server can use to listen for requests:
PORT=3000If you are using git, we have to make sure that unnecessary files or files that contain sensitive information are not pushed to github. Let’s create a .gitignore file and start by adding the following lines to it:
/node_modules
.envServer Setup
Create a src directory inside your project and a new file called index.ts that serves as the entry point to our application. At this point, your project structure should look like this:
src/
index.ts
.env
.gitignore
package-lock.json
package.json
tsconfig.jsonThe index.ts file can be structured into the following parts:
- Required External Modules
- App Variables
- App Configuration
- Server Activation
Let’s start with the first part and import the project dependencies that we installed earlier:
// Required External Modules
import * as dotenv from 'dotenv';
import express from 'express';
import cors from 'cors';
import helmet from 'helmet';Under the App Variables section, we load any environmental variables from the local .env file using the dotenv.config() method and we assign the port variable from process.env to port:
// App Variables
dotenv.config();
const port = process.env.PORT;Under the App Configuration section, we create an instance of an express application, mount the middleware functions and add a basic route:
// App Configuration
const app = express();
app.use(helmet());
app.use(cors());
app.use(express.json());
app.get('/', (req, res) => {
res.send('Hello World!')
})
helmet is a collection of 14 small middleware functions that set HTTP response headers. Mountinghelmet()doesn't include all of these middleware functions but provides you with sensible defaults such as DNS Prefetch Control, Frameguard, Hide Powered-By, HSTS, IE No Open, Don't Sniff Mimetype, and XSS Filter.
By mounting
cors(), you enable all CORS requests.
With
express.json(), you parse incoming requests with JSON payloads, which populates therequestobject with a newbodyobject containing the parsed data.
Finally, under the Server Activation section, we start the express server:
// Server Activation
app.listen(port, () => {
console.log(`Listening on port ${port}`);
});The final index.ts file should look like this:
// Required External Modules
import * as dotenv from 'dotenv';
import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
// App Variables
dotenv.config();
const port = process.env.PORT;
// App Configuration
const app = express();
app.use(helmet());
app.use(cors());
app.use(express.json());
app.get('/', (req, res) => {
res.send('Hello World!')
})
// Server Activation
app.listen(port, () => {
console.log(`Listening on port ${port}`);
});
Dev Script
Another development-related utility library we are using is nodemon. It helps develop Node.js based applications by automatically restarting the nodejs application when file changes in the directory are detected.
We also need ts-node, which is a TypeScript execution engine and REPL for Node.js. It JIT transforms TypeScript into JavaScript, enabling you to directly execute TypeScript on Node.js without precompiling.
Add nodemon and ts-node as dev dependency:
npm i -D nodemon ts-node
Now we can customise nodemon by creating a nodemon.json file in our project directory. At this time we do not need some of the configurations, but we can still use the following code for a basic setup:
{
"watch": [
"src",
".env"
],
"ext": "js,ts,json",
"ignore": [
"src/logs/*",
"src/**/*.{spec,test}.ts"
],
"exec": "ts-node --transpile-only src/index.ts"
}In order to use nodemon with the configuration we just created, create a dev npm script in package.json to run your server:
"scripts": {
"dev": "nodemon"
},Now we can use the dev script to check if the installation is working so far:
npm run dev
If you see “Listening on Port…” in the console, everything is working so far.
Build Script
Next we have to add the build script to our package.json file. We can also add a start script:
"build": "tsc",
"start": "npm run build && node dist/index.js"Node.js assumes it’s always running in a development environment. You can signal Node.js that you are running in production by setting the NODE_ENV=production environment variable. In case you want to use conditional statements to execute code in different environments, we can also adapt our dev script. However it depends on your operating system.
For Linux and Mac:
"dev": "NODE_ENV=development nodemon"
"build": "tsc",
"start": "npm run build && NODE_ENV=production node dist/index.js"For Windows we also need to install the following:
Option 1:
npm install -g win-node-env
Option 2:
npm i -D cross-env
When choosing option 2 we need to edit our scripts:
"dev": "cross_env NODE_ENV=development nodemon"
"build": "tsc",
"start": "npm run build && cross-env NODE_ENV=production node dist/index.js"The last step of this part of the series is to check if our setup is working. Try each of the following commands one after the other:
npm run dev npm run build npm run start
Finish
We have successfully created a basic nodejs, express project with typescript. In the next part of this series, we continue by adding additional tools. We will cover some new modules as well as tools that help us improve our development workflow.
Content of the next part:
- Advanced Configuration
- Path Aliases
- Environment Variable Validation
- Optional: SWC
- ESLint + Prettier
- Optional: Husky
Go ahead and check out the next part of this series, which is all about evolving our Basic Project Starter to an Advanced Project Starter:
If you find this tutorial helpful, feel free to clap and follow me to stay up to date with all the articles from myself. More tutorials and insights are on the way.
If you want to get unlimited, ad-free access to all the stories on Medium, you can subscribe by using my referral link below :)






