Of course you should version mix.lock! Wait do we..?


i found a post from Yehuda katz where he explain the reason to version and not version Gemfile.lock in ruby. To me it feels strange that we need to say explicitly, what we where trying to say with declarations. What about you?

1 Like

I think he explains it pretty well. For production applications, your builds need to be 100% reproducible. Every change you deploy, should be traceable to a diff in your repository whether it is your code, a dependency or a transitive dependency.

Libraries on the other hand, need to “float” - they should be compatible with various versions of their own dependencies, otherwise users get locked to libraries that they cannot upgrade as they need to. This seems to happen a lot in the Java/Maven ecosystem, where no one can build their dependencies from source, and are at the mercy of the slowest upstream to update a new downstream that they need.


The downside of not having a lock in libraries is that contributing to a library may become harder for a newcomer because they may be unlucky to clone it exactly when a breaking dependency is introduced.

Furthermore, you usually have a small group of developers working on a project and their local checkout all have an old mix.lock. So most of the time, you are not updating the dependencies, unless you are constantly removing your local mix.lock file.

If you want to test against latest versions, do it on CI, where you will be running it constantly and without the risk of pushing the burden to new contributors.


This is a good idea. You can set up a specific CI build that deletes mix.lock before running mix deps.get and it will run tests with the same versions users will get when they add your dependency to their project.


What about start up? Because they don t really have legacy when they start. Shouldn they focus on building a realliable dev env for everybody? Rather than locking?
I do agree that If you have legacy code It s the way to go. And even if everybody has the same env you might have to lock anyway. But I just feel like the use case of lock could be narrowed for the greater good. Isn t declarative the best for these kind of problems?

If you are a startup you most likely want to focus on your business logic rather than focus on upgrading dependencies or debugging production issues because your dev and test environments ended-up being different than your production one.


Great and why not have more CI tools in the elixir standard lib, by that i mean something like mix format --check-formatted . That s a great tool.

Mix doesn’t use a dependent library’s lock file when resolving package versions though, right? Just the constraints in its deps. So the lock file is just a tool for the developer of the library. I think this systematically applies the approach advocated, rather than contradicting it.

But shouldn t we be using stuff like Docker/Ansible/Vagrant for all that?

No, it doesn’t. But I was talking about the top-level. Imagine I remove the mix.lock from Ecto. Now a person who is trying to contribute to Ecto for the first time may clone it and get a bad dependency which may be the source of confusion.

1 Like

These do not solve the same problem. Those tools do not resolve your Elixir library dependencies when you build your application. You deploy your built application with those sort of tools.

And having reproducible builds has nothing to do with startups or legacy code. It has to do with not wanting stuff to break for unexplainable reasons. Frankly, I’d consider it unprofessional to deploy whatever random code resolves that day to production.

1 Like

We don’t disagree at all, I think I didn’t express myself well to begin with. Mix already implements the part I think is important, which is that lock files in a library shouldn’t constrain the resolution of dependencies when that library is used in someone else’s project. I agree with having a lock file in the repo, this way other developers on the project have a resolution set known to work when they begin development.

1 Like

You can build a dev env on your server and store it, and then ship it to your dev team with docker/vagrant. How dependencies could resolve differently then? And that might be where I lost some of you. I was assuming that you CAN clone you environment and make it available for your team(I hope a fresh start up can do that). And from that prospective why would you lock?

Yes having legacy code is a major source of locking stuff, like when you have java dependencies… And I m not saying the only cause but a major cause.(Why security sofware is never up to date?)

Shipping a docker/vagrant image with dependencies already included is the super expensive version of locking dependencies. If you’re not including dependencies in those images when you’re back to square one: Either include the lock file so everyone gets the same versions when using the image or don’t included it and risk that dependencies drift and cause issues.

That’s why the issue is really orthogonal to using docker or vagrant. Both neither prevent nor solve the issue.

In an ideal world you could just depend on a mayor version of a library instead of locking to a specific one, but people make errors, multiple dependencies might conflict and cause issues the individual maintainer couldn’t have known, …. The real world just isn’t that perfect.

1 Like

A lock file can be versioned in your source repository. This way you know when every change was made. When a problem is found, you can git blame to see what the change was supposed to address in the first place, etc. In general, you want all of your code managed this way, including your dockerfiles ansible scripts etc. Much of the success of docker, and much of the benefit of “infrastructure as code” relates to the fact that you can manage it this way. The built images are managed strictly as a deployment concern, not as a development tool.