---
title: Dockerizing Our Heroku Apps
description: Heroku allowed us to focus our energy on building the applications rather than building the infrastructure that runs the applications.
image: https://blog.ambassify.com/hubfs/Blog_NEW_Jorgen-01.png
---

English - United States

[![Ambassify Logo](https://blog.ambassify.com/hubfs/raw_assets/public/ambassify-theme/images/logo-ambassify.svg)](https://blog.ambassify.com/)[Book a Demo](https://get.ambassify.com/demo-options/schedule-a-1-on-1-demo-of-the-ambassify-platform)

- [Why Ambassify](https://get.ambassify.com/why-ambassify)
- Use Cases
  
  By Use Case
  
    - [Employee Advocacy](https://get.ambassify.com/use-cases/employee-advocacy)
    - [Employer Branding](https://get.ambassify.com/use-cases/employer-branding)
    - [Dealer Advocacy](https://get.ambassify.com/use-cases/dealer-advocacy)
    - [Social Selling](https://get.ambassify.com/use-cases/social-selling)
    - [Social Media Marketing](https://get.ambassify.com/use-cases/social-media-marketing)

  By Industry
  
    - [HR Leaders](https://get.ambassify.com/employee-advocacy-for-hr-leaders)
    - [Financial Services](https://get.ambassify.com/employee-advocacy-for-financial-services)
    - [Payroll & Social Secretariats](https://get.ambassify.com/employee-advocacy-for-professional-services)
- Product
  
  By Stage
  
    - [Platform Overview](https://get.ambassify.com/platform)
    - [Diagnose](https://get.ambassify.com/employee-advocacy-assessment)
    - [Educate](https://get.ambassify.com/product/skills)
    - [Activate](https://get.ambassify.com/product/employee-advocacy-activation)
    - [Measure](https://get.ambassify.com/product/reporting)
    - [Prove](https://get.ambassify.com/product/advocacy-impact)

  By Features
  
    - [Gamification](https://get.ambassify.com/product/gamification)
    - [AI assistant](https://get.ambassify.com/product/ai-assistant)
    - [Multilingual Employee Advocacy](https://get.ambassify.com/product/multilingual-employee-advocacy)
    - [Personal Post](https://get.ambassify.com/product/personal-post)
    - [Compliance Guardrails](https://get.ambassify.com/product/guardrails)
    - [In-App Training](https://get.ambassify.com/product/in-app-social-media-training)
    - [Security & Privacy](https://get.ambassify.com/security-and-privacy)
    - [Integrations](https://get.ambassify.com/product/integrations) 
          - [Browser Plugin](https://get.ambassify.com/features/browser-plugin)
          - [Single Sign-on](https://get.ambassify.com/product/integrations/single-sign-on)
          - [Zapier](https://get.ambassify.com/product/integrations/zapier)
          - [Microsoft Teams](https://get.ambassify.com/product/integrations/microsoft-teams)
          - [Salesforce](https://get.ambassify.com/product/integrations/salesforce)
          - [Strava](https://get.ambassify.com/product/integrations/strava)
          - [Webhooks](https://get.ambassify.com/product/integrations/webhooks)
    - Social Channels 
          - [Instagram](https://get.ambassify.com/features/instagram-sharing)
- [Plans](https://get.ambassify.com/pricing)
- Resources 
    - [Customer Stories](https://get.ambassify.com/customer-stories)
    - [Advocacy Customer Experiences](https://get.ambassify.com/advocacy-customer-experiences)
    - [Blog](https://blog.ambassify.com/blog)
    - [Ebooks](https://get.ambassify.com/resources/content-library)
    - [Webinars](https://get.ambassify.com/resources/webinars)
    - [Customer Campaign Examples](https://get.ambassify.com/resources/customer-campaign-examples)
    - [Help Center](https://help.ambassify.com/en/)
    - [Services & Consultancy](https://get.ambassify.com/resources/ambassify-services)
- Company 
    - [About Us](https://get.ambassify.com/company/about-us)
    - [Partnerships](https://get.ambassify.com/company/partner)
    - [Contact Us](https://get.ambassify.com/contact)

[Book a Demo](https://get.ambassify.com/demo-options/schedule-a-1-on-1-demo-of-the-ambassify-platform) [Get Advocacy Score](https://get.ambassify.com/employee-engagement-score)

[Call Us!](tel:0032460201203)

English - United States

# Dockerizing Our Heroku Apps

Perfect for a **7 minute** break •  Written on **December 07, 2022** by 

[**Jorgen Evens**](https://blog.ambassify.com/blog/author/jorgen-evens) 

on October 1, 2024

![Avatar picture of Jorgen Evens](https://vision.ambassify.eu/vision/image/https%3A%2F%2Fget.ambassify.com%2Fhubfs%2FTeam%2FTeam%2520images%2520for%2520vacancy%2520pages%2FJorgen_Evens.png/768.webp?resize=crop&cache=31536000)

Herokuish is a great tool to deploy a Heroku code base onto the many different container platforms that use Docker, such as Kubernetes. It, however, comes with the downside of producing images that are larger than they need to be to run your applications.

## What we’re built on

The engineering team behind Ambassify isn’t a large one, so using Heroku was an obvious choice. Heroku allowed us to focus our energy on building the applications rather than building the infrastructure that runs the applications. Today, Ambassify is made out of nearly 25 microservices, each created using javascript and node.js to run the code. 

Heroku provides a consistent environment where we can run our applications, so we’ve automated getting our code to run on it. Each and every one of our microservices is exposed to a large set of tests and scans. If these succeed, Heroku picks up on this, builds it into an image, and deploys it into our staging environment.

## Keeping our options open

At the end of 2020, we started exploring what options we would have if we decided to move away from the Heroku platform. The reason is that we were having some issues implementing some of our more complex features.

Most of the options we encountered on our journey involved using docker containers. For us to test our applications on some of the other platforms, we started looking for a way to package our services into docker images without having to modify them.

This led us to a solution using *herokuish* and two scripts that could be used across all of our apps to get our code packaged up into a docker image.

## How social is your workforce, really?

Get your Employee Social Engagement Score and see how your people show up on social today — where the reach is, where the gaps are, and what to fix first.

[Book a Demo](https://get.ambassify.com/demo-options/schedule-a-1-on-1-demo-of-the-ambassify-platform) [Get Advocacy Score](https://get.ambassify.com/employee-engagement-score)

## Building the image

Some of us on the team had experience with [dokku](https://dokku.com/), the self-hosted and open-source PaaS solution; it uses the [gliderlabs/herokuish](https://hub.docker.com/) docker image to build and run your applications as if they were running on Heroku.

### Gliderlabs/herokuish

The [herokuish](https://github.com/gliderlabs/herokuish) docker image provides an environment as close as possible to the server environments on Heroku. This is how the tool is described on GitHub:

*The goal is to be the definitive, well maintained and heavily tested Heroku emulation utility shared by all. It is based on the Heroku:18, Heroku:20, and Heroku:22 system images. Together they form a toolkit for achieving Heroku compatibility.*

Building and running your application within the herokuish image is really simple but requires some massaging to get working. Most importantly, you’ll need to know that your app’s source code must be available during the build at /tmp/app, but may not be there when calling the `/start` command.

```
docker run -ti -v /path/to/app:/tmp/source:ro gliderlabs/herokuish /bin/bashcp -a /tmp/source /tmp/app/buildrm -Rf /tmp/app/start web
```

Using these steps you could bundle your app into a docker image using this simple Dockerfile and `docker build`.

```
FROM gliderlabs/herokuishCOPY . /tmp/appRUN /build && rm -Rf /tmp/appENTRYPOINT [ "/start" ]CMD [ "web" ]
```

 

### Optimizing image

The above Dockerfile will however result in an image that is larger than required. Below are two changes we can make to our Dockerfile that will reduce the size to essentials.

#### Multi-stage build

Docker has support for multi-stage builds, this allows us to build all our assets without them being included in the second stage (our final image) of the build. A new stage is denoted by a new `FROM` command in the Dockerfile.

```
FROM gliderlabs/herokuish AS buildCOPY . /tmp/appRUN /build && rm -Rf /tmp/*RUN herokuish slug generate && \    herokuish slug export > /app.tar.gzFROM gliderlabs/herokuishCOPY --from=build /app.tar.gzRUN herokuish slug import < /app.tar.gzENTRYPOINT [ "start" ]CMD [ "web" ]
```

 

You might notice that the first section of this file looks familiar, except for the fact that we use the herokuish command to generate and export a slug containing only the built version of our app. This excludes the buildpacks that were downloaded or temporary resources that were used during the build.

We copy this slug over to our second stage using the `COPY` command. Finally, we import the slug back into our final image to generate an image that can run our app.

#### Unpack slug

In our previous Dockerfile, we still copied over our app slug while we never use it again after the import. Would there be a way to remove this slug from our final result? This slug can quickly become a few hundred megabytes, after all.

As it turns out, not only is it possible to copy over artifacts from a previous stage. When using docker with BuildKit you can actually mount resources from a previous stage while building your next stage.

```
FROM gliderlabs/herokuish AS buildCOPY . /tmp/appRUN /build && rm -Rf /tmp/*RUN herokuish slug generate && \    herokuish slug export > /app.tar.gzFROM gliderlabs/herokuishRUN --mount=type=bind,from=build,source=/app.tar.gz,target=/app.tar.gz \    herokuish slug import < /app.tar.gzENTRYPOINT [ "start" ]CMD [ "web" ]
```

 

Here you can see that we supply the mount argument to the RUN command that will be extracting our app into the final image. We need to supply 4 parameters to the mount argument. `type=bind` specifies we want to reference a directory from a previous stage. The ‘from’ parameter specifies the stage from which we want to mount images; in our case that is ‘build.’ Finally, ‘source’ and ‘target’ specify the source file or directory and ‘target’ where to mount the file in the new stage.

### Compatibility

To improve compatibility, we’ve included a line in our initial build stage to load custom buildpacks from ‘app.json’. Without this line, only the automatically detected buildpacks will work.

```
RUN (cat /tmp/app/app.json || echo '{}') | jq -r '.buildpacks[].url' > /tmp/app/.buildpacks && \    (test -s /tmp/app/.buildpacks || rm /tmp/app/.buildpacks)
```

 

This will read the buildpacks from your ‘app.json’ file using the `jq` utility and write them into `.buildpacks`, which is the file that herokuish will read to determine which buildpacks to use.

### Improving developer experience

Now we just need a way to name our images consistently, test them and eventually also deploy them. For simplicity, we’ve chosen to use a Makefile in the project’s root directory. `make` is easily accessible on most platforms and is easy to understand. Our Makefile has a few parameters that can be changed during setup. After that, building, testing, and deploying can be controlled with a few `make` commands.

```
APP_NAME?=some-appAPP_NAMESPACE?=appsIMAGE_NAME?="ambassify/$(APP_NAME)"export DOCKER_BUILDKIT = 1up: build    docker run -t -i \        -e PORT=3000 \        -p 3000:3000/tcp \        $(IMAGE_NAME)pull:    docker pull gliderlabs/herokuishbuild: pull    docker build --build-arg NPM_TOKEN -t $(IMAGE_NAME) .debug: build    docker run -t -i --entrypoint /bin/bash $(IMAGE_NAME)publish: build    docker tag $(IMAGE_NAME) ghcr.io/$(IMAGE_NAME)    docker push ghcr.io/$(IMAGE_NAME)deploy: publish    kubectl rollout restart deployment $(APP_NAME) -n $(APP_NAMESPACE)
```

 

This is a generic Makefile that only requires us to change the three parameters at the top of the file. `APP_NAME` controls the name of the service we are building. `APP_NAMESPACE` is only required in combination with Kubernetes and references the namespace into which the app is deployed. `IMAGE_NAME` is the name used to publish the image.

The `export DOCKER_BUILDKIT=1` command ensures that any docker commands are run using BuildKit, which is required to use the mount argument to `RUN` discussed earlier.

## Future improvements

Herokuish is a great tool to help us test and transition without having to sacrifice our ongoing development. It allows us to continue using heroku and use a familiar software stack until we are ready to make the switch. 

### Herokuish vs. specialized image

Using herokuish has one disadvantage, the images produced are quite large in comparison to some of the regular `node` images or even larger than the `node-alpine` docker base images. Even the smallest applications generate an image with a total size of over 1GB, causing slow startup or restarts on occasion.

Once we are ready to move away from Heroku we will most likely modify our workflow to use the regular node images for specific programming languages, such as the `node` image.

## Conclusion

Herokuish is a great tool to deploy a Heroku code base onto the many different container platforms that use Docker, such as Kubernetes. It, however, comes with the downside of producing images that are larger than they need to be to run your applications.

If you are not intending to use Heroku for your code base, you are most likely better off going with a specialized image for your programming language. The full scripts used in this blog post can be found on [our GitHub gist.](https://gist.github.com/JorgenEvens/565f0c6d3591d249bcc5bf9cbbc8f785)

## How social is your workforce, really?

Get your Employee Social Engagement Score and see how your people show up on social today — where the reach is, where the gaps are, and what to fix first.

[Book a Demo](https://get.ambassify.com/demo-options/schedule-a-1-on-1-demo-of-the-ambassify-platform) [Get Advocacy Score](https://get.ambassify.com/employee-engagement-score)

## Related Blog Posts

Not done reading yet? No problem, here are other things you might be interested in.

- ![Building Community Advocacy](https://vision.ambassify.eu/vision/image/https%3A%2F%2Fget.ambassify.com%2Fhubfs%2FBlog_Community_Advocacy-02.png/768.webp?resize=auto&cache=31536000)
  
  ### Community Building & Employee Advocacy

  [Read more](https://blog.ambassify.com/blog/building-employee-advocacy)
- ![partnership announcement Ambassify and baas.agency](https://vision.ambassify.eu/vision/image/https%3A%2F%2Fget.ambassify.com%2Fhubfs%2FBlog_baas.agency_Partnership_Tavola%2520disegno%25201.png/768.webp?resize=auto&cache=31536000)
  
  ### Partnership announcement: baas.agency & Ambassify

  [Read more](https://blog.ambassify.com/blog/partnership-announcement-baas.agency-ambassify)
- ![how to increase employee engagement and motivation to boost productivity](https://vision.ambassify.eu/vision/image/https%3A%2F%2Fcdn2.hubspot.net%2Fhubfs%2F2828935%2FThumbnail-2.jpg/768.webp?resize=auto&cache=31536000)
  
  ### 7 Ways to Increase Employee Motivation in the Workplace

  [Read more](https://blog.ambassify.com/blog/employee-motivation)

## Pulse shows you the gap. Ambassify helps you close it.

Take the 5-minute Pulse assessment to see where your advocacy program stands today. Then book a demo to see how Ambassify gets you where you want to be.

[Get Advocacy Score](https://pulse.ambassify.com) [Talk to an Expert](https://get.ambassify.com/demo-options/schedule-a-1-on-1-demo-of-the-ambassify-platform)

[![Ambassify Logo](https://blog.ambassify.com/hubfs/raw_assets/public/ambassify-theme/images/logo-ambassify-white.svg)](https://blog.ambassify.com/)

### Product

[Core Features](https://get.ambassify.com/features/employee-advocacy-software-must-have-features)[Native Video (Sharing)](https://get.ambassify.com/features/native-video-sharing)[Campaign Variations](https://get.ambassify.com/features/campaign-caption-and-image-variations)[Community Goals](https://get.ambassify.com/features/community-goals)[Browser Plugin](https://get.ambassify.com/features/browser-plugin)[AI Assistant](https://get.ambassify.com/product/ai-assistant)[White Labeling](https://get.ambassify.com/product/white-labeling)[Content Creation](https://get.ambassify.com/product/creating)[Content Scheduling](https://get.ambassify.com/product/scheduling)[Gamification](https://get.ambassify.com/product/gamification)

### Useful pages

[Testimonials](https://get.ambassify.com/testimonials)[Ambassify vs Haiilo](https://get.ambassify.com/ambassify-vs-haiilo)[Ambassify vs Sociuu](https://get.ambassify.com/ambassify-vs-sociuu)[Onboarding in Ambassify](https://get.ambassify.com/welcome-page)[Ambassify vs DSMN8](https://get.ambassify.com/ambassify-vs-dsmn8)[Ambassify vs Soworker](https://get.ambassify.com/ambassify-vs-soworker)[Tutorial Library](https://get.ambassify.com/tutorial-library)[Ambassify vs BeAmbassador](https://get.ambassify.com/ambassify-vs-beambassador)[Employee Advocacy ROI calculator](https://get.ambassify.com/employee-advocacy-roi-calculator)[Campaign Examples](https://get.ambassify.com/resources/employee-advocacy-examples)[Social Impact](https://get.ambassify.com/use-cases/employer-brand-social-impact)[Glossary](https://get.ambassify.com/glossary)[Corporate Branding](https://get.ambassify.com/use-cases/corporate-branding)[Employee Advocacy](https://get.ambassify.com/employee-advocacy)[State of Social Advocacy 2025](https://get.ambassify.com/resources/2025-report-on-the-state-of-social-advocacy)[Newsletter](https://get.ambassify.com/sign-up-for-our-newsletter)[Leader Advocacy (FR)](https://get.ambassify.com/fr/leader-advocacy)[Sitemap](https://get.ambassify.com/sitemap)[Social media impact](https://get.ambassify.com/show-the-business-impact-of-your-social-media-results)[Social Selling](https://get.ambassify.com/use-cases/social-selling)[Press](https://get.ambassify.com/press)

### Jobs

[All Vacancies](https://get.ambassify.com/company/careers)[Spontaneous Applications](https://get.ambassify.com/company/vacancies/spontaneous-applications)

### Company

[Contact Us](https://get.ambassify.com/contact)[Team](https://get.ambassify.com/company/about-us)[Become a Partner](https://get.ambassify.com/company/partner)[Legal Center](https://doc.ambassify.com/)

### Offices

**Office Europe**  
 Everselstraat 133  
 3580 Beringen, Belgium

**Office APAC**  
 36 Carpenter Street  
 Carpenter Haus, Singapore 059915

[Visit our Ambassify Facebook page](https://www.facebook.com/ambassify) [Visit our Ambassify X page](https://x.com/ambassify) [Visit our Ambassify LinkedIn page](https://www.linkedin.com/company/ambassify/)

[Terms of Service](https://doc.ambassify.com/terms.html)[Privacy Policy](https://doc.ambassify.com/policy/privacy-controller.html)[Data Protection Policy](https://doc.ambassify.com/policy/data-protection.html)[Cookie Policy](https://doc.ambassify.com/policy/cookie-controller.html)[GDPR](https://doc.ambassify.com/gdpr.html)

Cookie Settings

English - United States

© 2026 Ambassify

```json
{
  "@context" : "https://schema.org",
  "@type" : "BlogPosting",
  "author" : {
    "@type" : "Person",
    "name" : "Jorgen Evens",
    "url" : "https://blog.ambassify.com/blog/author/jorgen-evens"
  },
  "dateModified" : "2023-03-15T14:17:24.591Z",
  "datePublished" : "2022-12-07T10:00:00.000Z",
  "headline" : "Dockerizing Our Heroku Apps",
  "image" : [ "https://blog.ambassify.com/hubfs/Blog_NEW_Jorgen-01.png" ],
  "mainEntityOfPage" : {
    "@id" : "https://blog.ambassify.com/blog/dockerizing-our-heroku-apps",
    "@type" : "WebPage"
  },
  "publisher" : {
    "@type" : "Organization",
    "logo" : {
      "@type" : "ImageObject",
      "url" : "https://blog.ambassify.com/hubfs/Look-n-Feel/ambassify-without-baseline-positive.png"
    },
    "name" : "Ambassify"
  }
}
```

```json
{
  "@context" : "https://schema.org",
  "@id" : "https://www.ambassify.com/#place",
  "@type" : "Place",
  "address" : {
    "@type" : "PostalAddress",
    "addressCountry" : "BE",
    "addressLocality" : "Beringen",
    "addressRegion" : "Limburg",
    "postalCode" : "3580",
    "streetAddress" : "Everselstraat 133"
  }
}
```

```json
{
  "@context" : "https://schema.org",
  "@id" : "https://www.ambassify.com/#organization",
  "@type" : "Organization",
  "address" : {
    "@type" : "PostalAddress",
    "addressCountry" : "BE",
    "addressLocality" : "Beringen",
    "addressRegion" : "Limburg",
    "postalCode" : "3580",
    "streetAddress" : "Everselstraat 133"
  },
  "alternateName" : "Ambassify",
  "duns" : "400750905",
  "email" : "support@ambassify.com",
  "foundingDate" : "2016-01-03",
  "knowsAbout" : "employee advocacy, employee engagement, employee branding",
  "legalName" : "Ambassify NV",
  "location" : {
    "@id" : "https://www.ambassify.com/#place"
  },
  "logo" : {
    "@id" : "https://www.ambassify.com/#logo",
    "@type" : "ImageObject",
    "caption" : "Ambassify",
    "contentUrl" : "https://www.ambassify.com/hubfs/2828935/raw_assets/public/ambassify-theme/images/apple-touch-icons/apple-touch-icon-120x120.png",
    "height" : "120",
    "inLanguage" : "en-US",
    "url" : "https://www.ambassify.com/hubfs/2828935/raw_assets/public/ambassify-theme/images/apple-touch-icons/apple-touch-icon-120x120.png",
    "width" : "120"
  },
  "name" : "Ambassify Employee Advocacy",
  "sameAs" : [ "https://www.facebook.com/ambassify/", "https://twitter.com/ambassify", "https://linkedin.com/company/ambassify", "https://instagram.com/ambassify", "https://www.youtube.com/ambassify" ],
  "url" : "https://www.ambassify.com",
  "vatID" : "BE0830870128"
}
```

```json
{
  "@context" : "https://schema.org",
  "@id" : "https://www.ambassify.com/#website",
  "@type" : "WebSite",
  "inLanguage" : "en-US",
  "name" : "Ambassify",
  "publisher" : {
    "@id" : "https://www.ambassify.com/#organization"
  },
  "url" : "https://www.ambassify.com"
}
```

```json
{
  "@context" : "https://schema.org",
  "@id" : "https://www.ambassify.com/#webpage",
  "@type" : "WebPage",
  "about" : {
    "@id" : "https://www.ambassify.com/#organization"
  },
  "dateModified" : "1678889844596",
  "datePublished" : "2016-01-03T12:09:10+00:00",
  "inLanguage" : "en-US",
  "isPartOf" : {
    "@id" : "https://www.ambassify.com/#website"
  },
  "name" : "Ambassify | Employee Advocacy Platform",
  "url" : "https://www.ambassify.com/"
}
```