In this post, we will go through how you can get started with setting up a Next.js app. We will then deploy the app to Google Cloud Run using Docker. We will also set up a Cloud Build trigger so that a new version of our app is automatically built and deployed every time we push to the main
branch of our repository.
If you, like me, have very little experience with web development, you might be wondering what Next.js is and where it sits in the web development ecosystem. Next.js is a framework for building React apps. In turn, React is a Javascript library for building user interfaces. React is a very popular library and is used by both large companies and individuals. React is a powerful library, but it is also lower level and unopinionated. It is flexible, but it also means that you have to make a lot of decisions yourself. Next.js is a framework that builds on top of React and provides a lot of functionality out of the box. This makes it easier to get started with building a React app, and it also makes it easier to build a React app that is fast, accessible, and SEO-friendly.
I strongly recommend to start with the Next.js Learn tutorials to get a better understanding of what Next.js is and how it works. The tutorial is very well constructed and will walk you though building a simple Next.js app. You will even deploy an app to Vercel, which is the company behind Next.js.
If you’re not familiar with React either, I recommend to start with the Learn React tutorial first. It is also very well constructed and will give you a good understanding of how React works.
The best place to start is with the official Next.js documentation. On the Deploying page we learn that Next.js apps can be deployed to any hosting provider that supports Docker containers. This is great news, because it means that we can deploy to Google Cloud Run. The Google Cloud Run documentation is also a great resource. It is a lot of information, but we will only need a small part of it which I am to explain here.
This blog post by Frontend Engineer is also a great resource. We will be going through similar steps.
Both under Deploying/Docker Image and Deploying/Managed Server we are linked to the vercel/next.js repository with-docker
examples.
Feel free to create your app with the create-next-app
commands provided, or follow the instructions under the “In existing projects” section. I will not repeat the steps here, but I will add some additional information that I found useful.
In an existing project, copy both the Dockerfile
and the .dockerignore
files from the with-docker
example into the root of your project.
In an existing project, if you do not have a next.config.js
file, create it in the root of your project with the following contents:
/** @type {import('next').NextConfig} */
module.exports = {
output: "standalone",
};
with-docker
README:# Build the image
docker build -t nextjs-docker .
# Run the container
docker run -p 3000:3000 nextjs-docker
where nextjs-docker
is the name/tag of the image. You can choose any name you want.
If you haven’t already, create a new repository on Github and push your code to it. This should be straight forward if you have used Github before. If you haven’t, you can follow the instructions on the Github Docs.
⚠️ Note: Make sure you do not push any sensitive information to Github. This includes any
.env
files or any other files that contain secrets. This is easily avoided using a.gitignore
file.
The next.js repo’s with-docker
example provides instructions on how to deploy using the Google Cloud SDK. However, we will use the Google Cloud Console to set up our project, Cloud Run service, Cloud Build trigger, and Github connection. This way, a new version of our app will be automatically built and deployed every time we push to the main
branch of our repository.
Most of the following steps should be straight forward, I will provide some additional information where I think it is useful.
Create a new project in the Google Cloud Console. You can follow the instructions on the Google Cloud Docs.
Enable billing for your project by searching for “Billing” and following the steps. You can follow the instructions on the Google Cloud Docs.
Navigate to Cloud Run (can also be done by searching!) and click Create service
. You can follow the instructions on the Google Cloud Docs. In the setup guide:
Select Continuously deploy new revisions from a source repository
.
Click Set up Cloud Build
, which will open a sidebar.
Github
.Next
.^main$
. This will trigger a build every time you push to the main
branch.Dockerfile
and enter the path to your Dockerfile
, i.e., /Dockerfile
in our case.Save
.nextjs-app
.europe-north1
if you’re in Stockholm like me.Under “CPU allocation and pricing” we can tune some options to minimize cost:
CPU is only allocated during request processing
.0
, as we will allow cold starts.1
, as we don’t expect a lot of traffic.All
as we want to publish this app on the internet.Allow unauthenticated invocations
as we are creating a public API/website.Expand the “Container, Networking, Security” section:
3000
as this is the port that our app is listening on.Create
.Go to the API Library and enable Identity and Access Management (IAM) API
, so that we can trigger a deployment manually.
In the Service details page, click Edit continuous deployment
.
Cloud Build configuration file (YAML or JSON)
.Inline
.Save
.Go to the Cloud Build Triggers page and click Run
on the trigger you just created. This should add an entry to the “History” table. Click on the entry in the Build column to see the details. There should be 3 steps executing (Build, Push, Deploy), as seen in the YAML editor in the previous step. Once the build is complete, you should be able to see your app running on the internet. You can find the URL on the Cloud Run Services page.
steps:
- name: gcr.io/cloud-builders/docker
args:
- build
- "--no-cache"
- "-t"
- >-
$_AR_HOSTNAME/$PROJECT_ID/cloud-run-source-deploy/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA
- .
- "-f"
- Dockerfile
id: Build
- name: gcr.io/cloud-builders/docker
args:
- push
- >-
$_AR_HOSTNAME/$PROJECT_ID/cloud-run-source-deploy/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA
id: Push
- name: "gcr.io/google.com/cloudsdktool/cloud-sdk:slim"
args:
- run
- services
- update
- $_SERVICE_NAME
- "--platform=managed"
- >-
--image=$_AR_HOSTNAME/$PROJECT_ID/cloud-run-source-deploy/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA
- >-
--labels=managed-by=gcp-cloud-build-deploy-cloud-run,commit-sha=$COMMIT_SHA,gcb-build-id=$BUILD_ID,gcb-trigger-id=$_TRIGGER_ID
- "--region=$_DEPLOY_REGION"
- "--quiet"
id: Deploy
entrypoint: gcloud
images:
- >-
$_AR_HOSTNAME/$PROJECT_ID/cloud-run-source-deploy/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA
options:
substitutionOption: ALLOW_LOOSE
logging: CLOUD_LOGGING_ONLY
substitutions:
_PLATFORM: managed
_SERVICE_NAME: nextjs-app # example service name
_DEPLOY_REGION: europe-north1 # example region
_TRIGGER_ID: 123ab4cd-ef5g-6hi7-8j90-klmnopq234r5 # example trigger ID
_AR_HOSTNAME: europe-north1-docker.pkg.dev
tags:
- gcp-cloud-build-deploy-cloud-run
- gcp-cloud-build-deploy-cloud-run-managed
- nextjs-app # example service name
Finally, we can test that everything works as expected. Push a small change to the main
branch of your repository. This should trigger a new build and deploy. You can follow the progress on the Cloud Build History page. Once the build is complete, you should be able to see your app running on the internet.
As previously stated in this guide, you are assigned a static URL when you create a Cloud Run service. This URL is not very user friendly, and you probably want to use your own domain. Documentation can be found in the Cloud Run Docs, but I will walk you through the steps here.
Go to the Cloud Search Console and add a property of type “Domain”. I personally wanted to deploy the Next.js app to app.rygard.se
, as opposed to www.rygard.se
, so I entered app.rygard.se
as (sub)domain.
The page will ask you to verify the ownership of this property via DNS record. Follow the instructions provided to add a TXT record in your host’s DNS management page (Hostup.se in my case), much like we did in the previous blog post for Github Pages.
Now, we can head to the Cloud Run Services page and click on our service. Find the Domains page and add a new mapping. Select your service, e.g., nextjs-app
and enter the domain we just verified, e.g. app.rygard.se
. No need to enter anything the the subdomain field.
Now we are asked to make the final DNS changes. Head back to your hosts’s DNS management page and add the records provided. These are four A records and four AAAA records.
Finally, allow some time for the change to propagate, after a while you should be able to reach your app on your custom domain, like app.<domain-name>.se
.