Do you ever get tired of fiddling with a Dockerfile? Dockerfiles and Docker images are a great way to package your app for reusable, containerized deployments. However, writing and maintaining a Dockerfile is not always intuitive, and it takes up time that could otherwise be used for adding features to your app. Enter Cloud Native Buildpacks. Buildpacks exist to pull together everything your app needs to run and put it into an Open Container Initiative (OCI) image — no Dockerfile required.
For all the developers out there who need a container build process that’s easy to use and will save them time and headaches, Cloud Native Buildpacks might be the solution they’re looking for. Interested? I’ll tell you more.
What Are Cloud Native Buildpacks?
Broadly speaking, a buildpack takes an application code and makes it runnable through a build process. So then, Cloud Native Buildpacks (CNBs) take your application source code and turn it into runnable, reproducible OCI images, implementing your requirements for image security, performance optimization, and container build order. It’s like having the exact Dockerfile you need — only you don’t need to write one.
While most developers can write a Dockerfile, few are experts in either Docker or infrastructure. Too many apps have Dockerfiles that are cobbled together from code snippets found across the web — often a mash-up of Copilot, Stack Overflow, and ChatGPT. Dockerfile errors can lead to insecure and poorly performing applications.
Cloud Native Buildpacks take on this burden, automatically applying best practices for each language or framework. A builder can then utilize any number of buildpacks, automatically detecting which buildpacks are needed and applying them to build an application. Here are the buildpacks that Heroku’s builder currently supports:
$ pack builder inspect heroku/builder:24
Inspecting builder: heroku/builder:24
REMOTE:
Description: Ubuntu 24.04 AMD64+ARM64 base image with buildpacks for .NET, Go, Java, Node.js, PHP, Python, Ruby & Scala.
...
Buildpacks:
ID NAME VERSION
heroku/deb-packages Heroku .deb Packages 0.0.3
heroku/dotnet Heroku .NET 0.1.10
heroku/go Heroku Go 0.5.2
heroku/gradle Heroku Gradle 6.0.4
heroku/java Heroku Java 6.0.4
heroku/jvm Heroku OpenJDK 6.0.4
heroku/maven Heroku Maven 6.0.4
heroku/nodejs Heroku Node.js 3.4.5
heroku/nodejs-corepack Heroku Node.js Corepack 3.4.5
heroku/nodejs-engine Heroku Node.js Engine 3.4.5
heroku/nodejs-npm-engine Heroku Node.js npm Engine 3.4.5
heroku/nodejs-npm-install Heroku Node.js npm Install 3.4.5
heroku/nodejs-pnpm-engine Heroku Node.js pnpm Engine 3.4.5
heroku/nodejs-pnpm-install Heroku Node.js pnpm install 3.4.5
heroku/nodejs-yarn Heroku Node.js Yarn 3.4.5
heroku/php Heroku PHP 0.2.0
heroku/procfile Heroku Procfile 4.0.0
heroku/python Heroku Python 0.23.0
heroku/ruby Heroku Ruby 5.0.1
heroku/sbt Heroku sbt 6.0.4
heroku/scala Heroku Scala 6.0.4
Other builders, like the ones from Paketo or Google Cloud, also bring an array of buildpacks. All in all, the Cloud Native Buildpacks ecosystem is growing and maturing, which is exciting for developers!
Those of you who are familiar with Heroku have already been enjoying the buildpack experience. With git push heroku main
, you’ve been able to deploy directly to Heroku, with no Dockerfile required. Cloud Native Buildpacks build on the Heroku buildpack experience, taking what was once a vendor-specific implementation and turning it into a CNCF standard that’s usable on any cloud platform.
In short, Cloud Native Buildpacks allow developers to:
- Deploy applications more easily than ever
- … in a standard-based fashion without lock-in
- … all while applying container best practices
- … and without making developers tinker with Dockerfiles.
Use Cases
Sounds great, right? With all these benefits, let’s look at some specific cases where you could benefit from using Cloud Native Buildpacks.
Any place where you would ordinarily need a Dockerfile is an opportunity to use a buildpack. Examples include:
- A Node.js web application
- A Python microservice
- A heterogeneous application that uses multiple languages or frameworks
- Building applications for deployment on cloud platforms such as AWS, Azure, and Heroku
One thing to note is this: While buildpacks are declarative, Dockerfiles are procedural. With a buildpack, you simply declare that you want a given application built with a given builder or buildpack.
In contrast, a Dockerfile requires you to define the commands and the order in which those commands are run to build your application. As such, buildpacks don’t currently offer the level of configurability that’s available within a Dockerfile, so it might not meet the needs of some more advanced use cases.
That said, there is no vendor lock-in with Cloud Native Buildpacks. They simply build an OCI image. Need more customization and options than are available in the buildpack? Simply replace the builder in your build pipeline with your Dockerfile and a standard OCI image build, and you are good to go.
A Simple Walkthrough
Let’s do a quick walkthrough of how to use Cloud Native Buildpacks.
To get started with buildpacks as an app developer, your first step should be to install the Pack CLI tool. This tool allows you to build an application with buildpacks. Follow the installation instructions for your operating system.
Additionally, if you don’t have it already, you’ll need a Docker daemon for the builder to build your app, and for you to run your image. With these two tools installed, you’re ready to begin.
Build a Sample App
With access to the pack tool, you’re ready to try it out by building a sample application. I’ll be running this inside a Next.js application. Need a sample application to test out the buildpack on? Here is a full directory of Next.js sample applications. You can also try out any application you have on hand.
Once you have your application ready, start by seeing what builder the pack tool suggests. In your shell, navigate to your app directory and run this command:
On my Ubuntu installation, for my Next.js application, the pack tool suggests the following builders:
Let’s try the suggested Heroku buildpack (heroku/builder:24). To use this one, run the following command:
$ pack build my-app --builder heroku/builder:24
Build time will vary depending on the size of your application; for me, building the app took 30 seconds. With that, my image was ready to go. We can run the image with the following:
$ docker run -p 3000:3000 my-app
The result looks like this:
And that’s it! We’ve successfully built an OCI image of our Next.js application without using a Dockerfile.
Additional Configurations
What if you need to configure something inside the buildpack? For this, you would reference the buildpack(s) that were selected by your builder. For example, for my Next.js app, I can see in the logs that the builder selected two buildpacks: nodejs-engine and nodejs-yarn.
Let’s say that I want to specify the yarn version used by the buildpack. First, I would go to the nodejs-yarn buildpack Readme, where I see that I can specify the yarn version in my package.json
file with a packageManager
key. I would modify my file to look like this:
{
"packageManager": "yarn@1.22.22"
}
From there, all I would need to do is run pack build my-app --builder heroku/builder:24
again.
Conclusion
Cloud Native Buildpacks are an exciting new way to build container images for our applications. By removing the need for a Dockerfile, they make it faster than ever to get our application packaged and deployed. Plus, as they build standard container images, there is no vendor lock-in.
Cloud Native Buildpacks are in preview on many platforms, which means that the feature set is light but fast-growing. Heroku, which has open-sourced their Cloud Native Buildpacks, is bringing them to their next-generation platform, too. I’m looking forward to seeing how Cloud Native Buildpacks enable secure, speedy application deployment across the cloud platform community.