Starting a web project is more than just hacking a some lines of code and you're done - at least if you want to create something good and sustainable.

Having a solid foundation to work on - tools that help you to improve the product you're working on - has become a necessity in a fast-paced web development world. Making it possible for others to contribute requires some preparation - but gladly throughout the years some de facto standards have established which we're going to cover in this post.


Using version control is mandatory and Git is always a good choice. But just running git init is not enough to have a clean repository.


One of the first things which I'll always add to my repositories right after initializing the repository is a proper .gitignore file which tells Git which files to ignore. Check out the github/gitignore repository for a list of language-specific gitignore files.

Commit message convention

Having a clean history is only possible with every developer using the same convention to write commit messages. One convention I really like reading and writing is Conventional Commits, which enforces commit messages like

feat(post): add post about project setup
docs: add usage guide for library x
refactor: clean up class y

But no matter if you want to stick to a convention or not: always stick to one tense for all commits. There's a preference from Git itself which recommends a present-tense, imperative style, like:

add feature x
remove deprecated code
change this to that

Instead of

added feature x
this commit will add feature x
feature x added
some badass dude (me) has added feature x!

As a rule of thumb I always tell myself that commit messages should be read like

This commit will [the actual commit message]

Hence things like past tense ("This commit will added / this feature will add / feature x added / some badass dude ..."?!) would make no sense at all.

Yarn or NPM?

Some time ago there's been a lot of discussion about if you should use Yarn or NPM. Most of these articles concluded that Yarn is superior to NPM - but is this still valid? Let's consider a few things:

  • In terms of Speed NPM has caught up
  • Yarn supports workspaces (which is great for maintaining a monorepo), while NPM doesn't provide such a feature
  • npm ci removes the node_modules directory before installing, making caching on CI environments pretty useless
  • NPM added a lock file some time ago, which was one of main advantages of Yarn before

Personally I'd follow a simple rule: if you're going to need workspaces (because you're working on a mono repo) go for Yarn, otherwise NPM. NPM is still shipped with Node without having to install yet another tool.

Should I commit lock files?


Coding style

No matter how many developers are involved, code should always look like it was being written by one single person. This does not take away the way some people like to work - it simply adds readability and structure. Just imagine every scene within a movie would have a different style - that would be horrendous to watch. Seeing something like

if (condition) {


if (condition)

within the same project just makes everything harder to read and even write. If everyone follows the same rules many questions are answered straight away and overall code quality increases.


At the most basic level things like indention level or if to use tabs or spaces can easily be defined within the project by using EditorConfig. You just create a .editorconfig file within your repository and there's a plugin for pretty much every editor and IDE out there to consume this file.


In terms of JavaScript ESLint is the de facto standard to help maintaining a consistent coding standard.

Note: Keep in mind that the linting tool for TypeScript, TSLint, has been deprecated and will transition to ESLint in the future!

When it comes to linting rules there's one thing which should never be forgotten: if a linting rule causes more harm than good simply disable it. There's no godly entity which would judge you by what linting rules you've enabled - so use it to help you, not to torture you.

So... tabs or spaces?



Software without tests is incomplete. I don't trust others people code - I don't even trust my own code. But I do trust tests. Mostly.

Using a testing framework is essential to write proper tests. Choosing one might be somewhat overwhelming at first, since there's:

Comparing these would deserve its own blog post - but as a matter of fact none of them is a bad choice.

Karma is primarily used for Angular (at least I haven't seen any other projects using it).

I personally used to write my tests for quite some time using Mocha, but recently switched to Jest since it's pretty much what some would call battery-included, bringing an assertion- and mocking library and a coverage generator (while all of these need to be installed for Mocha separately via libraries like Chai, Sinon and nyc).

Continuous Integration (CI)

A very common practice and indication of good maintenance is making use of continuous integration tools or CI in short. Popular CI tools for web development are:

  • Travis CI (free for open source, see here for pricing on private repositories)
  • GitLab (free for open source, up to 2.000 minutes build time for private projects)
  • GitHub actions (free for open source, up to 2.000 minutes build time for private projects)

CI tools execute a list of commands whenever your code changes (or other events, like webhooks, comments, new pull requests, etc. occur). If your code does have tests these tests (and things like linting, checking dependencies for security vulnerabilites, ...) will be executed by your CI everytime this event occurs (most likely a git push command).

Code quality analysis

There's a huge amount of really useful tools which help you to analyse your code without having to run it. These tools help to identify code smell (duplications, over-engineered methods, ...), potential bugs or security vulnerabilities. They make it possible to get reviews without having someone to review it and often lead to cleaner code right away.

To name a few of them:

All of them are very useful and have their own benefits. Sonarqube is great because it provides a self-hosted docker which can be used even for projects not hosted publicly without causing additional cost.


Fist of all: you definitely should include a license if you want other people to use your software.

When you make a creative work (which includes code), the work is under exclusive copyright by default. Unless you include a license that specifies otherwise, nobody else can copy, distribute, or modify your work without being at risk of take-downs, shake-downs, or litigation. Once the work has other contributors (each a copyright holder), “nobody” starts including you.

Licensing may can be a bit confusing, especially if you've never dealt with it before. There's a great tool available at which helps you to choose the right license without having to call an attorney to translate license texts into something more approachable.

In my case most of my projects either use MIT (when they're open source) or a proprietary text instead of a prefabricated license text whenever they're not meant to be used by others:

Copyright (c) <year> <name>
All rights reserved.
Keep in mind that putting a proprietary license within an open GitHub repo does not mean people can't just clone, modify or distribute your code. It may be against the license - but there's technically nothing which would prevent that. In case of GitHub you can submit a DMCA Takedown Notice to take down repositories which unlawfully use your code.


Proper versioning can help identify changes without even looking at changelogs or code. By using semantic versioning (which is defined as MAJOR.MINOR.PATCH, e.g. 2.1.3) it's really easy to tell what happened from one version to another:

  • the MAJOR version indicates incompatible API changes. If your code breaks backward compatibility (or, in other words, your release requires modification to the existing code base to work again) it's time for a MAJOR version.
  • increasing the MINOR version just means that functionality has been added without breaking compatibility.
  • PATCH numbers are for bug fixes.

If you stick to this scheme it'll always be easy to follow the development of your software.

Random fact: WordPress doesn't follow semantic versioning, but instead increases the first number as soon as the second number would exceed "9". It uses the first two numbers to indicate major releases, where the first one is actually just a counter.

If you've got no release roadmap it may be confusing on how to apply semantic versioning. I've stuck to putting 0.1.0 on the entire project until the first release - and applying semantic versioning from there on (except for bigger projects, where I increment the MINOR version for releases until I hit something which I'd like to call 1.0.0).


If you've ever worked with software without documentation you definitely ackknowledge its value. Writing good documentation is hard and requires a lot of work to keep up to date - but gladly there are tools out there which help you in this regard.


A well-written README is mandatory for getting into a project. How to install it, what is it even for, how to contribute, etc. - all these things should be included in a good README file. offers a solid template for how your README file may be structured.


Badges are essential whenever you want people to immediately see that the example test passed and that your CI didn't die already during installing dependencies.

But, seriously, badges are cool - as long as they indicate good stats. It's always a bit frightening looking at a repository to see a red "Build: Failing" badge. offers a huge collection of different badges to add to your project - and even offer creating custom badges.


Changelogs are part of a good documentation and maintaining them helps to identify changes in detail between versions. Check out for a decent changelog format.

Code documentation

There's two different kinds of code documentation: generated API documentation and usage documentation.

Tools like Typedoc, TSDoc or JSDoc help you to generate a useful documentation based on your code. This is often useful to give an insight in your implementation without having to look directly within the files.

The other thing is usage documentation which needs to be done mostly by hand. Utilities like docz may help you to get started faster - but it's still up to you to write a good documentation.

If you're building a component-based frontend application (by using a framework like React, Vue or Angular) Storybook is also something to take a look at - a decent option to document and showcase standalone components.

Contribution guidelines

It's hard for others to get involved without knowing what you're expecting from them. Describing how you want people to participate (conventions, formats, ...) might be an essential part of getting others to work on your code. There's a good template on GitHub which even includes a Code of Conduct (which basically tells people who want to be a part of your software not be complete scumbags).


After your software has been released the fun is not over; it needs to be maintained! Bots like renovate or Dependabot help you by submitting pull requests as soon as new versions for the libraries you're using are available.


A lot of open source projects rely on support from their users. In the end even open source projects are brought to you just by normal human beings who sacrifice their free time to work indirectly for people they don't even know (weird, isn't it?).

There are many platforms for getting or being supported, like:

Random fact: Evan You, creator of the Vue framework, makes around 20k per month on Patreon - from open source!

Something's missing?

If you think there's something missing within this post for creating a solid foundation for your next web project please let me know in the comments - I'm always interested in tools and libraries to help and improve existing workflows!