Setting up a Webapp – Part 1: Introduction

Veröffentlicht von

Every so often I find myself wanting to play with an idea for a new webapp. Usually this ends with me spending hours combing through documentation of the same handful of packages again and again. Today I found myself doing that same thing once again, but this time I decided enough is enough: This time I’ll write it down for future reference.

The End Goal

So, let’s start with the basics. What exactly do I even need? Most of my app ideas depend on the same few services. In this blog series we’ll setup the following:

  • Express webapp written in Typescript
  • PostgreSQL to store the data
  • Redis, to cache various things
  • Docker, to test and deploy the app
  • Drone, as a CI/CD solution with automated tests

Before we start a quick disclaimer: I’m not an expert in any of these services, so there might be some issues with it. It’s designed to be enjoyable to use, not so much as a production ready app setup. The way I show here is not necessarily the right way, it’s just the way I do it.

Basic Structure

Like all good things, this setup also starts with the holy trinity of bash commands:

git init
npm init
tsc --init

This will create a new git repository in your current directory, initialize it as a npm package with a package.json and then it’ll create a typescript project config file tsconfig.json.


Let’s first look at the tsconfig.json file. If you ignore all the commented lines it will probably look somewhat like this:

  "compilerOptions": {
    "target": "es5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
    "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
    "strict": true,                           /* Enable all strict type-checking options. */
    "esModuleInterop": true,                  /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
    "forceConsistentCasingInFileNames": true  /* Disallow inconsistently-cased references to the same file. */

The first thing we’ll change is the target. As of writing this I have Node.js Version 15.14 on all my systems, which has full support for all ES2020 features. There isn’t really a reason for me to have ES5 as target, so I’ll change it to ES2020.

By default typescript emits the resulting js files next to the ts files. I prefer to have them in a separate ./bin/ directory. My Source files usually reside in the ./src/directory and typings may live in ./typings/. To achieve that we’ll have to add the following options:

  "compilerOptions": {
    "outDir": "./bin/",
  "include": [

When you’re don it should look like this:

	"compilerOptions": {
	  "target": "es2019",
	  "module": "commonjs",
	  "strict": true,
	  "esModuleInterop": true,
	  "forceConsistentCasingInFileNames": true
	"include": [
		"./src/", "./typings"


With git we won’t have to setup much. I’ll add my personal gitea as a remote and configure the gitignore file. Instead of gitea you could use your github or gitlab, if you prefer those. The setup will be the same. First you create the repository on gitea/gitlab/github and then run the following commands:

git remote add origin <URL to your repo>
git add .
git commit -m "Initial commit"
git push -u origin main

The only other thing we’ll have to change is the .gitignore file. In particular we want to keep everything out of the repo, if it can be generated automatically by another tool. This includes all node packages, since they can be installed by npm install. The bin/ directory should also stay out of the repo, since it will be created by the Typescript compiler.

During development I usually don’t write my application logs to a file, I only output them to the console. But I might have to pipe it into a file for debugging. To prevent littering the repo in that case, I’ll ignore the logs/ directory too.

# Ignore editor/IDE settings

# Ignore automatically generated files

# Ignore packages, they will be installed by npm install, not by git

# Ignore personal todolist, github/gitlab/gitea issues should be used instead

# Ignore environment variables file
# it may contain secrets that should not live in a git repo

You might have noticed that I didn’t explain the .env file thus far. I’ll talk a bit more about that later in the series, but for now the comment in the block above should suffice.

The should be fairly obvious, but in case it isn’t: I use that as a scratchpad for development sessions. The data doesn’t need to persist between dev sessions, so it doesn’t really belong in the repo. For anything of substance – like actual todo items – I’ll use either gitea issues or a kanban board app like Wekan. Maybe it’s time to rename the file to… 🤷‍♂


Since I like to have my compiled js files in a separate ./bin/ directory, I’ll have to tell node where to find the index.js file. This can be changed by modifying the main field inside the package.json file:

  "name": "webapp",
  "version": "1.0.0",
  "description": "A fancy webapp.",
  "main": "bin/index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  "author": "Alexander Schramm",
  "license": "MIT"

We now have set up a basic foundation to build our app upon. In the next part we’ll install a few packages, write a little boilerplate code and get an initial web server up and running.

Kommentar hinterlassen

Deine E-Mail-Adresse wird nicht veröffentlicht.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.