Welcome back! If you're reading this guide, you've already created your Heroku account, set up your profile and billing, and installed the Heroku CLI. Let's get your Docker containers deployed to the cloud!
Before we begin, check Heroku CLI is installed:
heroku --version
Check Docker is installed
docker --version
Check Git is installed
git --version
If any of these commands return "command not found," you'll need to install the missing tools first.
First, log into Heroku through your command line:
heroku login
This opens your browser for authentication. After logging in, you can close the browser and return to your terminal.
Alternative login method: If the browser method doesn't work, use:
heroku login -i
This will prompt for your email and an authorization token (not your regular password). Get your token from Account Settings > Applications in your Heroku dashboard.
Heroku's container registry is where we'll store our Docker images:
heroku container:login
Critical Step: Before proceeding, ensure Docker Desktop is configured correctly:
Go to Docker Desktop Settings > General tab
Uncheck "Use containerd for pulling and storing images"
Restart Docker Desktop

This prevents 405 errors when pushing to Heroku's registry.
Heroku only supports x86_64 (AMD64) architecture. If you're on an Apple Silicon Mac, ensure that you built for the correct platform. We'll handle this in our build commands.
See what Heroku apps you currently have:
heroku apps
If this is your first time, the list should be empty.
Since Heroku app names must be globally unique, append your name to avoid conflicts:
heroku create grade-api-firstname-lastname
Replace firstname-lastname with your actual name.
Now let's verify your app was created:
heroku apps
You should now see your new app listed! If this was your first Heroku app, you'll see it went from an empty list to showing your grade-api-firstname-lastname app.
By default, Heroku apps use a buildpack stack (like heroku-24), which expects you to push source code that Heroku then builds for you. However, since we want to deploy our pre-built Docker containers, we need to tell Heroku to expect container images instead.
Setting the container stack tells Heroku: "This app will receive Docker container deployments, not source code deployments." This enables container-specific commands and deployment processes for your app.
heroku stack:set container -a grade-api-firstname-lastname
You've likely already built your Docker images locally during development. If you built them without the --provenance false flag, you might encounter compatibility issues with Heroku's registry. Let's rebuild them with the correct settings to ensure smooth deployment.
Important: Make sure you're in the same directory as your Dockerfile for the grade submission API before running these commands:
Navigate to your API project directory (if not already there)
cd /path/to/your/grade-submission-api
Build for the correct platform and push directly
docker buildx build --provenance false --platform linux/amd64 -t registry.heroku.com/grade-api-firstname-lastname/web .
Push to Heroku's registry
docker push registry.heroku.com/grade-api-firstname-lastname/web
Release the container
heroku container:release web -a grade-api-firstname-lastname
Note: The --provenance false flag prevents compatibility issues with Heroku's registry. Even if you've built your images before, rebuilding with this flag ensures they'll work with Heroku's container registry.
Check logs
heroku logs --tail -a grade-api-firstname-lastname
Open your app
heroku open -a grade-api-firstname-lastname
Your API should now be running! You can test it by visiting /grades endpoint.
heroku create grade-portal-firstname-lastname
heroku stack:set container -a grade-portal-firstname-lastname
Important: Make sure you're in the same directory as your Dockerfile for the grade submission portal before running these commands:
Navigate to your portal project directory
cd /path/to/your/grade-submission-portal
Build for the correct platform and push directly
docker buildx build --provenance false --platform linux/amd64 --load -t registry.heroku.com/grade-portal-firstname-lastname/web .
Push to Heroku's registry
docker push registry.heroku.com/grade-portal-firstname-lastname/web
Release the container
heroku container:release web -a grade-portal-firstname-lastname
Your portal needs to know how to communicate with your API. Remember when you opened the grade-api Heroku app? Grab that URL. It should look something like this: https://grade-api-rayan-slim-e46af09e4515.herokuapp.com/. Obviously your specific identifier will be different, but using that URL, set the environment variable:
heroku config:set GRADE_SUBMISSION_API=https://grade-api-rayan-slim-e46af09e4515.herokuapp.com/grades -a grade-portal-firstname-lastname
Important: Replace firstname-lastname with your actual app name from Step 6. Notice we append /grades to the end of the URL because that's the specific endpoint your portal needs to communicate with. This tells your portal container where to find your API.
Open your portal application:
heroku open -a grade-portal-firstname-lastname
Try submitting a grade (e.g., "Harry", score "94", subject "Potions"). If everything is configured correctly, you should be able to submit grades and see them persist in your MongoDB database.
heroku logs --tail -a grade-api-firstname-lastname heroku logs --tail -a grade-portal-firstname-lastname
heroku ps -a grade-api-firstname-lastname heroku ps -a grade-portal-firstname-lastname
Your apps are now running on Heroku's paid tier at approximately $0.10/hour each. To avoid charges when you're done testing:
heroku apps:destroy grade-api-firstname-lastname heroku apps:destroy grade-portal-firstname-lastname
You'll need to confirm each deletion by typing the app name when prompted.
While Heroku is excellent for simple deployments like this, when you have larger applications with many services, you'll typically want to use Kubernetes clusters deployed to cloud providers like AWS or Azure for better scalability and management.