Git is not great for deployment configuration | by Jesper Joergensen | Jun, 2026 | MediumSitemapOpen in appSign up<br>Sign in
Medium Logo
Get app<br>Write
Search
Sign up<br>Sign in
Git is not great for deployment configuration
Jesper Joergensen
6 min read·<br>1 day ago
Listen
Share
Press enter or click to view image in full size
In ConfigHub, the startup I founded with Brian and Alexis, we’re building a new kind of configuration storage using a plain old database instead of git.<br>Git has become the dominant way to store software deployment configuration because it has some nice things that you need:<br>It is versioned (duh)<br>Config became increasingly declarative (k8s, terraform, cloudformation, etc), which represents well as files<br>There are cloud services available for hosting it which come with rich collaboration and workflow tools<br>Git is great for managing something that is truly a file. But deployment configuration just masquerades as files. In reality it is a graph-shaped data structure that describes a set of live systems, e.g. your dev, staging and production clusters.<br>You can get pretty far with git, but it just isn’t a great tool to manage a data graph. There are much better tools for that, such as a graph database or a plain old SQL database with a graph schema and some JSON capabilities (hello Postgres).<br>Git frictions<br>Where do we run into friction with git?<br>Relationships<br>Let’s use the simplest example of a k8s deployment that needs access to a database. The deployment needs a DB_HOST environment variable to connect to the database. The database is a managed service, so this hostname is provided by the service provider (e.g. AWS RDS) once the database is provisioned. The hostname can change, e.g. if you re-provision a new database from a snapshot.<br>In git, we solve this with something like ${database.host} variable interpolation. But that just means that git is no longer the source of truth for the actual configuration. The actual hostname is stored somewhere else, e.g. in a terraform state file or some key/value store. You can’t check referential integrity with git alone. You don’t have a single place to audit changes to your configuration.<br>In a database, you can represent the relationship between the deployment and the database. You can store the hostname as a “fact” about the deployed database and link to it from the deployment. You will know when this value changes. You can surface staleness. You can decide to automatically remediate (auto-update the deployment and apply the change), or fire an alert. You have a complete audit trail of what is happening at the right level of granularity.<br>Granularity<br>Speaking of granularity. Git imposes granularity on you in terms of files and repos. In theory, you can have very small or very large git repos. But in reality, you are constrained by the tooling available to you. If you use Github, there is a complexity cost to having 1000s of repos. But if you have just a few repos, then you don’t have good access control.<br>It is not ideal to have this kind of granularity imposed on deployment configuration when it really should be treated as a single data graph with granular access controls.<br>You are forced to separate your prod config from non-prod because you want to constrain access to it and now you have made it harder for changes to flow naturally from non-prod to prod.<br>Or you force teams to raise a ticket to get a new environment up and running because the granularity constraint prevents you from giving them self-service access.<br>When config is stored in a database, you can have the same kind of access control that you have for your CRM or HR system or Google Docs. Teams can self-service create new variants of existing components (deployed only to the environments they’re allowed to touch). There is no need to artificially divide up the config just for access control reasons.<br>Distributed versioning<br>One of the greatest powers of git is its distributed versioning capabilities. Developers can work for long periods of time in different branches and then merge or rebase later on. This is great for software development and it works because you are working on a collection of “dead” files.<br>When you use git for deployment configuration, the files in the repo describe the state of a specific live system. There is not a live system for every distributed copy of the repo. Distributed copies are meaningless. But this distribution is deeply engrained in git and that creates an impedance mismatch.<br>We usually solve this by only caring about one centralized copy of the repo (e.g. main branch in github). But we still have to deal with the awkwardness of using pull requests to “deploy”. Do I deploy before I merge or after? Git can get the job done. But it is not the best tool.<br>A database is a more natural fit. With a database, you can create the right model for the job and you have clear centralized and transactional control over changes. You can cleanly model the intended live state...